diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 26900f8cdd..d5b385a89d 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -113,7 +113,7 @@ jobs: run: | mkdir build cd build - cmake .. -DMUMPS_DIR=$PWD/../../mumps/build + cmake .. -DMUMPS_DIR=$PWD/../../mumps/build -DCMAKE_PREFIX_PATH=/usr/local/Cellar/libaec/1.1.3/cmake cmake --build . --target OpenSees -j8 cmake --build . --target OpenSeesPy -j8 mv ./OpenSeesPy.dylib ./opensees.so @@ -160,6 +160,12 @@ jobs: export PYTHONPATH="./build/lib/" python3 -c "import sys; print(sys.path)" python3 ./EXAMPLES/ExamplePython/example_variable_analysis.py + - name: Run pytest in tests/ folder + run: | + python3 -m pip install pytest + cp build/lib/opensees.so tests/ + cd tests + pytest -v - name: Upload Artifacts uses: actions/upload-artifact@v4 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index cccba0f85a..9d7ad9d105 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ #============================================================================== -# +# # OpenSees -- Open System For Earthquake Engineering Simulation # Pacific Earthquake Engineering Research Center # @@ -63,7 +63,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++") MESSAGE("COMPILER: GNU") -elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel") +elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Intel") MESSAGE("COMPILER: Intel") add_compile_options(-fPIC) elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC") @@ -75,7 +75,7 @@ else() MESSAGE("COMPILER: UKNOWN COMPILER ${CMAKE_CXX_COMPILER_ID}") endif() - + # # external packages # @@ -83,9 +83,9 @@ endif() add_library(OPS_External_packages INTERFACE) add_library(OPS_OS_Specific_libs INTERFACE) -# +# # Conan (manages external dependencies for a typical build) -# +# MESSAGE("${CMAKE_BINARY_DIR}") @@ -110,6 +110,8 @@ else() include(OpenSeesFunctions) set(NOT_USING_CONAN TRUE) set (CONAN_LIBS ) + find_package(ZLIB REQUIRED) + find_package(libaec REQUIRED) find_package(HDF5 REQUIRED) find_package(TCL REQUIRED) find_package(Eigen3 REQUIRED) @@ -120,7 +122,7 @@ else() endif() # define user-selectable options for end target -set_property(CACHE OPS_FINAL_TARGET PROPERTY STRINGS +set_property(CACHE OPS_FINAL_TARGET PROPERTY STRINGS G3 OpenSees OpenSeesMP OpenSeesSP OpenSeesPy) # @@ -142,7 +144,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") add_compile_definitions(_LINUX _UNIX _TCL85) if (NOT_USING_CONAN) include(OpenSeesDependenciesUnix) - endif() + endif() endif() if(CMAKE_SYSTEM_NAME STREQUAL "Windows") @@ -150,7 +152,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") add_compile_definitions(_WIN32 _TCL85) if (NOT_USING_CONAN) include(OpenSeesDependenciesWin) - endif() + endif() endif() #============================================================================== @@ -159,7 +161,7 @@ endif() #============================================================================== #---------------------------------------------------------------- # Compilers -#---------------------------------------------------------------- +#---------------------------------------------------------------- # Fortran #-------------------------------------- @@ -191,7 +193,7 @@ set(CMAKE_CXX_ARCHIVE_CREATE " cqls ") # Global Includes #---------------------------------------------------------------- # include paths to main abstract classes - + # NOTE BeamIntegration and MatrixUtil need to be removed from element/forceBEamColumn include_directories( @@ -251,7 +253,7 @@ include_directories( ) # TODO: Temporary fix; include all directories with .h files through glob -file(GLOB_RECURSE ops_include_files CONFIGURE_DEPENDS +file(GLOB_RECURSE ops_include_files CONFIGURE_DEPENDS ${OPS_SRC_DIR}/*.h ${OPS_BUNDLED_DIR}/*.h ) @@ -285,6 +287,8 @@ add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/ARPACK") set (ARPACK_LIBRARIES ARPACK) add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/CSPARSE") set (CSPARSE_LIBRARIES CSPARSE) +add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/ITPACK") +set (ITPACK_LIBRARIES ITPACK) add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/tetgen1.4.3") set (TETGEN_LIBRARIES tet) add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/Triangle") @@ -293,13 +297,13 @@ set (TRIANGLE_LIBRARIES triangle) # set (EIGENAPI_LIBRARIES EIGENAPI) -if (NOT DEFINED LAPACK_LIBRARIES) +if (NOT DEFINED LAPACK_LIBRARIES) find_package(LAPACK) else() set (LAPACK_FOUND TRUE CACHE BOOL "providing own lapack lib") endif() -if (NOT DEFINED Python_LIBRARIES) +if (NOT DEFINED Python_LIBRARIES) find_package(Python COMPONENTS Interpreter Development) else() set (PYTHON_FOUND TRUE CACHE BOOL "providing own python lib") @@ -317,7 +321,7 @@ if(LAPACK_FOUND) message(STATUS "LAPACK_LINKER_FLAGS = ${LAPACK_LINKER_FLAGS}") message(STATUS "LAPACK_LIBRARIES = ${LAPACK_LIBRARIES}" ) else() - add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/BLAS") + add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/BLAS") add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/LAPACK") set(LAPACK_LIBRARIES LAPACK) endif() @@ -327,7 +331,7 @@ if(PYTHON_FOUND) #message("Python_VERSION:${Python_VERSION}") #message("Python_Development_FOUND:${Python_Development_FOUND}") message("Python_LIBRARIES:${Python_LIBRARIES}") - message("Python_INCLUDES:${Python_INCLUDE_DIRS}") + message("Python_INCLUDES:${Python_INCLUDE_DIRS}") else() message(STATUS "PYTHON NOT FOUND") endif() @@ -353,7 +357,7 @@ if(MPI_FOUND) set (MUMPS_FLAG -D_NOMUMPS) set (MUMPS_LIBRARIES "") else() - set (MUMPS_FLAG -D_MUMPS) + set (MUMPS_FLAG -D_MUMPS) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set (MUMPS_LIBRARIES "${MUMPS_DIR}/dmumps;${MUMPS_DIR}/mumps_common;${MUMPS_DIR}/pord") else() @@ -363,7 +367,7 @@ if(MPI_FOUND) endif() add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/SuperLU_DIST_4.3/SRC") - add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/METIS") + add_subdirectory("${PROJECT_SOURCE_DIR}/OTHER/METIS") else() message(STATUS "MPI was NOT found.") endif() @@ -377,7 +381,7 @@ if(MKL_FOUND) if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set (MKL_LPATH ${MKL_ROOT}/lib/intel64) set (SCALAPACK_LIBRARIES "${MKL_LPATH}/mkl_scalapack_ilp64.lib;${MKL_LPATH}/mkl_intel_ilp64.lib;${MKL_LPATH}/mkl_sequential.lib;${MKL_LPATH}/mkl_core.lib;${MKL_LPATH}/mkl_blacs_intelmpi_ilp64.lib") - endif() + endif() else() message(STATUS "MKL NOT found .. user to provide -DSCALAPACK_LIBRARIES=") @@ -385,26 +389,26 @@ else() endif() message(STATUS "SCALAPACK_LIBRARIES=${SCALAPACK_LIBRARIES}") - + #get_cmake_property(_variableNames VARIABLES) #list (SORT _variableNames) #foreach (_variableName ${_variableNames}) # message(STATUS "${_variableName}=${${_variableName}}") -#endforeach() +#endforeach() + - add_library(OPS_Numerics INTERFACE) target_link_libraries(OPS_Numerics INTERFACE ${ARPACK_LIBRARIES} - ${CSPARSE_LIBRARIES} + ${CSPARSE_LIBRARIES} ${SUPERLU_LIBRARIES} ${UMFPACK_LIBRARIES} ${TETGEN_LIBRARIES} - ${TRIANGLE_LIBRARIES} + ${TRIANGLE_LIBRARIES} ${AMD_LIBRARIES} - ${AMD_LIBRARIES} + ${ITPACK_LIBRARIES} ${LAPACK_LIBRARIES} ${EIGENAPI_LIBRARIES} ) @@ -469,13 +473,13 @@ endif() # OpenSees G3 Library - a slimmed down OpenSees # -add_library(G3) +add_library(G3) target_link_libraries(G3 coordTransformation damping OPS_Matrix - OPS_Analysis + OPS_Analysis OPS_ModelBuilder OPS_Domain OPS_ConvergenceTest @@ -484,10 +488,10 @@ target_link_libraries(G3 OPS_Recorder OPS_Handler OPS_SysOfEqn - OPS_Tagged + OPS_Tagged OPS_Utilities graph - OPS_Actor + OPS_Actor OPS_ObjectBroker OPS_Numerics OPS_INTERPRETER @@ -501,19 +505,19 @@ add_library(OpenSeesLIB EXCLUDE_FROM_ALL) target_link_libraries(OpenSeesLIB ${OPS_Extension_List} - OPS_Actor - OPS_Analysis + OPS_Actor + OPS_Analysis OPS_ConvergenceTest OPS_Damage OPS_Database OPS_Domain graph OPS_Element - OPS_ElementFortran + OPS_ElementFortran OPS_Handler OPS_INTERPRETER OPS_Material - OPS_MaterialFortran + OPS_MaterialFortran OPS_Material_YieldSurface OPS_Matrix OPS_ModelBuilder @@ -526,9 +530,9 @@ target_link_libraries(OpenSeesLIB OPS_Section_Repres OPS_Section_YieldSurface OPS_SysOfEqn - OPS_Thermal + OPS_Thermal OPS_OS_Specific_libs - OPS_Tagged + OPS_Tagged OPS_Utilities ) @@ -547,7 +551,7 @@ target_link_libraries(OpenSeesLIB -add_executable(OpenSees EXCLUDE_FROM_ALL +add_executable(OpenSees EXCLUDE_FROM_ALL ${OPS_SRC_DIR}/tcl/tclAppInit.cpp ${OPS_SRC_DIR}/tcl/tclMain.cpp ${OPS_SRC_DIR}/tcl/commands.cpp @@ -560,7 +564,7 @@ if(NOT EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake") FILE(COPY ${CONAN_LIB_DIRS_TCL}/tcl8.6 DESTINATION ${PROJECT_BINARY_DIR}/lib/tcl8.6 FILES_MATCHING PATTERN .tcl) - + else () FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib/tcl8.6) add_custom_command( @@ -574,15 +578,15 @@ endif() target_link_libraries(OpenSees - OPS_InterpTcl + OPS_InterpTcl coordTransformation OpenSeesLIB OPS_Reliability - OPS_ReliabilityTcl + OPS_ReliabilityTcl OPS_Numerics OPS_Recorder - ${CMAKE_DL_LIBS} - ${HDF5_LIBRARIES} + ${CMAKE_DL_LIBS} + ${HDF5_LIBRARIES} ${CONAN_LIBS} ) @@ -594,7 +598,7 @@ target_link_libraries(OpenSees if(MPI_FOUND) - add_executable(OpenSeesSP EXCLUDE_FROM_ALL + add_executable(OpenSeesSP EXCLUDE_FROM_ALL ${OPS_SRC_DIR}/tcl/mpiMain.cpp ${OPS_SRC_DIR}/tcl/tclMain.cpp ${OPS_SRC_DIR}/tcl/commands.cpp @@ -621,15 +625,15 @@ if(MPI_FOUND) target_compile_options(OpenSeesSP PRIVATE ${MPI_CXX_COMPILE_FLAGS}) if (DEFINED OPENMPI) - target_compile_definitions(OpenSeesSP + target_compile_definitions(OpenSeesSP PUBLIC _PARALLEL_PROCESSING ${MUMPS_FLAG} _OPENMPI) else() - target_compile_definitions(OpenSeesSP + target_compile_definitions(OpenSeesSP PUBLIC _PARALLEL_PROCESSING ${MUMPS_FLAG}) endif() - target_link_libraries(OpenSeesSP - OPS_InterpTcl + target_link_libraries(OpenSeesSP + OPS_InterpTcl OpenSeesLIB OPS_Reliability OPS_ReliabilityTcl @@ -638,15 +642,15 @@ if(MPI_FOUND) SUPERLU_DIST OPS_Numerics ${MUMPS_LIBRARIES} - ${CMAKE_DL_LIBS} - ${HDF5_LIBRARIES} + ${CMAKE_DL_LIBS} + ${HDF5_LIBRARIES} ${CONAN_LIBS} ${MPI_CXX_LIBRARIES} ${SCALAPACK_LIBRARIES} - ${MPI_Fortran_LIBRARIES} + ${MPI_Fortran_LIBRARIES} ${MPI_CXX_LINK_FLAGS} ) - + endif() @@ -656,13 +660,13 @@ endif() if(MPI_FOUND) - add_executable(OpenSeesMP EXCLUDE_FROM_ALL + add_executable(OpenSeesMP EXCLUDE_FROM_ALL ${OPS_SRC_DIR}/tcl/mpiParameterMain.cpp ${OPS_SRC_DIR}/tcl/tclMain.cpp ${OPS_SRC_DIR}/tcl/commands.cpp ${OPS_SRC_DIR}/domain/domain/partitioned/PartitionedDomain.cpp ${OPS_SRC_DIR}/domain/domain/partitioned/PartitionedDomainEleIter.cpp - ${OPS_SRC_DIR}/domain/domain/partitioned/PartitionedDomainSubIter.cpp + ${OPS_SRC_DIR}/domain/domain/partitioned/PartitionedDomainSubIter.cpp ${OPS_SRC_DIR}/actor/machineBroker/MPI_MachineBroker.cpp ${OPS_SRC_DIR}/actor/objectBroker/FEM_ObjectBrokerAllClasses.cpp ${OPS_SRC_DIR}/system_of_eqn/linearSOE/diagonal/MPIDiagonalSOE.cpp @@ -678,38 +682,38 @@ if(MPI_FOUND) target_include_directories(OpenSeesMP PRIVATE ${MUMPS_DIR}/_deps/mumps-src/include ${MPI_CXX_INCLUDE_DIRS}) target_compile_options(OpenSeesMP PRIVATE ${MPI_CXX_COMPILE_FLAGS}) - + if (NOT DEFINED MUMPS_DIR) add_dependencies(OpenSeesMP mumps) - endif() + endif() if (DEFINED OPENMPI) - target_compile_definitions(OpenSeesMP + target_compile_definitions(OpenSeesMP PUBLIC _PARALLEL_INTERPRETERS ${MUMPS_FLAG} _OPENMPI) else() - target_compile_definitions(OpenSeesMP + target_compile_definitions(OpenSeesMP PUBLIC _PARALLEL_INTERPRETERS ${MUMPS_FLAG}) endif() - - target_link_libraries(OpenSeesMP - OPS_InterpTcl + + target_link_libraries(OpenSeesMP + OPS_InterpTcl OpenSeesLIB OPS_Reliability OPS_ReliabilityTcl - OPS_Recorder + OPS_Recorder METIS SUPERLU_DIST OPS_Numerics ${MUMPS_LIBRARIES} - ${CMAKE_DL_LIBS} - ${HDF5_LIBRARIES} + ${CMAKE_DL_LIBS} + ${HDF5_LIBRARIES} ${CONAN_LIBS} ${MPI_CXX_LIBRARIES} ${SCALAPACK_LIBRARIES} - ${MPI_Fortran_LIBRARIES} + ${MPI_Fortran_LIBRARIES} ${MPI_CXX_LINK_FLAGS} ) - + endif() @@ -727,12 +731,12 @@ set_target_properties(OpenSeesPy PROPERTIES PREFIX "") target_include_directories(OpenSeesPy PUBLIC ${Python_INCLUDE_DIRS}) target_link_libraries(OpenSeesPy - OpenSeesLIB + OpenSeesLIB OPS_Reliability OPS_Recorder - OPS_Numerics - ${HDF5_LIBRARIES} - ${CONAN_LIBS} + OPS_Numerics + ${HDF5_LIBRARIES} + ${CONAN_LIBS} ${Python_LIBRARIES} ) @@ -776,11 +780,11 @@ add_subdirectory(${OPS_SRC_DIR}) #---------------------------- if(FMK) add_compile_definitions( - _HAVE_Damage2p + _HAVE_Damage2p _HAVE_PSUMAT _HAVE_PML _FILIP_LHNMYS - ) + ) endif() #---------------------------- @@ -788,12 +792,12 @@ endif() #---------------------------- message("OPS >>> Configuring OpenSees extensions") foreach(extension IN LISTS OPS_SysOfEqn_List OPS_Element_List OPS_Extension_List) - string(TOUPPER "${extension}" ext_flag) + string(TOUPPER "${extension}" ext_flag) string(REGEX REPLACE "^OPS_" "OPSDEF_" ext_flag "${ext_flag}") add_compile_definitions(${ext_flag}) endforeach() foreach(extension IN LISTS OPS_Exclude_List) - string(TOUPPER "${extension}" ext_flag) + string(TOUPPER "${extension}" ext_flag) string(REGEX REPLACE "^OPS_" "OPS_EXCLUDE_" ext_flag "${ext_flag}") message(" Adding macro definition '${ext_flag}'") add_compile_definitions(${ext_flag}) @@ -842,7 +846,7 @@ if(HDF5_FOUND) if (HDF5_VERSION VERSION_GREATER_EQUAL 1.12.0) add_compile_definitions(_H5DRM) add_compile_definitions(_HDF5) - message(STATUS "OPS >>> Have HDF5 and VERSION >= 1.12.0") + message(STATUS "OPS >>> Have HDF5 and VERSION >= 1.12.0") endif() else() message(STATUS "OPS >>> Could not find HDF5") diff --git a/DEVELOPER/core/DOF_Group.cpp b/DEVELOPER/core/DOF_Group.cpp index 5c3f723aa8..ca36246085 100644 --- a/DEVELOPER/core/DOF_Group.cpp +++ b/DEVELOPER/core/DOF_Group.cpp @@ -650,14 +650,14 @@ void DOF_Group::incrNodeDisp(const Vector &u) { if (myNode == 0) { - opserr << "DOF_Group::setNodeDisp: 0 Node Pointer\n"; + opserr << "DOF_Group::incrNodeDisp: 0 Node Pointer\n"; exit(-1); } Vector &disp = *unbalance;; if (disp.Size() == 0) { - opserr << "DOF_Group::setNodeIncrDisp - out of space\n"; + opserr << "DOF_Group::incrNodeDisp - out of space\n"; return; } int i; @@ -683,7 +683,7 @@ DOF_Group::incrNodeVel(const Vector &udot) { if (myNode == 0) { - opserr << "DOF_Group::setNodeVel: 0 Node Pointer\n"; + opserr << "DOF_Group::incrNodeVel: 0 Node Pointer\n"; exit(-1); } @@ -711,7 +711,7 @@ DOF_Group::incrNodeAccel(const Vector &udotdot) { if (myNode == 0) { - opserr << "DOF_Group::setNodeAccel: 0 Node Pointer\n"; + opserr << "DOF_Group::incrNodeAccel: 0 Node Pointer\n"; exit(-1); } @@ -735,7 +735,7 @@ DOF_Group::setEigenvector(int mode, const Vector &theVector) { if (myNode == 0) { - opserr << "DOF_Group::setNodeAccel: 0 Node Pointer\n"; + opserr << "DOF_Group::setEigenvector: 0 Node Pointer\n"; exit(-1); } @@ -758,7 +758,7 @@ const Matrix & DOF_Group::getEigenvectors(void) { if (myNode == 0) { - opserr << "DOF_Group::setNodeAccel: 0 Node Pointer\n"; + opserr << "DOF_Group::getEigenvectors: 0 Node Pointer\n"; exit(-1); } diff --git a/DEVELOPER/core/classTags.h b/DEVELOPER/core/classTags.h index 65de56e9ce..325ad7bf9b 100644 --- a/DEVELOPER/core/classTags.h +++ b/DEVELOPER/core/classTags.h @@ -432,9 +432,12 @@ #define ND_TAG_PM4Sand 14021 // PM4Silt material - L.Chen #define ND_TAG_PM4Silt 14022 -// J2CyclicBoundingSurface material - D.Turello -#define ND_TAG_J2CyclicBoundingSurface 14023 - +// J2CyclicBoundingSurface material - P. Arduino, D.Turello +#define ND_TAG_J2CyclicBoundingSurface 14023 +#define ND_TAG_J2CyclicBoundingSurface3D 14024 +#define ND_TAG_J2CyclicBoundingSurfacePlaneStrain 14025 +// LinearElasticGGmax material - P. Arduino +#define ND_TAG_LinearElasticGGmax 14026 // MultiaxialCyclicPlasticity, add by Gang Wang #define ND_TAG_MultiaxialCyclicPlasticity 10031 #define ND_TAG_MultiaxialCyclicPlasticity3D 10032 diff --git a/MAKES/Makefile.def.EC2-UBUNTU b/MAKES/Makefile.def.EC2-UBUNTU index 249632c0f5..1a6f9b11be 100644 --- a/MAKES/Makefile.def.EC2-UBUNTU +++ b/MAKES/Makefile.def.EC2-UBUNTU @@ -89,6 +89,9 @@ RELIABILITY_FLAG = -D_RELIABILITY # remove the directory from DIRS. BASE = ./usr/local +# Uncomment the HOME directory and if OpnSees is cloned to the +# path /home/ubuntu/OpenSees the HOME directory should be /home/ubuntu +# HOME = /home/ubuntu FE = $(HOME)/OpenSees/SRC AMDdir = $(HOME)/OpenSees/OTHER/AMD diff --git a/MAKES/Makefile.def.Ubuntu20.04 b/MAKES/Makefile.def.Ubuntu20.04 index 890a8863e4..f0a80ab9d2 100644 --- a/MAKES/Makefile.def.Ubuntu20.04 +++ b/MAKES/Makefile.def.Ubuntu20.04 @@ -62,6 +62,9 @@ RELIABILITY = NO_RELIABILITY # remove the directory from DIRS. BASE = ./usr/local +# Uncomment the HOME directory and if OpnSees is cloned to the +# path /home/ubuntu/OpenSees the HOME directory should be /home/ubuntu +# HOME = /home/ubuntu FE = $(HOME)/OpenSees/SRC AMDdir = $(HOME)/OpenSees/OTHER/AMD diff --git a/OTHER/ITPACK/README.md b/OTHER/ITPACK/README.md new file mode 100644 index 0000000000..d2330530c6 --- /dev/null +++ b/OTHER/ITPACK/README.md @@ -0,0 +1,10 @@ +To compile test problem, `dtst2c.f` + +```console +gfortran -o myprogram dtst2c.f dsrc2c.f jcg.f jsi.f rscg.f rssi.f sor.f ssorcg.f ssorsi.f -lblas +``` + +Additional compilation notes + ++ Rename `IRAND` to `IRANDBLH` (due to name conflict) ++ Changed line 1 to `PROGRAM ITPTST` (removed args) diff --git a/OTHER/ITPACK/dtst2c.f b/OTHER/ITPACK/dtst2c.f index cb29465fd9..239b756e58 100644 --- a/OTHER/ITPACK/dtst2c.f +++ b/OTHER/ITPACK/dtst2c.f @@ -1,4 +1,4 @@ - PROGRAM ITPTST (OUTPUT,TAPE6=OUTPUT) + PROGRAM ITPTST C C CHANGES TO BE MADE FOR USE ON DIFFERENT COMPUTERS: C 1. REMOVE OR CHANGE PROGRAM LINE ABOVE OR OPEN LINE BELOW @@ -1608,7 +1608,7 @@ SUBROUTINE SETPER (P,IP) C DO 10 I = 1,N P(I) = I - IP(I) = IRAND(1,N,ISEED) + IP(I) = IRANDBLH(1,N,ISEED) 10 CONTINUE C RETURN @@ -1657,8 +1657,8 @@ SUBROUTINE SETSYS (IA,JA,A,RHS,P,IP,ROW,IROW,IWKSP) C STORE SYMMETRIC SYSTEM OFF-DIAGONAL ELEMENTS C DO 90 K = 1,NZRED - 70 I = IRAND(1,NRED,ISEED) - J = IRAND(NRED+1,N,ISEED) + 70 I = IRANDBLH(1,NRED,ISEED) + J = IRANDBLH(NRED+1,N,ISEED) PI = MIN0(P(I),P(J)) PJ = MAX0(P(I),P(J)) VAL = -DBLE(RANDOM(ISEED)) @@ -1681,8 +1681,8 @@ SUBROUTINE SETSYS (IA,JA,A,RHS,P,IP,ROW,IROW,IWKSP) C STORE NONSYMMETRIC SYSTEM OFF-DIAGONAL ELEMENTS C DO 130 K = 1,NZRED - 120 I = IRAND(1,NRED,ISEED) - J = IRAND(NRED+1,N,ISEED) + 120 I = IRANDBLH(1,NRED,ISEED) + J = IRANDBLH(NRED+1,N,ISEED) PI = P(I) PJ = P(J) VAL = -DBLE(RANDOM(ISEED)) @@ -1693,8 +1693,8 @@ SUBROUTINE SETSYS (IA,JA,A,RHS,P,IP,ROW,IROW,IWKSP) ROW(PI) = ROW(PI)-VAL 130 CONTINUE DO 150 K = 1,NZBLK - 140 I = IRAND(NRED+1,N,ISEED) - J = IRAND(1,NRED,ISEED) + 140 I = IRANDBLH(NRED+1,N,ISEED) + J = IRANDBLH(1,NRED,ISEED) PI = P(I) PJ = P(J) VAL = -DBLE(RANDOM(ISEED)) @@ -1731,7 +1731,7 @@ SUBROUTINE SETSYS (IA,JA,A,RHS,P,IP,ROW,IROW,IWKSP) IF (IER.NE.0) STOP C DO 190 K = 1,N,5 - NBIG = IRAND(1,N,ISEED) + NBIG = IRANDBLH(1,N,ISEED) RHS(NBIG) = EVAL+RHS(NBIG) PI = NBIG PJ = NBIG @@ -2036,7 +2036,7 @@ SUBROUTINE CHKNRM (U,WKSP,DIGIT) C RETURN END - INTEGER FUNCTION IRAND (I,J,ISEED) + INTEGER FUNCTION IRANDBLH (I,J,ISEED) C C***************************************************************** C @@ -2049,7 +2049,7 @@ INTEGER FUNCTION IRAND (I,J,ISEED) C C==================================================================== C - IRAND = IFIX(FLOAT(J-I+1)*RANDOM(ISEED))+I + IRANDBLH = IFIX(FLOAT(J-I+1)*RANDOM(ISEED))+I C RETURN END diff --git a/OTHER/LAPACK/CMakeLists.txt b/OTHER/LAPACK/CMakeLists.txt index 9131a2c286..8490563a6d 100644 --- a/OTHER/LAPACK/CMakeLists.txt +++ b/OTHER/LAPACK/CMakeLists.txt @@ -143,6 +143,26 @@ target_sources(LAPACK PUBLIC dlatrs.f dla_rpvgrw.f dla_gerpvgrw.f + + dsygvx.f + dsygst.f + dsygs2.f + dsyevx.f + dormtr.f + dorgtr.f + dorgql.f + dorg2l.f + dormql.f + dorm2l.f + dlansy.f + dlarf1l.f + iladlr.f + iladlc.f + disnan.f + dlaisnan.f + dsytrd.f + dlatrd.f + dsytd2.f ) add_library(LAPACK_C) diff --git a/OTHER/LAPACK/Makefile b/OTHER/LAPACK/Makefile index 06d6ab8502..e0c54dce06 100644 --- a/OTHER/LAPACK/Makefile +++ b/OTHER/LAPACK/Makefile @@ -20,7 +20,10 @@ DOBJ = dgeqr2.o dlabad.o dlacon.o dlacpy.o dladiv.o dlae2.o dlaev2.o\ chla_transtype.o dla_gercond.o dla_wwaddw.o ilaprec.o ilatrans.o dgecon.o \ dla_geamv.o dlacn2.o dla_lin_berr.o drscl.o dlatrs.o dla_rpvgrw.o dla_gerpvgrw.o \ BLAS_dgemv2_x.o BLAS_dgemv2_x-f2c.o \ - BLAS_dgemv_x.o BLAS_dgemv_x-f2c.o BLAS_error.o BLAS_error.o + BLAS_dgemv_x.o BLAS_dgemv_x-f2c.o BLAS_error.o BLAS_error.o \ + dsygvx.o dsygst.o dsygs2.o dsyevx.o dormtr.o dorgtr.o dorgql.o \ + dorg2l.o dormql.o dorm2l.o dlansy.o dlarf1l.o iladlr.o iladlc.o \ + disnan.o dlaisnan.o dsytrd.o dlatrd.o dsytd2.o diff --git a/OTHER/LAPACK/disnan.f b/OTHER/LAPACK/disnan.f new file mode 100644 index 0000000000..fd59cfd5c1 --- /dev/null +++ b/OTHER/LAPACK/disnan.f @@ -0,0 +1,77 @@ +*> \brief \b DISNAN tests input for NaN. +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DISNAN + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* LOGICAL FUNCTION DISNAN( DIN ) +* +* .. Scalar Arguments .. +* DOUBLE PRECISION, INTENT(IN) :: DIN +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DISNAN returns .TRUE. if its argument is NaN, and .FALSE. +*> otherwise. To be replaced by the Fortran 2003 intrinsic in the +*> future. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] DIN +*> \verbatim +*> DIN is DOUBLE PRECISION +*> Input to test for NaN. +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup isnan +* +* ===================================================================== + LOGICAL FUNCTION DISNAN( DIN ) +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + DOUBLE PRECISION, INTENT(IN) :: DIN +* .. +* +* ===================================================================== +* +* .. External Functions .. + LOGICAL DLAISNAN + EXTERNAL DLAISNAN +* .. +* .. Executable Statements .. + DISNAN = DLAISNAN(DIN,DIN) + RETURN + END diff --git a/OTHER/LAPACK/dlaisnan.f b/OTHER/LAPACK/dlaisnan.f new file mode 100644 index 0000000000..d879d9e409 --- /dev/null +++ b/OTHER/LAPACK/dlaisnan.f @@ -0,0 +1,88 @@ +*> \brief \b DLAISNAN tests input for NaN by comparing two arguments for inequality. +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DLAISNAN + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* LOGICAL FUNCTION DLAISNAN( DIN1, DIN2 ) +* +* .. Scalar Arguments .. +* DOUBLE PRECISION, INTENT(IN) :: DIN1, DIN2 +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> This routine is not for general use. It exists solely to avoid +*> over-optimization in DISNAN. +*> +*> DLAISNAN checks for NaNs by comparing its two arguments for +*> inequality. NaN is the only floating-point value where NaN != NaN +*> returns .TRUE. To check for NaNs, pass the same variable as both +*> arguments. +*> +*> A compiler must assume that the two arguments are +*> not the same variable, and the test will not be optimized away. +*> Interprocedural or whole-program optimization may delete this +*> test. The ISNAN functions will be replaced by the correct +*> Fortran 03 intrinsic once the intrinsic is widely available. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] DIN1 +*> \verbatim +*> DIN1 is DOUBLE PRECISION +*> \endverbatim +*> +*> \param[in] DIN2 +*> \verbatim +*> DIN2 is DOUBLE PRECISION +*> Two numbers to compare for inequality. +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup laisnan +* +* ===================================================================== + LOGICAL FUNCTION DLAISNAN( DIN1, DIN2 ) +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + DOUBLE PRECISION, INTENT(IN) :: DIN1, DIN2 +* .. +* +* ===================================================================== +* +* .. Executable Statements .. + DLAISNAN = (DIN1.NE.DIN2) + RETURN + END diff --git a/OTHER/LAPACK/dlansy.f b/OTHER/LAPACK/dlansy.f new file mode 100644 index 0000000000..b6239929d9 --- /dev/null +++ b/OTHER/LAPACK/dlansy.f @@ -0,0 +1,240 @@ +*> \brief \b DLANSY returns the value of the 1-norm, or the Frobenius norm, or the infinity norm, or the element of largest absolute value of a real symmetric matrix. +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DLANSY + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* DOUBLE PRECISION FUNCTION DLANSY( NORM, UPLO, N, A, LDA, WORK ) +* +* .. Scalar Arguments .. +* CHARACTER NORM, UPLO +* INTEGER LDA, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), WORK( * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DLANSY returns the value of the one norm, or the Frobenius norm, or +*> the infinity norm, or the element of largest absolute value of a +*> real symmetric matrix A. +*> \endverbatim +*> +*> \return DLANSY +*> \verbatim +*> +*> DLANSY = ( max(abs(A(i,j))), NORM = 'M' or 'm' +*> ( +*> ( norm1(A), NORM = '1', 'O' or 'o' +*> ( +*> ( normI(A), NORM = 'I' or 'i' +*> ( +*> ( normF(A), NORM = 'F', 'f', 'E' or 'e' +*> +*> where norm1 denotes the one norm of a matrix (maximum column sum), +*> normI denotes the infinity norm of a matrix (maximum row sum) and +*> normF denotes the Frobenius norm of a matrix (square root of sum of +*> squares). Note that max(abs(A(i,j))) is not a consistent matrix norm. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] NORM +*> \verbatim +*> NORM is CHARACTER*1 +*> Specifies the value to be returned in DLANSY as described +*> above. +*> \endverbatim +*> +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the upper or lower triangular part of the +*> symmetric matrix A is to be referenced. +*> = 'U': Upper triangular part of A is referenced +*> = 'L': Lower triangular part of A is referenced +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the matrix A. N >= 0. When N = 0, DLANSY is +*> set to zero. +*> \endverbatim +*> +*> \param[in] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> The symmetric matrix A. If UPLO = 'U', the leading n by n +*> upper triangular part of A contains the upper triangular part +*> of the matrix A, and the strictly lower triangular part of A +*> is not referenced. If UPLO = 'L', the leading n by n lower +*> triangular part of A contains the lower triangular part of +*> the matrix A, and the strictly upper triangular part of A is +*> not referenced. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(N,1). +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)), +*> where LWORK >= N when NORM = 'I' or '1' or 'O'; otherwise, +*> WORK is not referenced. +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup lanhe +* +* ===================================================================== + DOUBLE PRECISION FUNCTION DLANSY( NORM, UPLO, N, A, LDA, WORK ) +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER NORM, UPLO + INTEGER LDA, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), WORK( * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO + PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + INTEGER I, J + DOUBLE PRECISION ABSA, SCALE, SUM, VALUE +* .. +* .. External Subroutines .. + EXTERNAL DLASSQ +* .. +* .. External Functions .. + LOGICAL LSAME, DISNAN + EXTERNAL LSAME, DISNAN +* .. +* .. Intrinsic Functions .. + INTRINSIC ABS, SQRT +* .. +* .. Executable Statements .. +* + IF( N.EQ.0 ) THEN + VALUE = ZERO + ELSE IF( LSAME( NORM, 'M' ) ) THEN +* +* Find max(abs(A(i,j))). +* + VALUE = ZERO + IF( LSAME( UPLO, 'U' ) ) THEN + DO 20 J = 1, N + DO 10 I = 1, J + SUM = ABS( A( I, J ) ) + IF( VALUE .LT. SUM .OR. DISNAN( SUM ) ) VALUE = SUM + 10 CONTINUE + 20 CONTINUE + ELSE + DO 40 J = 1, N + DO 30 I = J, N + SUM = ABS( A( I, J ) ) + IF( VALUE .LT. SUM .OR. DISNAN( SUM ) ) VALUE = SUM + 30 CONTINUE + 40 CONTINUE + END IF + ELSE IF( ( LSAME( NORM, 'I' ) ) .OR. + $ ( LSAME( NORM, 'O' ) ) .OR. + $ ( NORM.EQ.'1' ) ) THEN +* +* Find normI(A) ( = norm1(A), since A is symmetric). +* + VALUE = ZERO + IF( LSAME( UPLO, 'U' ) ) THEN + DO 60 J = 1, N + SUM = ZERO + DO 50 I = 1, J - 1 + ABSA = ABS( A( I, J ) ) + SUM = SUM + ABSA + WORK( I ) = WORK( I ) + ABSA + 50 CONTINUE + WORK( J ) = SUM + ABS( A( J, J ) ) + 60 CONTINUE + DO 70 I = 1, N + SUM = WORK( I ) + IF( VALUE .LT. SUM .OR. DISNAN( SUM ) ) VALUE = SUM + 70 CONTINUE + ELSE + DO 80 I = 1, N + WORK( I ) = ZERO + 80 CONTINUE + DO 100 J = 1, N + SUM = WORK( J ) + ABS( A( J, J ) ) + DO 90 I = J + 1, N + ABSA = ABS( A( I, J ) ) + SUM = SUM + ABSA + WORK( I ) = WORK( I ) + ABSA + 90 CONTINUE + IF( VALUE .LT. SUM .OR. DISNAN( SUM ) ) VALUE = SUM + 100 CONTINUE + END IF + ELSE IF( ( LSAME( NORM, 'F' ) ) .OR. + $ ( LSAME( NORM, 'E' ) ) ) THEN +* +* Find normF(A). +* + SCALE = ZERO + SUM = ONE + IF( LSAME( UPLO, 'U' ) ) THEN + DO 110 J = 2, N + CALL DLASSQ( J-1, A( 1, J ), 1, SCALE, SUM ) + 110 CONTINUE + ELSE + DO 120 J = 1, N - 1 + CALL DLASSQ( N-J, A( J+1, J ), 1, SCALE, SUM ) + 120 CONTINUE + END IF + SUM = 2*SUM + CALL DLASSQ( N, A, LDA+1, SCALE, SUM ) + VALUE = SCALE*SQRT( SUM ) + END IF +* + DLANSY = VALUE + RETURN +* +* End of DLANSY +* + END diff --git a/OTHER/LAPACK/dlarf1l.f b/OTHER/LAPACK/dlarf1l.f new file mode 100644 index 0000000000..80a486f79c --- /dev/null +++ b/OTHER/LAPACK/dlarf1l.f @@ -0,0 +1,252 @@ +*> \brief \b DLARF1L applies an elementary reflector to a general rectangular +* matrix assuming v(lastv) = 1 where lastv is the last non-zero +* element +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DLARF1L + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DLARF1L( SIDE, M, N, V, INCV, TAU, C, LDC, WORK ) +* +* .. Scalar Arguments .. +* CHARACTER SIDE +* INTEGER INCV, LDC, M, N +* DOUBLE PRECISION TAU +* .. +* .. Array Arguments .. +* DOUBLE PRECISION C( LDC, * ), V( * ), WORK( * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DLARF1L applies a real elementary reflector H to a real m by n matrix +*> C, from either the left or the right. H is represented in the form +*> +*> H = I - tau * v * v**T +*> +*> where tau is a real scalar and v is a real vector. +*> +*> If tau = 0, then H is taken to be the unit matrix. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] SIDE +*> \verbatim +*> SIDE is CHARACTER*1 +*> = 'L': form H * C +*> = 'R': form C * H +*> \endverbatim +*> +*> \param[in] M +*> \verbatim +*> M is INTEGER +*> The number of rows of the matrix C. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The number of columns of the matrix C. +*> \endverbatim +*> +*> \param[in] V +*> \verbatim +*> V is DOUBLE PRECISION array, dimension +*> (1 + (M-1)*abs(INCV)) if SIDE = 'L' +*> or (1 + (N-1)*abs(INCV)) if SIDE = 'R' +*> The vector v in the representation of H. V is not used if +*> TAU = 0. +*> \endverbatim +*> +*> \param[in] INCV +*> \verbatim +*> INCV is INTEGER +*> The increment between elements of v. INCV <> 0. +*> \endverbatim +*> +*> \param[in] TAU +*> \verbatim +*> TAU is DOUBLE PRECISION +*> The value tau in the representation of H. +*> \endverbatim +*> +*> \param[in,out] C +*> \verbatim +*> C is DOUBLE PRECISION array, dimension (LDC,N) +*> On entry, the m by n matrix C. +*> On exit, C is overwritten by the matrix H * C if SIDE = 'L', +*> or C * H if SIDE = 'R'. +*> \endverbatim +*> +*> \param[in] LDC +*> \verbatim +*> LDC is INTEGER +*> The leading dimension of the array C. LDC >= max(1,M). +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension +*> (N) if SIDE = 'L' +*> or (M) if SIDE = 'R' +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup larf +* +* ===================================================================== + SUBROUTINE DLARF1L( SIDE, M, N, V, INCV, TAU, C, LDC, WORK ) +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER SIDE + INTEGER INCV, LDC, M, N + DOUBLE PRECISION TAU +* .. +* .. Array Arguments .. + DOUBLE PRECISION C( LDC, * ), V( * ), WORK( * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO + PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL APPLYLEFT + INTEGER I, FIRSTV, LASTV, LASTC +* .. +* .. External Subroutines .. + EXTERNAL DGEMV, DGER +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILADLR, ILADLC + EXTERNAL LSAME, ILADLR, ILADLC +* .. +* .. Executable Statements .. +* + APPLYLEFT = LSAME( SIDE, 'L' ) + FIRSTV = 1 + LASTC = 0 + IF( TAU.NE.ZERO ) THEN +! Set up variables for scanning V. LASTV begins pointing to the end +! of V. + IF( APPLYLEFT ) THEN + LASTV = M + ELSE + LASTV = N + END IF + I = 1 +! Look for the last non-zero row in V. + DO WHILE( LASTV.GT.FIRSTV .AND. V( I ).EQ.ZERO ) + FIRSTV = FIRSTV + 1 + I = I + INCV + END DO + IF( APPLYLEFT ) THEN +! Scan for the last non-zero column in C(1:lastv,:). + LASTC = ILADLC(LASTV, N, C, LDC) + ELSE +! Scan for the last non-zero row in C(:,1:lastv). + LASTC = ILADLR(M, LASTV, C, LDC) + END IF + END IF + IF( LASTC.EQ.0 ) THEN + RETURN + END IF + IF( APPLYLEFT ) THEN +* +* Form H * C +* + IF( LASTV.GT.0 ) THEN + ! Check if m = 1. This means v = 1, So we just need to compute + ! C := HC = (1-\tau)C. + IF( LASTV.EQ.FIRSTV ) THEN + CALL DSCAL(LASTC, ONE - TAU, C( FIRSTV, 1), LDC) + ELSE +* +* w(1:lastc,1) := C(1:lastv,1:lastc)**T * v(1:lastv,1) +* + ! w(1:lastc,1) := C(1:lastv-1,1:lastc)**T * v(1:lastv-1,1) + CALL DGEMV( 'Transpose', LASTV-FIRSTV, LASTC, ONE, + $ C(FIRSTV,1), LDC, V(I), INCV, ZERO, + $ WORK, 1) + ! w(1:lastc,1) += C(lastv,1:lastc)**T * v(lastv,1) = C(lastv,1:lastc)**T + CALL DAXPY(LASTC, ONE, C(LASTV,1), LDC, WORK, 1) +* +* C(1:lastv,1:lastc) := C(...) - tau * v(1:lastv,1) * w(1:lastc,1)**T +* + ! C(lastv, 1:lastc) := C(...) - tau * v(lastv,1) * w(1:lastc,1)**T + ! = C(...) - tau * w(1:lastc,1)**T + CALL DAXPY(LASTC, -TAU, WORK, 1, C(LASTV,1), LDC) + ! C(1:lastv-1,1:lastc) := C(...) - tau * v(1:lastv-1,1)*w(1:lastc,1)**T + CALL DGER(LASTV-FIRSTV, LASTC, -TAU, V(I), INCV, + $ WORK, 1, C(FIRSTV,1), LDC) + END IF + END IF + ELSE +* +* Form C * H +* + IF( LASTV.GT.0 ) THEN + ! Check if n = 1. This means v = 1, so we just need to compute + ! C := CH = C(1-\tau). + IF( LASTV.EQ.FIRSTV ) THEN + CALL DSCAL(LASTC, ONE - TAU, C, 1) + ELSE +* +* w(1:lastc,1) := C(1:lastc,1:lastv) * v(1:lastv,1) +* + ! w(1:lastc,1) := C(1:lastc,1:lastv-1) * v(1:lastv-1,1) + CALL DGEMV( 'No transpose', LASTC, LASTV-FIRSTV, + $ ONE, C(1,FIRSTV), LDC, V(I), INCV, ZERO, WORK, 1 ) + ! w(1:lastc,1) += C(1:lastc,lastv) * v(lastv,1) = C(1:lastc,lastv) + CALL DAXPY(LASTC, ONE, C(1,LASTV), 1, WORK, 1) +* +* C(1:lastc,1:lastv) := C(...) - tau * w(1:lastc,1) * v(1:lastv,1)**T +* + ! C(1:lastc,lastv) := C(...) - tau * w(1:lastc,1) * v(lastv,1)**T + ! = C(...) - tau * w(1:lastc,1) + CALL DAXPY(LASTC, -TAU, WORK, 1, C(1,LASTV), 1) + ! C(1:lastc,1:lastv-1) := C(...) - tau * w(1:lastc,1) * v(1:lastv-1)**T + CALL DGER( LASTC, LASTV-FIRSTV, -TAU, WORK, 1, V(I), + $ INCV, C(1,FIRSTV), LDC ) + END IF + END IF + END IF + RETURN +* +* End of DLARF1L +* + END diff --git a/OTHER/LAPACK/dlatrd.f b/OTHER/LAPACK/dlatrd.f new file mode 100644 index 0000000000..e5737be058 --- /dev/null +++ b/OTHER/LAPACK/dlatrd.f @@ -0,0 +1,343 @@ +*> \brief \b DLATRD reduces the first nb rows and columns of a symmetric/Hermitian matrix A to real tridiagonal form by an orthogonal similarity transformation. +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DLATRD + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DLATRD( UPLO, N, NB, A, LDA, E, TAU, W, LDW ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER LDA, LDW, N, NB +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), E( * ), TAU( * ), W( LDW, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DLATRD reduces NB rows and columns of a real symmetric matrix A to +*> symmetric tridiagonal form by an orthogonal similarity +*> transformation Q**T * A * Q, and returns the matrices V and W which are +*> needed to apply the transformation to the unreduced part of A. +*> +*> If UPLO = 'U', DLATRD reduces the last NB rows and columns of a +*> matrix, of which the upper triangle is supplied; +*> if UPLO = 'L', DLATRD reduces the first NB rows and columns of a +*> matrix, of which the lower triangle is supplied. +*> +*> This is an auxiliary routine called by DSYTRD. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the upper or lower triangular part of the +*> symmetric matrix A is stored: +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the matrix A. +*> \endverbatim +*> +*> \param[in] NB +*> \verbatim +*> NB is INTEGER +*> The number of rows and columns to be reduced. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> On entry, the symmetric matrix A. If UPLO = 'U', the leading +*> n-by-n upper triangular part of A contains the upper +*> triangular part of the matrix A, and the strictly lower +*> triangular part of A is not referenced. If UPLO = 'L', the +*> leading n-by-n lower triangular part of A contains the lower +*> triangular part of the matrix A, and the strictly upper +*> triangular part of A is not referenced. +*> On exit: +*> if UPLO = 'U', the last NB columns have been reduced to +*> tridiagonal form, with the diagonal elements overwriting +*> the diagonal elements of A; the elements above the diagonal +*> with the array TAU, represent the orthogonal matrix Q as a +*> product of elementary reflectors; +*> if UPLO = 'L', the first NB columns have been reduced to +*> tridiagonal form, with the diagonal elements overwriting +*> the diagonal elements of A; the elements below the diagonal +*> with the array TAU, represent the orthogonal matrix Q as a +*> product of elementary reflectors. +*> See Further Details. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= (1,N). +*> \endverbatim +*> +*> \param[out] E +*> \verbatim +*> E is DOUBLE PRECISION array, dimension (N-1) +*> If UPLO = 'U', E(n-nb:n-1) contains the superdiagonal +*> elements of the last NB columns of the reduced matrix; +*> if UPLO = 'L', E(1:nb) contains the subdiagonal elements of +*> the first NB columns of the reduced matrix. +*> \endverbatim +*> +*> \param[out] TAU +*> \verbatim +*> TAU is DOUBLE PRECISION array, dimension (N-1) +*> The scalar factors of the elementary reflectors, stored in +*> TAU(n-nb:n-1) if UPLO = 'U', and in TAU(1:nb) if UPLO = 'L'. +*> See Further Details. +*> \endverbatim +*> +*> \param[out] W +*> \verbatim +*> W is DOUBLE PRECISION array, dimension (LDW,NB) +*> The n-by-nb matrix W required to update the unreduced part +*> of A. +*> \endverbatim +*> +*> \param[in] LDW +*> \verbatim +*> LDW is INTEGER +*> The leading dimension of the array W. LDW >= max(1,N). +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup latrd +* +*> \par Further Details: +* ===================== +*> +*> \verbatim +*> +*> If UPLO = 'U', the matrix Q is represented as a product of elementary +*> reflectors +*> +*> Q = H(n) H(n-1) . . . H(n-nb+1). +*> +*> Each H(i) has the form +*> +*> H(i) = I - tau * v * v**T +*> +*> where tau is a real scalar, and v is a real vector with +*> v(i:n) = 0 and v(i-1) = 1; v(1:i-1) is stored on exit in A(1:i-1,i), +*> and tau in TAU(i-1). +*> +*> If UPLO = 'L', the matrix Q is represented as a product of elementary +*> reflectors +*> +*> Q = H(1) H(2) . . . H(nb). +*> +*> Each H(i) has the form +*> +*> H(i) = I - tau * v * v**T +*> +*> where tau is a real scalar, and v is a real vector with +*> v(1:i) = 0 and v(i+1) = 1; v(i+1:n) is stored on exit in A(i+1:n,i), +*> and tau in TAU(i). +*> +*> The elements of the vectors v together form the n-by-nb matrix V +*> which is needed, with W, to apply the transformation to the unreduced +*> part of the matrix, using a symmetric rank-2k update of the form: +*> A := A - V*W**T - W*V**T. +*> +*> The contents of A on exit are illustrated by the following examples +*> with n = 5 and nb = 2: +*> +*> if UPLO = 'U': if UPLO = 'L': +*> +*> ( a a a v4 v5 ) ( d ) +*> ( a a v4 v5 ) ( 1 d ) +*> ( a 1 v5 ) ( v1 1 a ) +*> ( d 1 ) ( v1 v2 a a ) +*> ( d ) ( v1 v2 a a a ) +*> +*> where d denotes a diagonal element of the reduced matrix, a denotes +*> an element of the original matrix that is unchanged, and vi denotes +*> an element of the vector defining H(i). +*> \endverbatim +*> +* ===================================================================== + SUBROUTINE DLATRD( UPLO, N, NB, A, LDA, E, TAU, W, LDW ) +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER LDA, LDW, N, NB +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), E( * ), TAU( * ), W( LDW, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ZERO, ONE, HALF + PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0, HALF = 0.5D+0 ) +* .. +* .. Local Scalars .. + INTEGER I, IW + DOUBLE PRECISION ALPHA +* .. +* .. External Subroutines .. + EXTERNAL DAXPY, DGEMV, DLARFG, DSCAL, DSYMV +* .. +* .. External Functions .. + LOGICAL LSAME + DOUBLE PRECISION DDOT + EXTERNAL LSAME, DDOT +* .. +* .. Intrinsic Functions .. + INTRINSIC MIN +* .. +* .. Executable Statements .. +* +* Quick return if possible +* + IF( N.LE.0 ) + $ RETURN +* + IF( LSAME( UPLO, 'U' ) ) THEN +* +* Reduce last NB columns of upper triangle +* + DO 10 I = N, N - NB + 1, -1 + IW = I - N + NB + IF( I.LT.N ) THEN +* +* Update A(1:i,i) +* + CALL DGEMV( 'No transpose', I, N-I, -ONE, A( 1, I+1 ), + $ LDA, W( I, IW+1 ), LDW, ONE, A( 1, I ), 1 ) + CALL DGEMV( 'No transpose', I, N-I, -ONE, W( 1, + $ IW+1 ), + $ LDW, A( I, I+1 ), LDA, ONE, A( 1, I ), 1 ) + END IF + IF( I.GT.1 ) THEN +* +* Generate elementary reflector H(i) to annihilate +* A(1:i-2,i) +* + CALL DLARFG( I-1, A( I-1, I ), A( 1, I ), 1, + $ TAU( I-1 ) ) + E( I-1 ) = A( I-1, I ) + A( I-1, I ) = ONE +* +* Compute W(1:i-1,i) +* + CALL DSYMV( 'Upper', I-1, ONE, A, LDA, A( 1, I ), 1, + $ ZERO, W( 1, IW ), 1 ) + IF( I.LT.N ) THEN + CALL DGEMV( 'Transpose', I-1, N-I, ONE, W( 1, + $ IW+1 ), + $ LDW, A( 1, I ), 1, ZERO, W( I+1, IW ), 1 ) + CALL DGEMV( 'No transpose', I-1, N-I, -ONE, + $ A( 1, I+1 ), LDA, W( I+1, IW ), 1, ONE, + $ W( 1, IW ), 1 ) + CALL DGEMV( 'Transpose', I-1, N-I, ONE, A( 1, + $ I+1 ), + $ LDA, A( 1, I ), 1, ZERO, W( I+1, IW ), 1 ) + CALL DGEMV( 'No transpose', I-1, N-I, -ONE, + $ W( 1, IW+1 ), LDW, W( I+1, IW ), 1, ONE, + $ W( 1, IW ), 1 ) + END IF + CALL DSCAL( I-1, TAU( I-1 ), W( 1, IW ), 1 ) + ALPHA = -HALF*TAU( I-1 )*DDOT( I-1, W( 1, IW ), 1, + $ A( 1, I ), 1 ) + CALL DAXPY( I-1, ALPHA, A( 1, I ), 1, W( 1, IW ), 1 ) + END IF +* + 10 CONTINUE + ELSE +* +* Reduce first NB columns of lower triangle +* + DO 20 I = 1, NB +* +* Update A(i:n,i) +* + CALL DGEMV( 'No transpose', N-I+1, I-1, -ONE, A( I, 1 ), + $ LDA, W( I, 1 ), LDW, ONE, A( I, I ), 1 ) + CALL DGEMV( 'No transpose', N-I+1, I-1, -ONE, W( I, 1 ), + $ LDW, A( I, 1 ), LDA, ONE, A( I, I ), 1 ) + IF( I.LT.N ) THEN +* +* Generate elementary reflector H(i) to annihilate +* A(i+2:n,i) +* + CALL DLARFG( N-I, A( I+1, I ), A( MIN( I+2, N ), I ), + $ 1, + $ TAU( I ) ) + E( I ) = A( I+1, I ) + A( I+1, I ) = ONE +* +* Compute W(i+1:n,i) +* + CALL DSYMV( 'Lower', N-I, ONE, A( I+1, I+1 ), LDA, + $ A( I+1, I ), 1, ZERO, W( I+1, I ), 1 ) + CALL DGEMV( 'Transpose', N-I, I-1, ONE, W( I+1, 1 ), + $ LDW, + $ A( I+1, I ), 1, ZERO, W( 1, I ), 1 ) + CALL DGEMV( 'No transpose', N-I, I-1, -ONE, A( I+1, + $ 1 ), + $ LDA, W( 1, I ), 1, ONE, W( I+1, I ), 1 ) + CALL DGEMV( 'Transpose', N-I, I-1, ONE, A( I+1, 1 ), + $ LDA, + $ A( I+1, I ), 1, ZERO, W( 1, I ), 1 ) + CALL DGEMV( 'No transpose', N-I, I-1, -ONE, W( I+1, + $ 1 ), + $ LDW, W( 1, I ), 1, ONE, W( I+1, I ), 1 ) + CALL DSCAL( N-I, TAU( I ), W( I+1, I ), 1 ) + ALPHA = -HALF*TAU( I )*DDOT( N-I, W( I+1, I ), 1, + $ A( I+1, I ), 1 ) + CALL DAXPY( N-I, ALPHA, A( I+1, I ), 1, W( I+1, I ), + $ 1 ) + END IF +* + 20 CONTINUE + END IF +* + RETURN +* +* End of DLATRD +* + END diff --git a/OTHER/LAPACK/dorg2l.f b/OTHER/LAPACK/dorg2l.f new file mode 100644 index 0000000000..b954302396 --- /dev/null +++ b/OTHER/LAPACK/dorg2l.f @@ -0,0 +1,196 @@ +*> \brief \b DORG2L generates all or part of the orthogonal matrix Q from a QL factorization determined by sgeqlf (unblocked algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DORG2L + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DORG2L( M, N, K, A, LDA, TAU, WORK, INFO ) +* +* .. Scalar Arguments .. +* INTEGER INFO, K, LDA, M, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DORG2L generates an m by n real matrix Q with orthonormal columns, +*> which is defined as the last n columns of a product of k elementary +*> reflectors of order m +*> +*> Q = H(k) . . . H(2) H(1) +*> +*> as returned by DGEQLF. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] M +*> \verbatim +*> M is INTEGER +*> The number of rows of the matrix Q. M >= 0. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The number of columns of the matrix Q. M >= N >= 0. +*> \endverbatim +*> +*> \param[in] K +*> \verbatim +*> K is INTEGER +*> The number of elementary reflectors whose product defines the +*> matrix Q. N >= K >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> On entry, the (n-k+i)-th column must contain the vector which +*> defines the elementary reflector H(i), for i = 1,2,...,k, as +*> returned by DGEQLF in the last k columns of its array +*> argument A. +*> On exit, the m by n matrix Q. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The first dimension of the array A. LDA >= max(1,M). +*> \endverbatim +*> +*> \param[in] TAU +*> \verbatim +*> TAU is DOUBLE PRECISION array, dimension (K) +*> TAU(i) must contain the scalar factor of the elementary +*> reflector H(i), as returned by DGEQLF. +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension (N) +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument has an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup ung2l +* +* ===================================================================== + SUBROUTINE DORG2L( M, N, K, A, LDA, TAU, WORK, INFO ) +* +* -- LAPACK computational routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + INTEGER INFO, K, LDA, M, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO + PARAMETER ( ONE = 1.0D+0, ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + INTEGER I, II, J, L +* .. +* .. External Subroutines .. + EXTERNAL DLARF1L, DSCAL, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX +* .. +* .. Executable Statements .. +* +* Test the input arguments +* + INFO = 0 + IF( M.LT.0 ) THEN + INFO = -1 + ELSE IF( N.LT.0 .OR. N.GT.M ) THEN + INFO = -2 + ELSE IF( K.LT.0 .OR. K.GT.N ) THEN + INFO = -3 + ELSE IF( LDA.LT.MAX( 1, M ) ) THEN + INFO = -5 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DORG2L', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.LE.0 ) + $ RETURN +* +* Initialise columns 1:n-k to columns of the unit matrix +* + DO 20 J = 1, N - K + DO 10 L = 1, M + A( L, J ) = ZERO + 10 CONTINUE + A( M-N+J, J ) = ONE + 20 CONTINUE +* + DO 40 I = 1, K + II = N - K + I +* +* Apply H(i) to A(1:m-k+i,1:n-k+i) from the left +* + !A(M-N+II, II) = ONE + CALL DLARF1L( 'Left', M-N+II, II-1, A( 1, II ), 1, TAU( I ), + $ A, + $ LDA, WORK ) + CALL DSCAL( M-N+II-1, -TAU( I ), A( 1, II ), 1 ) + A( M-N+II, II ) = ONE - TAU( I ) +* +* Set A(m-k+i+1:m,n-k+i) to zero +* + DO 30 L = M - N + II + 1, M + A( L, II ) = ZERO + 30 CONTINUE + 40 CONTINUE + RETURN +* +* End of DORG2L +* + END diff --git a/OTHER/LAPACK/dorgql.f b/OTHER/LAPACK/dorgql.f new file mode 100644 index 0000000000..f931f5a9c8 --- /dev/null +++ b/OTHER/LAPACK/dorgql.f @@ -0,0 +1,294 @@ +*> \brief \b DORGQL +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DORGQL + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DORGQL( M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) +* +* .. Scalar Arguments .. +* INTEGER INFO, K, LDA, LWORK, M, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DORGQL generates an M-by-N real matrix Q with orthonormal columns, +*> which is defined as the last N columns of a product of K elementary +*> reflectors of order M +*> +*> Q = H(k) . . . H(2) H(1) +*> +*> as returned by DGEQLF. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] M +*> \verbatim +*> M is INTEGER +*> The number of rows of the matrix Q. M >= 0. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The number of columns of the matrix Q. M >= N >= 0. +*> \endverbatim +*> +*> \param[in] K +*> \verbatim +*> K is INTEGER +*> The number of elementary reflectors whose product defines the +*> matrix Q. N >= K >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> On entry, the (n-k+i)-th column must contain the vector which +*> defines the elementary reflector H(i), for i = 1,2,...,k, as +*> returned by DGEQLF in the last k columns of its array +*> argument A. +*> On exit, the M-by-N matrix Q. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The first dimension of the array A. LDA >= max(1,M). +*> \endverbatim +*> +*> \param[in] TAU +*> \verbatim +*> TAU is DOUBLE PRECISION array, dimension (K) +*> TAU(i) must contain the scalar factor of the elementary +*> reflector H(i), as returned by DGEQLF. +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)) +*> On exit, if INFO = 0, WORK(1) returns the optimal LWORK. +*> \endverbatim +*> +*> \param[in] LWORK +*> \verbatim +*> LWORK is INTEGER +*> The dimension of the array WORK. LWORK >= max(1,N). +*> For optimum performance LWORK >= N*NB, where NB is the +*> optimal blocksize. +*> +*> If LWORK = -1, then a workspace query is assumed; the routine +*> only calculates the optimal size of the WORK array, returns +*> this value as the first entry of the WORK array, and no error +*> message related to LWORK is issued by XERBLA. +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument has an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup ungql +* +* ===================================================================== + SUBROUTINE DORGQL( M, N, K, A, LDA, TAU, WORK, LWORK, INFO ) +* +* -- LAPACK computational routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + INTEGER INFO, K, LDA, LWORK, M, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ZERO + PARAMETER ( ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL LQUERY + INTEGER I, IB, IINFO, IWS, J, KK, L, LDWORK, LWKOPT, + $ NB, NBMIN, NX +* .. +* .. External Subroutines .. + EXTERNAL DLARFB, DLARFT, DORG2L, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN +* .. +* .. External Functions .. + INTEGER ILAENV + EXTERNAL ILAENV +* .. +* .. Executable Statements .. +* +* Test the input arguments +* + INFO = 0 + LQUERY = ( LWORK.EQ.-1 ) + IF( M.LT.0 ) THEN + INFO = -1 + ELSE IF( N.LT.0 .OR. N.GT.M ) THEN + INFO = -2 + ELSE IF( K.LT.0 .OR. K.GT.N ) THEN + INFO = -3 + ELSE IF( LDA.LT.MAX( 1, M ) ) THEN + INFO = -5 + END IF +* + IF( INFO.EQ.0 ) THEN + IF( N.EQ.0 ) THEN + LWKOPT = 1 + ELSE + NB = ILAENV( 1, 'DORGQL', ' ', M, N, K, -1 ) + LWKOPT = N*NB + END IF + WORK( 1 ) = LWKOPT +* + IF( LWORK.LT.MAX( 1, N ) .AND. .NOT.LQUERY ) THEN + INFO = -8 + END IF + END IF +* + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DORGQL', -INFO ) + RETURN + ELSE IF( LQUERY ) THEN + RETURN + END IF +* +* Quick return if possible +* + IF( N.LE.0 ) THEN + RETURN + END IF +* + NBMIN = 2 + NX = 0 + IWS = N + IF( NB.GT.1 .AND. NB.LT.K ) THEN +* +* Determine when to cross over from blocked to unblocked code. +* + NX = MAX( 0, ILAENV( 3, 'DORGQL', ' ', M, N, K, -1 ) ) + IF( NX.LT.K ) THEN +* +* Determine if workspace is large enough for blocked code. +* + LDWORK = N + IWS = LDWORK*NB + IF( LWORK.LT.IWS ) THEN +* +* Not enough workspace to use optimal NB: reduce NB and +* determine the minimum value of NB. +* + NB = LWORK / LDWORK + NBMIN = MAX( 2, ILAENV( 2, 'DORGQL', ' ', M, N, K, + $ -1 ) ) + END IF + END IF + END IF +* + IF( NB.GE.NBMIN .AND. NB.LT.K .AND. NX.LT.K ) THEN +* +* Use blocked code after the first block. +* The last kk columns are handled by the block method. +* + KK = MIN( K, ( ( K-NX+NB-1 ) / NB )*NB ) +* +* Set A(m-kk+1:m,1:n-kk) to zero. +* + DO 20 J = 1, N - KK + DO 10 I = M - KK + 1, M + A( I, J ) = ZERO + 10 CONTINUE + 20 CONTINUE + ELSE + KK = 0 + END IF +* +* Use unblocked code for the first or only block. +* + CALL DORG2L( M-KK, N-KK, K-KK, A, LDA, TAU, WORK, IINFO ) +* + IF( KK.GT.0 ) THEN +* +* Use blocked code +* + DO 50 I = K - KK + 1, K, NB + IB = MIN( NB, K-I+1 ) + IF( N-K+I.GT.1 ) THEN +* +* Form the triangular factor of the block reflector +* H = H(i+ib-1) . . . H(i+1) H(i) +* + CALL DLARFT( 'Backward', 'Columnwise', M-K+I+IB-1, IB, + $ A( 1, N-K+I ), LDA, TAU( I ), WORK, LDWORK ) +* +* Apply H to A(1:m-k+i+ib-1,1:n-k+i-1) from the left +* + CALL DLARFB( 'Left', 'No transpose', 'Backward', + $ 'Columnwise', M-K+I+IB-1, N-K+I-1, IB, + $ A( 1, N-K+I ), LDA, WORK, LDWORK, A, LDA, + $ WORK( IB+1 ), LDWORK ) + END IF +* +* Apply H to rows 1:m-k+i+ib-1 of current block +* + CALL DORG2L( M-K+I+IB-1, IB, IB, A( 1, N-K+I ), LDA, + $ TAU( I ), WORK, IINFO ) +* +* Set rows m-k+i+ib:m of current block to zero +* + DO 40 J = N - K + I, N - K + I + IB - 1 + DO 30 L = M - K + I + IB, M + A( L, J ) = ZERO + 30 CONTINUE + 40 CONTINUE + 50 CONTINUE + END IF +* + WORK( 1 ) = IWS + RETURN +* +* End of DORGQL +* + END diff --git a/OTHER/LAPACK/dorgtr.f b/OTHER/LAPACK/dorgtr.f new file mode 100644 index 0000000000..d19c305959 --- /dev/null +++ b/OTHER/LAPACK/dorgtr.f @@ -0,0 +1,253 @@ +*> \brief \b DORGTR +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DORGTR + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DORGTR( UPLO, N, A, LDA, TAU, WORK, LWORK, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, LWORK, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DORGTR generates a real orthogonal matrix Q which is defined as the +*> product of n-1 elementary reflectors of order N, as returned by +*> DSYTRD: +*> +*> if UPLO = 'U', Q = H(n-1) . . . H(2) H(1), +*> +*> if UPLO = 'L', Q = H(1) H(2) . . . H(n-1). +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> = 'U': Upper triangle of A contains elementary reflectors +*> from DSYTRD; +*> = 'L': Lower triangle of A contains elementary reflectors +*> from DSYTRD. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the matrix Q. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> On entry, the vectors which define the elementary reflectors, +*> as returned by DSYTRD. +*> On exit, the N-by-N orthogonal matrix Q. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[in] TAU +*> \verbatim +*> TAU is DOUBLE PRECISION array, dimension (N-1) +*> TAU(i) must contain the scalar factor of the elementary +*> reflector H(i), as returned by DSYTRD. +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)) +*> On exit, if INFO = 0, WORK(1) returns the optimal LWORK. +*> \endverbatim +*> +*> \param[in] LWORK +*> \verbatim +*> LWORK is INTEGER +*> The dimension of the array WORK. LWORK >= max(1,N-1). +*> For optimum performance LWORK >= (N-1)*NB, where NB is +*> the optimal blocksize. +*> +*> If LWORK = -1, then a workspace query is assumed; the routine +*> only calculates the optimal size of the WORK array, returns +*> this value as the first entry of the WORK array, and no error +*> message related to LWORK is issued by XERBLA. +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup ungtr +* +* ===================================================================== + SUBROUTINE DORGTR( UPLO, N, A, LDA, TAU, WORK, LWORK, INFO ) +* +* -- LAPACK computational routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, LWORK, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), TAU( * ), WORK( * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ZERO, ONE + PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL LQUERY, UPPER + INTEGER I, IINFO, J, LWKOPT, NB +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL DORGQL, DORGQR, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX +* .. +* .. Executable Statements .. +* +* Test the input arguments +* + INFO = 0 + LQUERY = ( LWORK.EQ.-1 ) + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + ELSE IF( LWORK.LT.MAX( 1, N-1 ) .AND. .NOT.LQUERY ) THEN + INFO = -7 + END IF +* + IF( INFO.EQ.0 ) THEN + IF( UPPER ) THEN + NB = ILAENV( 1, 'DORGQL', ' ', N-1, N-1, N-1, -1 ) + ELSE + NB = ILAENV( 1, 'DORGQR', ' ', N-1, N-1, N-1, -1 ) + END IF + LWKOPT = MAX( 1, N-1 )*NB + WORK( 1 ) = LWKOPT + END IF +* + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DORGTR', -INFO ) + RETURN + ELSE IF( LQUERY ) THEN + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) THEN + WORK( 1 ) = 1 + RETURN + END IF +* + IF( UPPER ) THEN +* +* Q was determined by a call to DSYTRD with UPLO = 'U' +* +* Shift the vectors which define the elementary reflectors one +* column to the left, and set the last row and column of Q to +* those of the unit matrix +* + DO 20 J = 1, N - 1 + DO 10 I = 1, J - 1 + A( I, J ) = A( I, J+1 ) + 10 CONTINUE + A( N, J ) = ZERO + 20 CONTINUE + DO 30 I = 1, N - 1 + A( I, N ) = ZERO + 30 CONTINUE + A( N, N ) = ONE +* +* Generate Q(1:n-1,1:n-1) +* + CALL DORGQL( N-1, N-1, N-1, A, LDA, TAU, WORK, LWORK, + $ IINFO ) +* + ELSE +* +* Q was determined by a call to DSYTRD with UPLO = 'L'. +* +* Shift the vectors which define the elementary reflectors one +* column to the right, and set the first row and column of Q to +* those of the unit matrix +* + DO 50 J = N, 2, -1 + A( 1, J ) = ZERO + DO 40 I = J + 1, N + A( I, J ) = A( I, J-1 ) + 40 CONTINUE + 50 CONTINUE + A( 1, 1 ) = ONE + DO 60 I = 2, N + A( I, 1 ) = ZERO + 60 CONTINUE + IF( N.GT.1 ) THEN +* +* Generate Q(2:n,2:n) +* + CALL DORGQR( N-1, N-1, N-1, A( 2, 2 ), LDA, TAU, WORK, + $ LWORK, IINFO ) + END IF + END IF + WORK( 1 ) = LWKOPT + RETURN +* +* End of DORGTR +* + END diff --git a/OTHER/LAPACK/dorm2l.f b/OTHER/LAPACK/dorm2l.f new file mode 100644 index 0000000000..37866ed0cf --- /dev/null +++ b/OTHER/LAPACK/dorm2l.f @@ -0,0 +1,270 @@ +*> \brief \b DORM2L multiplies a general matrix by the orthogonal matrix from a QL factorization determined by sgeqlf (unblocked algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DORM2L + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DORM2L( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, +* WORK, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER SIDE, TRANS +* INTEGER INFO, K, LDA, LDC, M, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DORM2L overwrites the general real m by n matrix C with +*> +*> Q * C if SIDE = 'L' and TRANS = 'N', or +*> +*> Q**T * C if SIDE = 'L' and TRANS = 'T', or +*> +*> C * Q if SIDE = 'R' and TRANS = 'N', or +*> +*> C * Q**T if SIDE = 'R' and TRANS = 'T', +*> +*> where Q is a real orthogonal matrix defined as the product of k +*> elementary reflectors +*> +*> Q = H(k) . . . H(2) H(1) +*> +*> as returned by DGEQLF. Q is of order m if SIDE = 'L' and of order n +*> if SIDE = 'R'. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] SIDE +*> \verbatim +*> SIDE is CHARACTER*1 +*> = 'L': apply Q or Q**T from the Left +*> = 'R': apply Q or Q**T from the Right +*> \endverbatim +*> +*> \param[in] TRANS +*> \verbatim +*> TRANS is CHARACTER*1 +*> = 'N': apply Q (No transpose) +*> = 'T': apply Q**T (Transpose) +*> \endverbatim +*> +*> \param[in] M +*> \verbatim +*> M is INTEGER +*> The number of rows of the matrix C. M >= 0. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The number of columns of the matrix C. N >= 0. +*> \endverbatim +*> +*> \param[in] K +*> \verbatim +*> K is INTEGER +*> The number of elementary reflectors whose product defines +*> the matrix Q. +*> If SIDE = 'L', M >= K >= 0; +*> if SIDE = 'R', N >= K >= 0. +*> \endverbatim +*> +*> \param[in] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,K) +*> The i-th column must contain the vector which defines the +*> elementary reflector H(i), for i = 1,2,...,k, as returned by +*> DGEQLF in the last k columns of its array argument A. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. +*> If SIDE = 'L', LDA >= max(1,M); +*> if SIDE = 'R', LDA >= max(1,N). +*> \endverbatim +*> +*> \param[in] TAU +*> \verbatim +*> TAU is DOUBLE PRECISION array, dimension (K) +*> TAU(i) must contain the scalar factor of the elementary +*> reflector H(i), as returned by DGEQLF. +*> \endverbatim +*> +*> \param[in,out] C +*> \verbatim +*> C is DOUBLE PRECISION array, dimension (LDC,N) +*> On entry, the m by n matrix C. +*> On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. +*> \endverbatim +*> +*> \param[in] LDC +*> \verbatim +*> LDC is INTEGER +*> The leading dimension of the array C. LDC >= max(1,M). +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension +*> (N) if SIDE = 'L', +*> (M) if SIDE = 'R' +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup unm2l +* +* ===================================================================== + SUBROUTINE DORM2L( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, + $ WORK, INFO ) +* +* -- LAPACK computational routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER SIDE, TRANS + INTEGER INFO, K, LDA, LDC, M, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE + PARAMETER ( ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL LEFT, NOTRAN + INTEGER I, I1, I2, I3, MI, NI, NQ +* .. +* .. External Functions .. + LOGICAL LSAME + EXTERNAL LSAME +* .. +* .. External Subroutines .. + EXTERNAL DLARF1L, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX +* .. +* .. Executable Statements .. +* +* Test the input arguments +* + INFO = 0 + LEFT = LSAME( SIDE, 'L' ) + NOTRAN = LSAME( TRANS, 'N' ) +* +* NQ is the order of Q +* + IF( LEFT ) THEN + NQ = M + ELSE + NQ = N + END IF + IF( .NOT.LEFT .AND. .NOT.LSAME( SIDE, 'R' ) ) THEN + INFO = -1 + ELSE IF( .NOT.NOTRAN .AND. .NOT.LSAME( TRANS, 'T' ) ) THEN + INFO = -2 + ELSE IF( M.LT.0 ) THEN + INFO = -3 + ELSE IF( N.LT.0 ) THEN + INFO = -4 + ELSE IF( K.LT.0 .OR. K.GT.NQ ) THEN + INFO = -5 + ELSE IF( LDA.LT.MAX( 1, NQ ) ) THEN + INFO = -7 + ELSE IF( LDC.LT.MAX( 1, M ) ) THEN + INFO = -10 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DORM2L', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( M.EQ.0 .OR. N.EQ.0 .OR. K.EQ.0 ) + $ RETURN +* + IF( ( LEFT .AND. NOTRAN ) .OR. ( .NOT.LEFT .AND. .NOT.NOTRAN ) ) + $ THEN + I1 = 1 + I2 = K + I3 = 1 + ELSE + I1 = K + I2 = 1 + I3 = -1 + END IF +* + IF( LEFT ) THEN + NI = N + ELSE + MI = M + END IF +* + DO 10 I = I1, I2, I3 + IF( LEFT ) THEN +* +* H(i) is applied to C(1:m-k+i,1:n) +* + MI = M - K + I + ELSE +* +* H(i) is applied to C(1:m,1:n-k+i) +* + NI = N - K + I + END IF +* +* Apply H(i) +* + CALL DLARF1L( SIDE, MI, NI, A( 1, I ), 1, TAU( I ), C, LDC, + $ WORK ) + 10 CONTINUE + RETURN +* +* End of DORM2L +* + END diff --git a/OTHER/LAPACK/dormql.f b/OTHER/LAPACK/dormql.f new file mode 100644 index 0000000000..11022d78c6 --- /dev/null +++ b/OTHER/LAPACK/dormql.f @@ -0,0 +1,340 @@ +*> \brief \b DORMQL +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DORMQL + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DORMQL( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, +* WORK, LWORK, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER SIDE, TRANS +* INTEGER INFO, K, LDA, LDC, LWORK, M, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DORMQL overwrites the general real M-by-N matrix C with +*> +*> SIDE = 'L' SIDE = 'R' +*> TRANS = 'N': Q * C C * Q +*> TRANS = 'T': Q**T * C C * Q**T +*> +*> where Q is a real orthogonal matrix defined as the product of k +*> elementary reflectors +*> +*> Q = H(k) . . . H(2) H(1) +*> +*> as returned by DGEQLF. Q is of order M if SIDE = 'L' and of order N +*> if SIDE = 'R'. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] SIDE +*> \verbatim +*> SIDE is CHARACTER*1 +*> = 'L': apply Q or Q**T from the Left; +*> = 'R': apply Q or Q**T from the Right. +*> \endverbatim +*> +*> \param[in] TRANS +*> \verbatim +*> TRANS is CHARACTER*1 +*> = 'N': No transpose, apply Q; +*> = 'T': Transpose, apply Q**T. +*> \endverbatim +*> +*> \param[in] M +*> \verbatim +*> M is INTEGER +*> The number of rows of the matrix C. M >= 0. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The number of columns of the matrix C. N >= 0. +*> \endverbatim +*> +*> \param[in] K +*> \verbatim +*> K is INTEGER +*> The number of elementary reflectors whose product defines +*> the matrix Q. +*> If SIDE = 'L', M >= K >= 0; +*> if SIDE = 'R', N >= K >= 0. +*> \endverbatim +*> +*> \param[in] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,K) +*> The i-th column must contain the vector which defines the +*> elementary reflector H(i), for i = 1,2,...,k, as returned by +*> DGEQLF in the last k columns of its array argument A. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. +*> If SIDE = 'L', LDA >= max(1,M); +*> if SIDE = 'R', LDA >= max(1,N). +*> \endverbatim +*> +*> \param[in] TAU +*> \verbatim +*> TAU is DOUBLE PRECISION array, dimension (K) +*> TAU(i) must contain the scalar factor of the elementary +*> reflector H(i), as returned by DGEQLF. +*> \endverbatim +*> +*> \param[in,out] C +*> \verbatim +*> C is DOUBLE PRECISION array, dimension (LDC,N) +*> On entry, the M-by-N matrix C. +*> On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. +*> \endverbatim +*> +*> \param[in] LDC +*> \verbatim +*> LDC is INTEGER +*> The leading dimension of the array C. LDC >= max(1,M). +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)) +*> On exit, if INFO = 0, WORK(1) returns the optimal LWORK. +*> \endverbatim +*> +*> \param[in] LWORK +*> \verbatim +*> LWORK is INTEGER +*> The dimension of the array WORK. +*> If SIDE = 'L', LWORK >= max(1,N); +*> if SIDE = 'R', LWORK >= max(1,M). +*> For good performance, LWORK should generally be larger. +*> +*> If LWORK = -1, then a workspace query is assumed; the routine +*> only calculates the optimal size of the WORK array, returns +*> this value as the first entry of the WORK array, and no error +*> message related to LWORK is issued by XERBLA. +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup unmql +* +* ===================================================================== + SUBROUTINE DORMQL( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, + $ WORK, LWORK, INFO ) +* +* -- LAPACK computational routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER SIDE, TRANS + INTEGER INFO, K, LDA, LDC, LWORK, M, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + INTEGER NBMAX, LDT, TSIZE + PARAMETER ( NBMAX = 64, LDT = NBMAX+1, + $ TSIZE = LDT*NBMAX ) +* .. +* .. Local Scalars .. + LOGICAL LEFT, LQUERY, NOTRAN + INTEGER I, I1, I2, I3, IB, IINFO, IWT, LDWORK, LWKOPT, + $ MI, NB, NBMIN, NI, NQ, NW +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL DLARFB, DLARFT, DORM2L, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN +* .. +* .. Executable Statements .. +* +* Test the input arguments +* + INFO = 0 + LEFT = LSAME( SIDE, 'L' ) + NOTRAN = LSAME( TRANS, 'N' ) + LQUERY = ( LWORK.EQ.-1 ) +* +* NQ is the order of Q and NW is the minimum dimension of WORK +* + IF( LEFT ) THEN + NQ = M + NW = MAX( 1, N ) + ELSE + NQ = N + NW = MAX( 1, M ) + END IF + IF( .NOT.LEFT .AND. .NOT.LSAME( SIDE, 'R' ) ) THEN + INFO = -1 + ELSE IF( .NOT.NOTRAN .AND. .NOT.LSAME( TRANS, 'T' ) ) THEN + INFO = -2 + ELSE IF( M.LT.0 ) THEN + INFO = -3 + ELSE IF( N.LT.0 ) THEN + INFO = -4 + ELSE IF( K.LT.0 .OR. K.GT.NQ ) THEN + INFO = -5 + ELSE IF( LDA.LT.MAX( 1, NQ ) ) THEN + INFO = -7 + ELSE IF( LDC.LT.MAX( 1, M ) ) THEN + INFO = -10 + ELSE IF( LWORK.LT.NW .AND. .NOT.LQUERY ) THEN + INFO = -12 + END IF +* + IF( INFO.EQ.0 ) THEN +* +* Compute the workspace requirements +* + IF( M.EQ.0 .OR. N.EQ.0 ) THEN + LWKOPT = 1 + ELSE + NB = MIN( NBMAX, ILAENV( 1, 'DORMQL', SIDE // TRANS, M, + $ N, + $ K, -1 ) ) + LWKOPT = NW*NB + TSIZE + END IF + WORK( 1 ) = LWKOPT + END IF +* + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DORMQL', -INFO ) + RETURN + ELSE IF( LQUERY ) THEN + RETURN + END IF +* +* Quick return if possible +* + IF( M.EQ.0 .OR. N.EQ.0 ) THEN + RETURN + END IF +* + NBMIN = 2 + LDWORK = NW + IF( NB.GT.1 .AND. NB.LT.K ) THEN + IF( LWORK.LT.LWKOPT ) THEN + NB = (LWORK-TSIZE) / LDWORK + NBMIN = MAX( 2, ILAENV( 2, 'DORMQL', SIDE // TRANS, M, N, + $ K, + $ -1 ) ) + END IF + END IF +* + IF( NB.LT.NBMIN .OR. NB.GE.K ) THEN +* +* Use unblocked code +* + CALL DORM2L( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, + $ WORK, + $ IINFO ) + ELSE +* +* Use blocked code +* + IWT = 1 + NW*NB + IF( ( LEFT .AND. NOTRAN ) .OR. + $ ( .NOT.LEFT .AND. .NOT.NOTRAN ) ) THEN + I1 = 1 + I2 = K + I3 = NB + ELSE + I1 = ( ( K-1 ) / NB )*NB + 1 + I2 = 1 + I3 = -NB + END IF +* + IF( LEFT ) THEN + NI = N + ELSE + MI = M + END IF +* + DO 10 I = I1, I2, I3 + IB = MIN( NB, K-I+1 ) +* +* Form the triangular factor of the block reflector +* H = H(i+ib-1) . . . H(i+1) H(i) +* + CALL DLARFT( 'Backward', 'Columnwise', NQ-K+I+IB-1, IB, + $ A( 1, I ), LDA, TAU( I ), WORK( IWT ), LDT ) + IF( LEFT ) THEN +* +* H or H**T is applied to C(1:m-k+i+ib-1,1:n) +* + MI = M - K + I + IB - 1 + ELSE +* +* H or H**T is applied to C(1:m,1:n-k+i+ib-1) +* + NI = N - K + I + IB - 1 + END IF +* +* Apply H or H**T +* + CALL DLARFB( SIDE, TRANS, 'Backward', 'Columnwise', MI, + $ NI, + $ IB, A( 1, I ), LDA, WORK( IWT ), LDT, C, LDC, + $ WORK, LDWORK ) + 10 CONTINUE + END IF + WORK( 1 ) = LWKOPT + RETURN +* +* End of DORMQL +* + END diff --git a/OTHER/LAPACK/dormtr.f b/OTHER/LAPACK/dormtr.f new file mode 100644 index 0000000000..eb85afce72 --- /dev/null +++ b/OTHER/LAPACK/dormtr.f @@ -0,0 +1,310 @@ +*> \brief \b DORMTR +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DORMTR + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DORMTR( SIDE, UPLO, TRANS, M, N, A, LDA, TAU, C, LDC, +* WORK, LWORK, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER SIDE, TRANS, UPLO +* INTEGER INFO, LDA, LDC, LWORK, M, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DORMTR overwrites the general real M-by-N matrix C with +*> +*> SIDE = 'L' SIDE = 'R' +*> TRANS = 'N': Q * C C * Q +*> TRANS = 'T': Q**T * C C * Q**T +*> +*> where Q is a real orthogonal matrix of order nq, with nq = m if +*> SIDE = 'L' and nq = n if SIDE = 'R'. Q is defined as the product of +*> nq-1 elementary reflectors, as returned by DSYTRD: +*> +*> if UPLO = 'U', Q = H(nq-1) . . . H(2) H(1); +*> +*> if UPLO = 'L', Q = H(1) H(2) . . . H(nq-1). +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] SIDE +*> \verbatim +*> SIDE is CHARACTER*1 +*> = 'L': apply Q or Q**T from the Left; +*> = 'R': apply Q or Q**T from the Right. +*> \endverbatim +*> +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> = 'U': Upper triangle of A contains elementary reflectors +*> from DSYTRD; +*> = 'L': Lower triangle of A contains elementary reflectors +*> from DSYTRD. +*> \endverbatim +*> +*> \param[in] TRANS +*> \verbatim +*> TRANS is CHARACTER*1 +*> = 'N': No transpose, apply Q; +*> = 'T': Transpose, apply Q**T. +*> \endverbatim +*> +*> \param[in] M +*> \verbatim +*> M is INTEGER +*> The number of rows of the matrix C. M >= 0. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The number of columns of the matrix C. N >= 0. +*> \endverbatim +*> +*> \param[in] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension +*> (LDA,M) if SIDE = 'L' +*> (LDA,N) if SIDE = 'R' +*> The vectors which define the elementary reflectors, as +*> returned by DSYTRD. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. +*> LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'. +*> \endverbatim +*> +*> \param[in] TAU +*> \verbatim +*> TAU is DOUBLE PRECISION array, dimension +*> (M-1) if SIDE = 'L' +*> (N-1) if SIDE = 'R' +*> TAU(i) must contain the scalar factor of the elementary +*> reflector H(i), as returned by DSYTRD. +*> \endverbatim +*> +*> \param[in,out] C +*> \verbatim +*> C is DOUBLE PRECISION array, dimension (LDC,N) +*> On entry, the M-by-N matrix C. +*> On exit, C is overwritten by Q*C or Q**T*C or C*Q**T or C*Q. +*> \endverbatim +*> +*> \param[in] LDC +*> \verbatim +*> LDC is INTEGER +*> The leading dimension of the array C. LDC >= max(1,M). +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)) +*> On exit, if INFO = 0, WORK(1) returns the optimal LWORK. +*> \endverbatim +*> +*> \param[in] LWORK +*> \verbatim +*> LWORK is INTEGER +*> The dimension of the array WORK. +*> If SIDE = 'L', LWORK >= max(1,N); +*> if SIDE = 'R', LWORK >= max(1,M). +*> For optimum performance LWORK >= N*NB if SIDE = 'L', and +*> LWORK >= M*NB if SIDE = 'R', where NB is the optimal +*> blocksize. +*> +*> If LWORK = -1, then a workspace query is assumed; the routine +*> only calculates the optimal size of the WORK array, returns +*> this value as the first entry of the WORK array, and no error +*> message related to LWORK is issued by XERBLA. +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup unmtr +* +* ===================================================================== + SUBROUTINE DORMTR( SIDE, UPLO, TRANS, M, N, A, LDA, TAU, C, + $ LDC, + $ WORK, LWORK, INFO ) +* +* -- LAPACK computational routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER SIDE, TRANS, UPLO + INTEGER INFO, LDA, LDC, LWORK, M, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) +* .. +* +* ===================================================================== +* +* .. Local Scalars .. + LOGICAL LEFT, LQUERY, UPPER + INTEGER I1, I2, IINFO, LWKOPT, MI, NB, NI, NQ, NW +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL DORMQL, DORMQR, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX +* .. +* .. Executable Statements .. +* +* Test the input arguments +* + INFO = 0 + LEFT = LSAME( SIDE, 'L' ) + UPPER = LSAME( UPLO, 'U' ) + LQUERY = ( LWORK.EQ.-1 ) +* +* NQ is the order of Q and NW is the minimum dimension of WORK +* + IF( LEFT ) THEN + NQ = M + NW = MAX( 1, N ) + ELSE + NQ = N + NW = MAX( 1, M ) + END IF + IF( .NOT.LEFT .AND. .NOT.LSAME( SIDE, 'R' ) ) THEN + INFO = -1 + ELSE IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -2 + ELSE IF( .NOT.LSAME( TRANS, 'N' ) .AND. + $ .NOT.LSAME( TRANS, 'T' ) ) + $ THEN + INFO = -3 + ELSE IF( M.LT.0 ) THEN + INFO = -4 + ELSE IF( N.LT.0 ) THEN + INFO = -5 + ELSE IF( LDA.LT.MAX( 1, NQ ) ) THEN + INFO = -7 + ELSE IF( LDC.LT.MAX( 1, M ) ) THEN + INFO = -10 + ELSE IF( LWORK.LT.NW .AND. .NOT.LQUERY ) THEN + INFO = -12 + END IF +* + IF( INFO.EQ.0 ) THEN + IF( UPPER ) THEN + IF( LEFT ) THEN + NB = ILAENV( 1, 'DORMQL', SIDE // TRANS, M-1, N, M-1, + $ -1 ) + ELSE + NB = ILAENV( 1, 'DORMQL', SIDE // TRANS, M, N-1, N-1, + $ -1 ) + END IF + ELSE + IF( LEFT ) THEN + NB = ILAENV( 1, 'DORMQR', SIDE // TRANS, M-1, N, M-1, + $ -1 ) + ELSE + NB = ILAENV( 1, 'DORMQR', SIDE // TRANS, M, N-1, N-1, + $ -1 ) + END IF + END IF + LWKOPT = NW*NB + WORK( 1 ) = LWKOPT + END IF +* + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DORMTR', -INFO ) + RETURN + ELSE IF( LQUERY ) THEN + RETURN + END IF +* +* Quick return if possible +* + IF( M.EQ.0 .OR. N.EQ.0 .OR. NQ.EQ.1 ) THEN + WORK( 1 ) = 1 + RETURN + END IF +* + IF( LEFT ) THEN + MI = M - 1 + NI = N + ELSE + MI = M + NI = N - 1 + END IF +* + IF( UPPER ) THEN +* +* Q was determined by a call to DSYTRD with UPLO = 'U' +* + CALL DORMQL( SIDE, TRANS, MI, NI, NQ-1, A( 1, 2 ), LDA, TAU, + $ C, + $ LDC, WORK, LWORK, IINFO ) + ELSE +* +* Q was determined by a call to DSYTRD with UPLO = 'L' +* + IF( LEFT ) THEN + I1 = 2 + I2 = 1 + ELSE + I1 = 1 + I2 = 2 + END IF + CALL DORMQR( SIDE, TRANS, MI, NI, NQ-1, A( 2, 1 ), LDA, TAU, + $ C( I1, I2 ), LDC, WORK, LWORK, IINFO ) + END IF + WORK( 1 ) = LWKOPT + RETURN +* +* End of DORMTR +* + END diff --git a/OTHER/LAPACK/dsyevx.f b/OTHER/LAPACK/dsyevx.f new file mode 100644 index 0000000000..1f9954850f --- /dev/null +++ b/OTHER/LAPACK/dsyevx.f @@ -0,0 +1,555 @@ +*> \brief DSYEVX computes the eigenvalues and, optionally, the left and/or right eigenvectors for SY matrices +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DSYEVX + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DSYEVX( JOBZ, RANGE, UPLO, N, A, LDA, VL, VU, IL, IU, +* ABSTOL, M, W, Z, LDZ, WORK, LWORK, IWORK, +* IFAIL, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER JOBZ, RANGE, UPLO +* INTEGER IL, INFO, IU, LDA, LDZ, LWORK, M, N +* DOUBLE PRECISION ABSTOL, VL, VU +* .. +* .. Array Arguments .. +* INTEGER IFAIL( * ), IWORK( * ) +* DOUBLE PRECISION A( LDA, * ), W( * ), WORK( * ), Z( LDZ, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DSYEVX computes selected eigenvalues and, optionally, eigenvectors +*> of a real symmetric matrix A. Eigenvalues and eigenvectors can be +*> selected by specifying either a range of values or a range of indices +*> for the desired eigenvalues. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] JOBZ +*> \verbatim +*> JOBZ is CHARACTER*1 +*> = 'N': Compute eigenvalues only; +*> = 'V': Compute eigenvalues and eigenvectors. +*> \endverbatim +*> +*> \param[in] RANGE +*> \verbatim +*> RANGE is CHARACTER*1 +*> = 'A': all eigenvalues will be found. +*> = 'V': all eigenvalues in the half-open interval (VL,VU] +*> will be found. +*> = 'I': the IL-th through IU-th eigenvalues will be found. +*> \endverbatim +*> +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> = 'U': Upper triangle of A is stored; +*> = 'L': Lower triangle of A is stored. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the matrix A. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA, N) +*> On entry, the symmetric matrix A. If UPLO = 'U', the +*> leading N-by-N upper triangular part of A contains the +*> upper triangular part of the matrix A. If UPLO = 'L', +*> the leading N-by-N lower triangular part of A contains +*> the lower triangular part of the matrix A. +*> On exit, the lower triangle (if UPLO='L') or the upper +*> triangle (if UPLO='U') of A, including the diagonal, is +*> destroyed. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[in] VL +*> \verbatim +*> VL is DOUBLE PRECISION +*> If RANGE='V', the lower bound of the interval to +*> be searched for eigenvalues. VL < VU. +*> Not referenced if RANGE = 'A' or 'I'. +*> \endverbatim +*> +*> \param[in] VU +*> \verbatim +*> VU is DOUBLE PRECISION +*> If RANGE='V', the upper bound of the interval to +*> be searched for eigenvalues. VL < VU. +*> Not referenced if RANGE = 'A' or 'I'. +*> \endverbatim +*> +*> \param[in] IL +*> \verbatim +*> IL is INTEGER +*> If RANGE='I', the index of the +*> smallest eigenvalue to be returned. +*> 1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0. +*> Not referenced if RANGE = 'A' or 'V'. +*> \endverbatim +*> +*> \param[in] IU +*> \verbatim +*> IU is INTEGER +*> If RANGE='I', the index of the +*> largest eigenvalue to be returned. +*> 1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0. +*> Not referenced if RANGE = 'A' or 'V'. +*> \endverbatim +*> +*> \param[in] ABSTOL +*> \verbatim +*> ABSTOL is DOUBLE PRECISION +*> The absolute error tolerance for the eigenvalues. +*> An approximate eigenvalue is accepted as converged +*> when it is determined to lie in an interval [a,b] +*> of width less than or equal to +*> +*> ABSTOL + EPS * max( |a|,|b| ) , +*> +*> where EPS is the machine precision. If ABSTOL is less than +*> or equal to zero, then EPS*|T| will be used in its place, +*> where |T| is the 1-norm of the tridiagonal matrix obtained +*> by reducing A to tridiagonal form. +*> +*> Eigenvalues will be computed most accurately when ABSTOL is +*> set to twice the underflow threshold 2*DLAMCH('S'), not zero. +*> If this routine returns with INFO>0, indicating that some +*> eigenvectors did not converge, try setting ABSTOL to +*> 2*DLAMCH('S'). +*> +*> See "Computing Small Singular Values of Bidiagonal Matrices +*> with Guaranteed High Relative Accuracy," by Demmel and +*> Kahan, LAPACK Working Note #3. +*> \endverbatim +*> +*> \param[out] M +*> \verbatim +*> M is INTEGER +*> The total number of eigenvalues found. 0 <= M <= N. +*> If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1. +*> \endverbatim +*> +*> \param[out] W +*> \verbatim +*> W is DOUBLE PRECISION array, dimension (N) +*> On normal exit, the first M elements contain the selected +*> eigenvalues in ascending order. +*> \endverbatim +*> +*> \param[out] Z +*> \verbatim +*> Z is DOUBLE PRECISION array, dimension (LDZ, max(1,M)) +*> If JOBZ = 'V', then if INFO = 0, the first M columns of Z +*> contain the orthonormal eigenvectors of the matrix A +*> corresponding to the selected eigenvalues, with the i-th +*> column of Z holding the eigenvector associated with W(i). +*> If an eigenvector fails to converge, then that column of Z +*> contains the latest approximation to the eigenvector, and the +*> index of the eigenvector is returned in IFAIL. +*> If JOBZ = 'N', then Z is not referenced. +*> Note: the user must ensure that at least max(1,M) columns are +*> supplied in the array Z; if RANGE = 'V', the exact value of M +*> is not known in advance and an upper bound must be used. +*> \endverbatim +*> +*> \param[in] LDZ +*> \verbatim +*> LDZ is INTEGER +*> The leading dimension of the array Z. LDZ >= 1, and if +*> JOBZ = 'V', LDZ >= max(1,N). +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)) +*> On exit, if INFO = 0, WORK(1) returns the optimal LWORK. +*> \endverbatim +*> +*> \param[in] LWORK +*> \verbatim +*> LWORK is INTEGER +*> The length of the array WORK. LWORK >= 1, when N <= 1; +*> otherwise 8*N. +*> For optimal efficiency, LWORK >= (NB+3)*N, +*> where NB is the max of the blocksize for DSYTRD and DORMTR +*> returned by ILAENV. +*> +*> If LWORK = -1, then a workspace query is assumed; the routine +*> only calculates the optimal size of the WORK array, returns +*> this value as the first entry of the WORK array, and no error +*> message related to LWORK is issued by XERBLA. +*> \endverbatim +*> +*> \param[out] IWORK +*> \verbatim +*> IWORK is INTEGER array, dimension (5*N) +*> \endverbatim +*> +*> \param[out] IFAIL +*> \verbatim +*> IFAIL is INTEGER array, dimension (N) +*> If JOBZ = 'V', then if INFO = 0, the first M elements of +*> IFAIL are zero. If INFO > 0, then IFAIL contains the +*> indices of the eigenvectors that failed to converge. +*> If JOBZ = 'N', then IFAIL is not referenced. +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument had an illegal value +*> > 0: if INFO = i, then i eigenvectors failed to converge. +*> Their indices are stored in array IFAIL. +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup heevx +* +* ===================================================================== + SUBROUTINE DSYEVX( JOBZ, RANGE, UPLO, N, A, LDA, VL, VU, IL, + $ IU, + $ ABSTOL, M, W, Z, LDZ, WORK, LWORK, IWORK, + $ IFAIL, INFO ) +* +* -- LAPACK driver routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER JOBZ, RANGE, UPLO + INTEGER IL, INFO, IU, LDA, LDZ, LWORK, M, N + DOUBLE PRECISION ABSTOL, VL, VU +* .. +* .. Array Arguments .. + INTEGER IFAIL( * ), IWORK( * ) + DOUBLE PRECISION A( LDA, * ), W( * ), WORK( * ), Z( LDZ, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ZERO, ONE + PARAMETER ( ZERO = 0.0D+0, ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL ALLEIG, INDEIG, LOWER, LQUERY, TEST, VALEIG, + $ WANTZ + CHARACTER ORDER + INTEGER I, IINFO, IMAX, INDD, INDE, INDEE, INDIBL, + $ INDISP, INDIWO, INDTAU, INDWKN, INDWRK, ISCALE, + $ ITMP1, J, JJ, LLWORK, LLWRKN, LWKMIN, + $ LWKOPT, NB, NSPLIT + DOUBLE PRECISION ABSTLL, ANRM, BIGNUM, EPS, RMAX, RMIN, SAFMIN, + $ SIGMA, SMLNUM, TMP1, VLL, VUU +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + DOUBLE PRECISION DLAMCH, DLANSY + EXTERNAL LSAME, ILAENV, DLAMCH, DLANSY +* .. +* .. External Subroutines .. + EXTERNAL DCOPY, DLACPY, DORGTR, DORMTR, DSCAL, + $ DSTEBZ, + $ DSTEIN, DSTEQR, DSTERF, DSWAP, DSYTRD, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN, SQRT +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + LOWER = LSAME( UPLO, 'L' ) + WANTZ = LSAME( JOBZ, 'V' ) + ALLEIG = LSAME( RANGE, 'A' ) + VALEIG = LSAME( RANGE, 'V' ) + INDEIG = LSAME( RANGE, 'I' ) + LQUERY = ( LWORK.EQ.-1 ) +* + INFO = 0 + IF( .NOT.( WANTZ .OR. LSAME( JOBZ, 'N' ) ) ) THEN + INFO = -1 + ELSE IF( .NOT.( ALLEIG .OR. VALEIG .OR. INDEIG ) ) THEN + INFO = -2 + ELSE IF( .NOT.( LOWER .OR. LSAME( UPLO, 'U' ) ) ) THEN + INFO = -3 + ELSE IF( N.LT.0 ) THEN + INFO = -4 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -6 + ELSE + IF( VALEIG ) THEN + IF( N.GT.0 .AND. VU.LE.VL ) + $ INFO = -8 + ELSE IF( INDEIG ) THEN + IF( IL.LT.1 .OR. IL.GT.MAX( 1, N ) ) THEN + INFO = -9 + ELSE IF( IU.LT.MIN( N, IL ) .OR. IU.GT.N ) THEN + INFO = -10 + END IF + END IF + END IF + IF( INFO.EQ.0 ) THEN + IF( LDZ.LT.1 .OR. ( WANTZ .AND. LDZ.LT.N ) ) THEN + INFO = -15 + END IF + END IF +* + IF( INFO.EQ.0 ) THEN + IF( N.LE.1 ) THEN + LWKMIN = 1 + LWKOPT = 1 + ELSE + LWKMIN = 8*N + NB = ILAENV( 1, 'DSYTRD', UPLO, N, -1, -1, -1 ) + NB = MAX( NB, ILAENV( 1, 'DORMTR', UPLO, N, -1, -1, + $ -1 ) ) + LWKOPT = MAX( LWKMIN, ( NB + 3 )*N ) + END IF + WORK( 1 ) = LWKOPT +* + IF( LWORK.LT.LWKMIN .AND. .NOT.LQUERY ) + $ INFO = -17 + END IF +* + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DSYEVX', -INFO ) + RETURN + ELSE IF( LQUERY ) THEN + RETURN + END IF +* +* Quick return if possible +* + M = 0 + IF( N.EQ.0 ) THEN + RETURN + END IF +* + IF( N.EQ.1 ) THEN + IF( ALLEIG .OR. INDEIG ) THEN + M = 1 + W( 1 ) = A( 1, 1 ) + ELSE + IF( VL.LT.A( 1, 1 ) .AND. VU.GE.A( 1, 1 ) ) THEN + M = 1 + W( 1 ) = A( 1, 1 ) + END IF + END IF + IF( WANTZ ) + $ Z( 1, 1 ) = ONE + RETURN + END IF +* +* Get machine constants. +* + SAFMIN = DLAMCH( 'Safe minimum' ) + EPS = DLAMCH( 'Precision' ) + SMLNUM = SAFMIN / EPS + BIGNUM = ONE / SMLNUM + RMIN = SQRT( SMLNUM ) + RMAX = MIN( SQRT( BIGNUM ), ONE / SQRT( SQRT( SAFMIN ) ) ) +* +* Scale matrix to allowable range, if necessary. +* + ISCALE = 0 + ABSTLL = ABSTOL + IF( VALEIG ) THEN + VLL = VL + VUU = VU + END IF + ANRM = DLANSY( 'M', UPLO, N, A, LDA, WORK ) + IF( ANRM.GT.ZERO .AND. ANRM.LT.RMIN ) THEN + ISCALE = 1 + SIGMA = RMIN / ANRM + ELSE IF( ANRM.GT.RMAX ) THEN + ISCALE = 1 + SIGMA = RMAX / ANRM + END IF + IF( ISCALE.EQ.1 ) THEN + IF( LOWER ) THEN + DO 10 J = 1, N + CALL DSCAL( N-J+1, SIGMA, A( J, J ), 1 ) + 10 CONTINUE + ELSE + DO 20 J = 1, N + CALL DSCAL( J, SIGMA, A( 1, J ), 1 ) + 20 CONTINUE + END IF + IF( ABSTOL.GT.0 ) + $ ABSTLL = ABSTOL*SIGMA + IF( VALEIG ) THEN + VLL = VL*SIGMA + VUU = VU*SIGMA + END IF + END IF +* +* Call DSYTRD to reduce symmetric matrix to tridiagonal form. +* + INDTAU = 1 + INDE = INDTAU + N + INDD = INDE + N + INDWRK = INDD + N + LLWORK = LWORK - INDWRK + 1 + CALL DSYTRD( UPLO, N, A, LDA, WORK( INDD ), WORK( INDE ), + $ WORK( INDTAU ), WORK( INDWRK ), LLWORK, IINFO ) +* +* If all eigenvalues are desired and ABSTOL is less than or equal to +* zero, then call DSTERF or DORGTR and SSTEQR. If this fails for +* some eigenvalue, then try DSTEBZ. +* + TEST = .FALSE. + IF( INDEIG ) THEN + IF( IL.EQ.1 .AND. IU.EQ.N ) THEN + TEST = .TRUE. + END IF + END IF + IF( ( ALLEIG .OR. TEST ) .AND. ( ABSTOL.LE.ZERO ) ) THEN + CALL DCOPY( N, WORK( INDD ), 1, W, 1 ) + INDEE = INDWRK + 2*N + IF( .NOT.WANTZ ) THEN + CALL DCOPY( N-1, WORK( INDE ), 1, WORK( INDEE ), 1 ) + CALL DSTERF( N, W, WORK( INDEE ), INFO ) + ELSE + CALL DLACPY( 'A', N, N, A, LDA, Z, LDZ ) + CALL DORGTR( UPLO, N, Z, LDZ, WORK( INDTAU ), + $ WORK( INDWRK ), LLWORK, IINFO ) + CALL DCOPY( N-1, WORK( INDE ), 1, WORK( INDEE ), 1 ) + CALL DSTEQR( JOBZ, N, W, WORK( INDEE ), Z, LDZ, + $ WORK( INDWRK ), INFO ) + IF( INFO.EQ.0 ) THEN + DO 30 I = 1, N + IFAIL( I ) = 0 + 30 CONTINUE + END IF + END IF + IF( INFO.EQ.0 ) THEN + M = N + GO TO 40 + END IF + INFO = 0 + END IF +* +* Otherwise, call DSTEBZ and, if eigenvectors are desired, SSTEIN. +* + IF( WANTZ ) THEN + ORDER = 'B' + ELSE + ORDER = 'E' + END IF + INDIBL = 1 + INDISP = INDIBL + N + INDIWO = INDISP + N + CALL DSTEBZ( RANGE, ORDER, N, VLL, VUU, IL, IU, ABSTLL, + $ WORK( INDD ), WORK( INDE ), M, NSPLIT, W, + $ IWORK( INDIBL ), IWORK( INDISP ), WORK( INDWRK ), + $ IWORK( INDIWO ), INFO ) +* + IF( WANTZ ) THEN + CALL DSTEIN( N, WORK( INDD ), WORK( INDE ), M, W, + $ IWORK( INDIBL ), IWORK( INDISP ), Z, LDZ, + $ WORK( INDWRK ), IWORK( INDIWO ), IFAIL, INFO ) +* +* Apply orthogonal matrix used in reduction to tridiagonal +* form to eigenvectors returned by DSTEIN. +* + INDWKN = INDE + LLWRKN = LWORK - INDWKN + 1 + CALL DORMTR( 'L', UPLO, 'N', N, M, A, LDA, WORK( INDTAU ), + $ Z, + $ LDZ, WORK( INDWKN ), LLWRKN, IINFO ) + END IF +* +* If matrix was scaled, then rescale eigenvalues appropriately. +* + 40 CONTINUE + IF( ISCALE.EQ.1 ) THEN + IF( INFO.EQ.0 ) THEN + IMAX = M + ELSE + IMAX = INFO - 1 + END IF + CALL DSCAL( IMAX, ONE / SIGMA, W, 1 ) + END IF +* +* If eigenvalues are not in order, then sort them, along with +* eigenvectors. +* + IF( WANTZ ) THEN + DO 60 J = 1, M - 1 + I = 0 + TMP1 = W( J ) + DO 50 JJ = J + 1, M + IF( W( JJ ).LT.TMP1 ) THEN + I = JJ + TMP1 = W( JJ ) + END IF + 50 CONTINUE +* + IF( I.NE.0 ) THEN + ITMP1 = IWORK( INDIBL+I-1 ) + W( I ) = W( J ) + IWORK( INDIBL+I-1 ) = IWORK( INDIBL+J-1 ) + W( J ) = TMP1 + IWORK( INDIBL+J-1 ) = ITMP1 + CALL DSWAP( N, Z( 1, I ), 1, Z( 1, J ), 1 ) + IF( INFO.NE.0 ) THEN + ITMP1 = IFAIL( I ) + IFAIL( I ) = IFAIL( J ) + IFAIL( J ) = ITMP1 + END IF + END IF + 60 CONTINUE + END IF +* +* Set WORK(1) to optimal workspace size. +* + WORK( 1 ) = LWKOPT +* + RETURN +* +* End of DSYEVX +* + END diff --git a/OTHER/LAPACK/dsygs2.f b/OTHER/LAPACK/dsygs2.f new file mode 100644 index 0000000000..dc747fcc7a --- /dev/null +++ b/OTHER/LAPACK/dsygs2.f @@ -0,0 +1,285 @@ +*> \brief \b DSYGS2 reduces a symmetric definite generalized eigenproblem to standard form, using the factorization results obtained from spotrf (unblocked algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DSYGS2 + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DSYGS2( ITYPE, UPLO, N, A, LDA, B, LDB, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, ITYPE, LDA, LDB, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), B( LDB, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DSYGS2 reduces a real symmetric-definite generalized eigenproblem +*> to standard form. +*> +*> If ITYPE = 1, the problem is A*x = lambda*B*x, +*> and A is overwritten by inv(U**T)*A*inv(U) or inv(L)*A*inv(L**T) +*> +*> If ITYPE = 2 or 3, the problem is A*B*x = lambda*x or +*> B*A*x = lambda*x, and A is overwritten by U*A*U**T or L**T *A*L. +*> +*> B must have been previously factorized as U**T *U or L*L**T by DPOTRF. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] ITYPE +*> \verbatim +*> ITYPE is INTEGER +*> = 1: compute inv(U**T)*A*inv(U) or inv(L)*A*inv(L**T); +*> = 2 or 3: compute U*A*U**T or L**T *A*L. +*> \endverbatim +*> +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the upper or lower triangular part of the +*> symmetric matrix A is stored, and how B has been factorized. +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the matrices A and B. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> On entry, the symmetric matrix A. If UPLO = 'U', the leading +*> n by n upper triangular part of A contains the upper +*> triangular part of the matrix A, and the strictly lower +*> triangular part of A is not referenced. If UPLO = 'L', the +*> leading n by n lower triangular part of A contains the lower +*> triangular part of the matrix A, and the strictly upper +*> triangular part of A is not referenced. +*> +*> On exit, if INFO = 0, the transformed matrix, stored in the +*> same format as A. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[in] B +*> \verbatim +*> B is DOUBLE PRECISION array, dimension (LDB,N) +*> The triangular factor from the Cholesky factorization of B, +*> as returned by DPOTRF. +*> \endverbatim +*> +*> \param[in] LDB +*> \verbatim +*> LDB is INTEGER +*> The leading dimension of the array B. LDB >= max(1,N). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit. +*> < 0: if INFO = -i, the i-th argument had an illegal value. +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup hegs2 +* +* ===================================================================== + SUBROUTINE DSYGS2( ITYPE, UPLO, N, A, LDA, B, LDB, INFO ) +* +* -- LAPACK computational routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, ITYPE, LDA, LDB, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), B( LDB, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, HALF + PARAMETER ( ONE = 1.0D0, HALF = 0.5D0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER K + DOUBLE PRECISION AKK, BKK, CT +* .. +* .. External Subroutines .. + EXTERNAL DAXPY, DSCAL, DSYR2, DTRMV, DTRSV, + $ XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX +* .. +* .. External Functions .. + LOGICAL LSAME + EXTERNAL LSAME +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( ITYPE.LT.1 .OR. ITYPE.GT.3 ) THEN + INFO = -1 + ELSE IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -2 + ELSE IF( N.LT.0 ) THEN + INFO = -3 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -5 + ELSE IF( LDB.LT.MAX( 1, N ) ) THEN + INFO = -7 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DSYGS2', -INFO ) + RETURN + END IF +* + IF( ITYPE.EQ.1 ) THEN + IF( UPPER ) THEN +* +* Compute inv(U**T)*A*inv(U) +* + DO 10 K = 1, N +* +* Update the upper triangle of A(k:n,k:n) +* + AKK = A( K, K ) + BKK = B( K, K ) + AKK = AKK / BKK**2 + A( K, K ) = AKK + IF( K.LT.N ) THEN + CALL DSCAL( N-K, ONE / BKK, A( K, K+1 ), LDA ) + CT = -HALF*AKK + CALL DAXPY( N-K, CT, B( K, K+1 ), LDB, A( K, K+1 ), + $ LDA ) + CALL DSYR2( UPLO, N-K, -ONE, A( K, K+1 ), LDA, + $ B( K, K+1 ), LDB, A( K+1, K+1 ), LDA ) + CALL DAXPY( N-K, CT, B( K, K+1 ), LDB, A( K, K+1 ), + $ LDA ) + CALL DTRSV( UPLO, 'Transpose', 'Non-unit', N-K, + $ B( K+1, K+1 ), LDB, A( K, K+1 ), LDA ) + END IF + 10 CONTINUE + ELSE +* +* Compute inv(L)*A*inv(L**T) +* + DO 20 K = 1, N +* +* Update the lower triangle of A(k:n,k:n) +* + AKK = A( K, K ) + BKK = B( K, K ) + AKK = AKK / BKK**2 + A( K, K ) = AKK + IF( K.LT.N ) THEN + CALL DSCAL( N-K, ONE / BKK, A( K+1, K ), 1 ) + CT = -HALF*AKK + CALL DAXPY( N-K, CT, B( K+1, K ), 1, A( K+1, K ), + $ 1 ) + CALL DSYR2( UPLO, N-K, -ONE, A( K+1, K ), 1, + $ B( K+1, K ), 1, A( K+1, K+1 ), LDA ) + CALL DAXPY( N-K, CT, B( K+1, K ), 1, A( K+1, K ), + $ 1 ) + CALL DTRSV( UPLO, 'No transpose', 'Non-unit', N-K, + $ B( K+1, K+1 ), LDB, A( K+1, K ), 1 ) + END IF + 20 CONTINUE + END IF + ELSE + IF( UPPER ) THEN +* +* Compute U*A*U**T +* + DO 30 K = 1, N +* +* Update the upper triangle of A(1:k,1:k) +* + AKK = A( K, K ) + BKK = B( K, K ) + CALL DTRMV( UPLO, 'No transpose', 'Non-unit', K-1, B, + $ LDB, A( 1, K ), 1 ) + CT = HALF*AKK + CALL DAXPY( K-1, CT, B( 1, K ), 1, A( 1, K ), 1 ) + CALL DSYR2( UPLO, K-1, ONE, A( 1, K ), 1, B( 1, K ), + $ 1, + $ A, LDA ) + CALL DAXPY( K-1, CT, B( 1, K ), 1, A( 1, K ), 1 ) + CALL DSCAL( K-1, BKK, A( 1, K ), 1 ) + A( K, K ) = AKK*BKK**2 + 30 CONTINUE + ELSE +* +* Compute L**T *A*L +* + DO 40 K = 1, N +* +* Update the lower triangle of A(1:k,1:k) +* + AKK = A( K, K ) + BKK = B( K, K ) + CALL DTRMV( UPLO, 'Transpose', 'Non-unit', K-1, B, + $ LDB, + $ A( K, 1 ), LDA ) + CT = HALF*AKK + CALL DAXPY( K-1, CT, B( K, 1 ), LDB, A( K, 1 ), LDA ) + CALL DSYR2( UPLO, K-1, ONE, A( K, 1 ), LDA, B( K, 1 ), + $ LDB, A, LDA ) + CALL DAXPY( K-1, CT, B( K, 1 ), LDB, A( K, 1 ), LDA ) + CALL DSCAL( K-1, BKK, A( K, 1 ), LDA ) + A( K, K ) = AKK*BKK**2 + 40 CONTINUE + END IF + END IF + RETURN +* +* End of DSYGS2 +* + END diff --git a/OTHER/LAPACK/dsygst.f b/OTHER/LAPACK/dsygst.f new file mode 100644 index 0000000000..eb48ee0907 --- /dev/null +++ b/OTHER/LAPACK/dsygst.f @@ -0,0 +1,327 @@ +*> \brief \b DSYGST +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DSYGST + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DSYGST( ITYPE, UPLO, N, A, LDA, B, LDB, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, ITYPE, LDA, LDB, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), B( LDB, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DSYGST reduces a real symmetric-definite generalized eigenproblem +*> to standard form. +*> +*> If ITYPE = 1, the problem is A*x = lambda*B*x, +*> and A is overwritten by inv(U**T)*A*inv(U) or inv(L)*A*inv(L**T) +*> +*> If ITYPE = 2 or 3, the problem is A*B*x = lambda*x or +*> B*A*x = lambda*x, and A is overwritten by U*A*U**T or L**T*A*L. +*> +*> B must have been previously factorized as U**T*U or L*L**T by DPOTRF. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] ITYPE +*> \verbatim +*> ITYPE is INTEGER +*> = 1: compute inv(U**T)*A*inv(U) or inv(L)*A*inv(L**T); +*> = 2 or 3: compute U*A*U**T or L**T*A*L. +*> \endverbatim +*> +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> = 'U': Upper triangle of A is stored and B is factored as +*> U**T*U; +*> = 'L': Lower triangle of A is stored and B is factored as +*> L*L**T. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the matrices A and B. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> On entry, the symmetric matrix A. If UPLO = 'U', the leading +*> N-by-N upper triangular part of A contains the upper +*> triangular part of the matrix A, and the strictly lower +*> triangular part of A is not referenced. If UPLO = 'L', the +*> leading N-by-N lower triangular part of A contains the lower +*> triangular part of the matrix A, and the strictly upper +*> triangular part of A is not referenced. +*> +*> On exit, if INFO = 0, the transformed matrix, stored in the +*> same format as A. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[in] B +*> \verbatim +*> B is DOUBLE PRECISION array, dimension (LDB,N) +*> The triangular factor from the Cholesky factorization of B, +*> as returned by DPOTRF. +*> \endverbatim +*> +*> \param[in] LDB +*> \verbatim +*> LDB is INTEGER +*> The leading dimension of the array B. LDB >= max(1,N). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup hegst +* +* ===================================================================== + SUBROUTINE DSYGST( ITYPE, UPLO, N, A, LDA, B, LDB, INFO ) +* +* -- LAPACK computational routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, ITYPE, LDA, LDB, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), B( LDB, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, HALF + PARAMETER ( ONE = 1.0D0, HALF = 0.5D0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER K, KB, NB +* .. +* .. External Subroutines .. + EXTERNAL DSYGS2, DSYMM, DSYR2K, DTRMM, DTRSM, + $ XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( ITYPE.LT.1 .OR. ITYPE.GT.3 ) THEN + INFO = -1 + ELSE IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -2 + ELSE IF( N.LT.0 ) THEN + INFO = -3 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -5 + ELSE IF( LDB.LT.MAX( 1, N ) ) THEN + INFO = -7 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DSYGST', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) + $ RETURN +* +* Determine the block size for this environment. +* + NB = ILAENV( 1, 'DSYGST', UPLO, N, -1, -1, -1 ) +* + IF( NB.LE.1 .OR. NB.GE.N ) THEN +* +* Use unblocked code +* + CALL DSYGS2( ITYPE, UPLO, N, A, LDA, B, LDB, INFO ) + ELSE +* +* Use blocked code +* + IF( ITYPE.EQ.1 ) THEN + IF( UPPER ) THEN +* +* Compute inv(U**T)*A*inv(U) +* + DO 10 K = 1, N, NB + KB = MIN( N-K+1, NB ) +* +* Update the upper triangle of A(k:n,k:n) +* + CALL DSYGS2( ITYPE, UPLO, KB, A( K, K ), LDA, + $ B( K, K ), LDB, INFO ) + IF( K+KB.LE.N ) THEN + CALL DTRSM( 'Left', UPLO, 'Transpose', + $ 'Non-unit', + $ KB, N-K-KB+1, ONE, B( K, K ), LDB, + $ A( K, K+KB ), LDA ) + CALL DSYMM( 'Left', UPLO, KB, N-K-KB+1, -HALF, + $ A( K, K ), LDA, B( K, K+KB ), LDB, ONE, + $ A( K, K+KB ), LDA ) + CALL DSYR2K( UPLO, 'Transpose', N-K-KB+1, KB, + $ -ONE, + $ A( K, K+KB ), LDA, B( K, K+KB ), LDB, + $ ONE, A( K+KB, K+KB ), LDA ) + CALL DSYMM( 'Left', UPLO, KB, N-K-KB+1, -HALF, + $ A( K, K ), LDA, B( K, K+KB ), LDB, ONE, + $ A( K, K+KB ), LDA ) + CALL DTRSM( 'Right', UPLO, 'No transpose', + $ 'Non-unit', KB, N-K-KB+1, ONE, + $ B( K+KB, K+KB ), LDB, A( K, K+KB ), + $ LDA ) + END IF + 10 CONTINUE + ELSE +* +* Compute inv(L)*A*inv(L**T) +* + DO 20 K = 1, N, NB + KB = MIN( N-K+1, NB ) +* +* Update the lower triangle of A(k:n,k:n) +* + CALL DSYGS2( ITYPE, UPLO, KB, A( K, K ), LDA, + $ B( K, K ), LDB, INFO ) + IF( K+KB.LE.N ) THEN + CALL DTRSM( 'Right', UPLO, 'Transpose', + $ 'Non-unit', + $ N-K-KB+1, KB, ONE, B( K, K ), LDB, + $ A( K+KB, K ), LDA ) + CALL DSYMM( 'Right', UPLO, N-K-KB+1, KB, -HALF, + $ A( K, K ), LDA, B( K+KB, K ), LDB, ONE, + $ A( K+KB, K ), LDA ) + CALL DSYR2K( UPLO, 'No transpose', N-K-KB+1, KB, + $ -ONE, A( K+KB, K ), LDA, B( K+KB, K ), + $ LDB, ONE, A( K+KB, K+KB ), LDA ) + CALL DSYMM( 'Right', UPLO, N-K-KB+1, KB, -HALF, + $ A( K, K ), LDA, B( K+KB, K ), LDB, ONE, + $ A( K+KB, K ), LDA ) + CALL DTRSM( 'Left', UPLO, 'No transpose', + $ 'Non-unit', N-K-KB+1, KB, ONE, + $ B( K+KB, K+KB ), LDB, A( K+KB, K ), + $ LDA ) + END IF + 20 CONTINUE + END IF + ELSE + IF( UPPER ) THEN +* +* Compute U*A*U**T +* + DO 30 K = 1, N, NB + KB = MIN( N-K+1, NB ) +* +* Update the upper triangle of A(1:k+kb-1,1:k+kb-1) +* + CALL DTRMM( 'Left', UPLO, 'No transpose', + $ 'Non-unit', + $ K-1, KB, ONE, B, LDB, A( 1, K ), LDA ) + CALL DSYMM( 'Right', UPLO, K-1, KB, HALF, A( K, + $ K ), + $ LDA, B( 1, K ), LDB, ONE, A( 1, K ), LDA ) + CALL DSYR2K( UPLO, 'No transpose', K-1, KB, ONE, + $ A( 1, K ), LDA, B( 1, K ), LDB, ONE, A, + $ LDA ) + CALL DSYMM( 'Right', UPLO, K-1, KB, HALF, A( K, + $ K ), + $ LDA, B( 1, K ), LDB, ONE, A( 1, K ), LDA ) + CALL DTRMM( 'Right', UPLO, 'Transpose', 'Non-unit', + $ K-1, KB, ONE, B( K, K ), LDB, A( 1, K ), + $ LDA ) + CALL DSYGS2( ITYPE, UPLO, KB, A( K, K ), LDA, + $ B( K, K ), LDB, INFO ) + 30 CONTINUE + ELSE +* +* Compute L**T*A*L +* + DO 40 K = 1, N, NB + KB = MIN( N-K+1, NB ) +* +* Update the lower triangle of A(1:k+kb-1,1:k+kb-1) +* + CALL DTRMM( 'Right', UPLO, 'No transpose', + $ 'Non-unit', + $ KB, K-1, ONE, B, LDB, A( K, 1 ), LDA ) + CALL DSYMM( 'Left', UPLO, KB, K-1, HALF, A( K, K ), + $ LDA, B( K, 1 ), LDB, ONE, A( K, 1 ), LDA ) + CALL DSYR2K( UPLO, 'Transpose', K-1, KB, ONE, + $ A( K, 1 ), LDA, B( K, 1 ), LDB, ONE, A, + $ LDA ) + CALL DSYMM( 'Left', UPLO, KB, K-1, HALF, A( K, K ), + $ LDA, B( K, 1 ), LDB, ONE, A( K, 1 ), LDA ) + CALL DTRMM( 'Left', UPLO, 'Transpose', 'Non-unit', + $ KB, + $ K-1, ONE, B( K, K ), LDB, A( K, 1 ), LDA ) + CALL DSYGS2( ITYPE, UPLO, KB, A( K, K ), LDA, + $ B( K, K ), LDB, INFO ) + 40 CONTINUE + END IF + END IF + END IF + RETURN +* +* End of DSYGST +* + END diff --git a/OTHER/LAPACK/dsygvx.f b/OTHER/LAPACK/dsygvx.f new file mode 100644 index 0000000000..3fa55b97c1 --- /dev/null +++ b/OTHER/LAPACK/dsygvx.f @@ -0,0 +1,462 @@ +*> \brief \b DSYGVX +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DSYGVX + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DSYGVX( ITYPE, JOBZ, RANGE, UPLO, N, A, LDA, B, LDB, +* VL, VU, IL, IU, ABSTOL, M, W, Z, LDZ, WORK, +* LWORK, IWORK, IFAIL, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER JOBZ, RANGE, UPLO +* INTEGER IL, INFO, ITYPE, IU, LDA, LDB, LDZ, LWORK, M, N +* DOUBLE PRECISION ABSTOL, VL, VU +* .. +* .. Array Arguments .. +* INTEGER IFAIL( * ), IWORK( * ) +* DOUBLE PRECISION A( LDA, * ), B( LDB, * ), W( * ), WORK( * ), +* $ Z( LDZ, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DSYGVX computes selected eigenvalues, and optionally, eigenvectors +*> of a real generalized symmetric-definite eigenproblem, of the form +*> A*x=(lambda)*B*x, A*Bx=(lambda)*x, or B*A*x=(lambda)*x. Here A +*> and B are assumed to be symmetric and B is also positive definite. +*> Eigenvalues and eigenvectors can be selected by specifying either a +*> range of values or a range of indices for the desired eigenvalues. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] ITYPE +*> \verbatim +*> ITYPE is INTEGER +*> Specifies the problem type to be solved: +*> = 1: A*x = (lambda)*B*x +*> = 2: A*B*x = (lambda)*x +*> = 3: B*A*x = (lambda)*x +*> \endverbatim +*> +*> \param[in] JOBZ +*> \verbatim +*> JOBZ is CHARACTER*1 +*> = 'N': Compute eigenvalues only; +*> = 'V': Compute eigenvalues and eigenvectors. +*> \endverbatim +*> +*> \param[in] RANGE +*> \verbatim +*> RANGE is CHARACTER*1 +*> = 'A': all eigenvalues will be found. +*> = 'V': all eigenvalues in the half-open interval (VL,VU] +*> will be found. +*> = 'I': the IL-th through IU-th eigenvalues will be found. +*> \endverbatim +*> +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> = 'U': Upper triangle of A and B are stored; +*> = 'L': Lower triangle of A and B are stored. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the matrix pencil (A,B). N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA, N) +*> On entry, the symmetric matrix A. If UPLO = 'U', the +*> leading N-by-N upper triangular part of A contains the +*> upper triangular part of the matrix A. If UPLO = 'L', +*> the leading N-by-N lower triangular part of A contains +*> the lower triangular part of the matrix A. +*> +*> On exit, the lower triangle (if UPLO='L') or the upper +*> triangle (if UPLO='U') of A, including the diagonal, is +*> destroyed. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[in,out] B +*> \verbatim +*> B is DOUBLE PRECISION array, dimension (LDB, N) +*> On entry, the symmetric matrix B. If UPLO = 'U', the +*> leading N-by-N upper triangular part of B contains the +*> upper triangular part of the matrix B. If UPLO = 'L', +*> the leading N-by-N lower triangular part of B contains +*> the lower triangular part of the matrix B. +*> +*> On exit, if INFO <= N, the part of B containing the matrix is +*> overwritten by the triangular factor U or L from the Cholesky +*> factorization B = U**T*U or B = L*L**T. +*> \endverbatim +*> +*> \param[in] LDB +*> \verbatim +*> LDB is INTEGER +*> The leading dimension of the array B. LDB >= max(1,N). +*> \endverbatim +*> +*> \param[in] VL +*> \verbatim +*> VL is DOUBLE PRECISION +*> If RANGE='V', the lower bound of the interval to +*> be searched for eigenvalues. VL < VU. +*> Not referenced if RANGE = 'A' or 'I'. +*> \endverbatim +*> +*> \param[in] VU +*> \verbatim +*> VU is DOUBLE PRECISION +*> If RANGE='V', the upper bound of the interval to +*> be searched for eigenvalues. VL < VU. +*> Not referenced if RANGE = 'A' or 'I'. +*> \endverbatim +*> +*> \param[in] IL +*> \verbatim +*> IL is INTEGER +*> If RANGE='I', the index of the +*> smallest eigenvalue to be returned. +*> 1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0. +*> Not referenced if RANGE = 'A' or 'V'. +*> \endverbatim +*> +*> \param[in] IU +*> \verbatim +*> IU is INTEGER +*> If RANGE='I', the index of the +*> largest eigenvalue to be returned. +*> 1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0. +*> Not referenced if RANGE = 'A' or 'V'. +*> \endverbatim +*> +*> \param[in] ABSTOL +*> \verbatim +*> ABSTOL is DOUBLE PRECISION +*> The absolute error tolerance for the eigenvalues. +*> An approximate eigenvalue is accepted as converged +*> when it is determined to lie in an interval [a,b] +*> of width less than or equal to +*> +*> ABSTOL + EPS * max( |a|,|b| ) , +*> +*> where EPS is the machine precision. If ABSTOL is less than +*> or equal to zero, then EPS*|T| will be used in its place, +*> where |T| is the 1-norm of the tridiagonal matrix obtained +*> by reducing C to tridiagonal form, where C is the symmetric +*> matrix of the standard symmetric problem to which the +*> generalized problem is transformed. +*> +*> Eigenvalues will be computed most accurately when ABSTOL is +*> set to twice the underflow threshold 2*DLAMCH('S'), not zero. +*> If this routine returns with INFO>0, indicating that some +*> eigenvectors did not converge, try setting ABSTOL to +*> 2*DLAMCH('S'). +*> \endverbatim +*> +*> \param[out] M +*> \verbatim +*> M is INTEGER +*> The total number of eigenvalues found. 0 <= M <= N. +*> If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1. +*> \endverbatim +*> +*> \param[out] W +*> \verbatim +*> W is DOUBLE PRECISION array, dimension (N) +*> On normal exit, the first M elements contain the selected +*> eigenvalues in ascending order. +*> \endverbatim +*> +*> \param[out] Z +*> \verbatim +*> Z is DOUBLE PRECISION array, dimension (LDZ, max(1,M)) +*> If JOBZ = 'N', then Z is not referenced. +*> If JOBZ = 'V', then if INFO = 0, the first M columns of Z +*> contain the orthonormal eigenvectors of the matrix A +*> corresponding to the selected eigenvalues, with the i-th +*> column of Z holding the eigenvector associated with W(i). +*> The eigenvectors are normalized as follows: +*> if ITYPE = 1 or 2, Z**T*B*Z = I; +*> if ITYPE = 3, Z**T*inv(B)*Z = I. +*> +*> If an eigenvector fails to converge, then that column of Z +*> contains the latest approximation to the eigenvector, and the +*> index of the eigenvector is returned in IFAIL. +*> Note: the user must ensure that at least max(1,M) columns are +*> supplied in the array Z; if RANGE = 'V', the exact value of M +*> is not known in advance and an upper bound must be used. +*> \endverbatim +*> +*> \param[in] LDZ +*> \verbatim +*> LDZ is INTEGER +*> The leading dimension of the array Z. LDZ >= 1, and if +*> JOBZ = 'V', LDZ >= max(1,N). +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)) +*> On exit, if INFO = 0, WORK(1) returns the optimal LWORK. +*> \endverbatim +*> +*> \param[in] LWORK +*> \verbatim +*> LWORK is INTEGER +*> The length of the array WORK. LWORK >= max(1,8*N). +*> For optimal efficiency, LWORK >= (NB+3)*N, +*> where NB is the blocksize for DSYTRD returned by ILAENV. +*> +*> If LWORK = -1, then a workspace query is assumed; the routine +*> only calculates the optimal size of the WORK array, returns +*> this value as the first entry of the WORK array, and no error +*> message related to LWORK is issued by XERBLA. +*> \endverbatim +*> +*> \param[out] IWORK +*> \verbatim +*> IWORK is INTEGER array, dimension (5*N) +*> \endverbatim +*> +*> \param[out] IFAIL +*> \verbatim +*> IFAIL is INTEGER array, dimension (N) +*> If JOBZ = 'V', then if INFO = 0, the first M elements of +*> IFAIL are zero. If INFO > 0, then IFAIL contains the +*> indices of the eigenvectors that failed to converge. +*> If JOBZ = 'N', then IFAIL is not referenced. +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument had an illegal value +*> > 0: DPOTRF or DSYEVX returned an error code: +*> <= N: if INFO = i, DSYEVX failed to converge; +*> i eigenvectors failed to converge. Their indices +*> are stored in array IFAIL. +*> > N: if INFO = N + i, for 1 <= i <= N, then the leading +*> minor of order i of B is not positive definite. +*> The factorization of B could not be completed and +*> no eigenvalues or eigenvectors were computed. +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup doubleSYeigen +* +*> \par Contributors: +* ================== +*> +*> Mark Fahey, Department of Mathematics, Univ. of Kentucky, USA +* +* ===================================================================== + SUBROUTINE DSYGVX( ITYPE, JOBZ, RANGE, UPLO, N, A, LDA, B, LDB, + $ VL, VU, IL, IU, ABSTOL, M, W, Z, LDZ, WORK, + $ LWORK, IWORK, IFAIL, INFO ) +* +* -- LAPACK driver routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER JOBZ, RANGE, UPLO + INTEGER IL, INFO, ITYPE, IU, LDA, LDB, LDZ, LWORK, M, N + DOUBLE PRECISION ABSTOL, VL, VU +* .. +* .. Array Arguments .. + INTEGER IFAIL( * ), IWORK( * ) + DOUBLE PRECISION A( LDA, * ), B( LDB, * ), W( * ), WORK( * ), + $ Z( LDZ, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE + PARAMETER ( ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL ALLEIG, INDEIG, LQUERY, UPPER, VALEIG, WANTZ + CHARACTER TRANS + INTEGER LWKMIN, LWKOPT, NB +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. External Subroutines .. + EXTERNAL DPOTRF, DSYEVX, DSYGST, DTRMM, DTRSM, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN +* .. +* .. Executable Statements .. +* +* Test the input parameters. +* + UPPER = LSAME( UPLO, 'U' ) + WANTZ = LSAME( JOBZ, 'V' ) + ALLEIG = LSAME( RANGE, 'A' ) + VALEIG = LSAME( RANGE, 'V' ) + INDEIG = LSAME( RANGE, 'I' ) + LQUERY = ( LWORK.EQ.-1 ) +* + INFO = 0 + IF( ITYPE.LT.1 .OR. ITYPE.GT.3 ) THEN + INFO = -1 + ELSE IF( .NOT.( WANTZ .OR. LSAME( JOBZ, 'N' ) ) ) THEN + INFO = -2 + ELSE IF( .NOT.( ALLEIG .OR. VALEIG .OR. INDEIG ) ) THEN + INFO = -3 + ELSE IF( .NOT.( UPPER .OR. LSAME( UPLO, 'L' ) ) ) THEN + INFO = -4 + ELSE IF( N.LT.0 ) THEN + INFO = -5 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -7 + ELSE IF( LDB.LT.MAX( 1, N ) ) THEN + INFO = -9 + ELSE + IF( VALEIG ) THEN + IF( N.GT.0 .AND. VU.LE.VL ) + $ INFO = -11 + ELSE IF( INDEIG ) THEN + IF( IL.LT.1 .OR. IL.GT.MAX( 1, N ) ) THEN + INFO = -12 + ELSE IF( IU.LT.MIN( N, IL ) .OR. IU.GT.N ) THEN + INFO = -13 + END IF + END IF + END IF + IF (INFO.EQ.0) THEN + IF (LDZ.LT.1 .OR. (WANTZ .AND. LDZ.LT.N)) THEN + INFO = -18 + END IF + END IF +* + IF( INFO.EQ.0 ) THEN + LWKMIN = MAX( 1, 8*N ) + NB = ILAENV( 1, 'DSYTRD', UPLO, N, -1, -1, -1 ) + LWKOPT = MAX( LWKMIN, ( NB + 3 )*N ) + WORK( 1 ) = LWKOPT +* + IF( LWORK.LT.LWKMIN .AND. .NOT.LQUERY ) THEN + INFO = -20 + END IF + END IF +* + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DSYGVX', -INFO ) + RETURN + ELSE IF( LQUERY ) THEN + RETURN + END IF +* +* Quick return if possible +* + M = 0 + IF( N.EQ.0 ) THEN + RETURN + END IF +* +* Form a Cholesky factorization of B. +* + CALL DPOTRF( UPLO, N, B, LDB, INFO ) + IF( INFO.NE.0 ) THEN + INFO = N + INFO + RETURN + END IF +* +* Transform problem to standard eigenvalue problem and solve. +* + CALL DSYGST( ITYPE, UPLO, N, A, LDA, B, LDB, INFO ) + CALL DSYEVX( JOBZ, RANGE, UPLO, N, A, LDA, VL, VU, IL, IU, ABSTOL, + $ M, W, Z, LDZ, WORK, LWORK, IWORK, IFAIL, INFO ) +* + IF( WANTZ ) THEN +* +* Backtransform eigenvectors to the original problem. +* + IF( INFO.GT.0 ) + $ M = INFO - 1 + IF( ITYPE.EQ.1 .OR. ITYPE.EQ.2 ) THEN +* +* For A*x=(lambda)*B*x and A*B*x=(lambda)*x; +* backtransform eigenvectors: x = inv(L)**T*y or inv(U)*y +* + IF( UPPER ) THEN + TRANS = 'N' + ELSE + TRANS = 'T' + END IF +* + CALL DTRSM( 'Left', UPLO, TRANS, 'Non-unit', N, M, ONE, B, + $ LDB, Z, LDZ ) +* + ELSE IF( ITYPE.EQ.3 ) THEN +* +* For B*A*x=(lambda)*x; +* backtransform eigenvectors: x = L*y or U**T*y +* + IF( UPPER ) THEN + TRANS = 'T' + ELSE + TRANS = 'N' + END IF +* + CALL DTRMM( 'Left', UPLO, TRANS, 'Non-unit', N, M, ONE, B, + $ LDB, Z, LDZ ) + END IF + END IF +* +* Set WORK(1) to optimal workspace size. +* + WORK( 1 ) = LWKOPT +* + RETURN +* +* End of DSYGVX +* + END diff --git a/OTHER/LAPACK/dsytd2.f b/OTHER/LAPACK/dsytd2.f new file mode 100644 index 0000000000..e948496a12 --- /dev/null +++ b/OTHER/LAPACK/dsytd2.f @@ -0,0 +1,323 @@ +*> \brief \b DSYTD2 reduces a symmetric matrix to real symmetric tridiagonal form by an orthogonal similarity transformation (unblocked algorithm). +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DSYTD2 + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DSYTD2( UPLO, N, A, LDA, D, E, TAU, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), D( * ), E( * ), TAU( * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DSYTD2 reduces a real symmetric matrix A to symmetric tridiagonal +*> form T by an orthogonal similarity transformation: Q**T * A * Q = T. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> Specifies whether the upper or lower triangular part of the +*> symmetric matrix A is stored: +*> = 'U': Upper triangular +*> = 'L': Lower triangular +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the matrix A. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> On entry, the symmetric matrix A. If UPLO = 'U', the leading +*> n-by-n upper triangular part of A contains the upper +*> triangular part of the matrix A, and the strictly lower +*> triangular part of A is not referenced. If UPLO = 'L', the +*> leading n-by-n lower triangular part of A contains the lower +*> triangular part of the matrix A, and the strictly upper +*> triangular part of A is not referenced. +*> On exit, if UPLO = 'U', the diagonal and first superdiagonal +*> of A are overwritten by the corresponding elements of the +*> tridiagonal matrix T, and the elements above the first +*> superdiagonal, with the array TAU, represent the orthogonal +*> matrix Q as a product of elementary reflectors; if UPLO +*> = 'L', the diagonal and first subdiagonal of A are over- +*> written by the corresponding elements of the tridiagonal +*> matrix T, and the elements below the first subdiagonal, with +*> the array TAU, represent the orthogonal matrix Q as a product +*> of elementary reflectors. See Further Details. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[out] D +*> \verbatim +*> D is DOUBLE PRECISION array, dimension (N) +*> The diagonal elements of the tridiagonal matrix T: +*> D(i) = A(i,i). +*> \endverbatim +*> +*> \param[out] E +*> \verbatim +*> E is DOUBLE PRECISION array, dimension (N-1) +*> The off-diagonal elements of the tridiagonal matrix T: +*> E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'. +*> \endverbatim +*> +*> \param[out] TAU +*> \verbatim +*> TAU is DOUBLE PRECISION array, dimension (N-1) +*> The scalar factors of the elementary reflectors (see Further +*> Details). +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument had an illegal value. +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup hetd2 +* +*> \par Further Details: +* ===================== +*> +*> \verbatim +*> +*> If UPLO = 'U', the matrix Q is represented as a product of elementary +*> reflectors +*> +*> Q = H(n-1) . . . H(2) H(1). +*> +*> Each H(i) has the form +*> +*> H(i) = I - tau * v * v**T +*> +*> where tau is a real scalar, and v is a real vector with +*> v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in +*> A(1:i-1,i+1), and tau in TAU(i). +*> +*> If UPLO = 'L', the matrix Q is represented as a product of elementary +*> reflectors +*> +*> Q = H(1) H(2) . . . H(n-1). +*> +*> Each H(i) has the form +*> +*> H(i) = I - tau * v * v**T +*> +*> where tau is a real scalar, and v is a real vector with +*> v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i), +*> and tau in TAU(i). +*> +*> The contents of A on exit are illustrated by the following examples +*> with n = 5: +*> +*> if UPLO = 'U': if UPLO = 'L': +*> +*> ( d e v2 v3 v4 ) ( d ) +*> ( d e v3 v4 ) ( e d ) +*> ( d e v4 ) ( v1 e d ) +*> ( d e ) ( v1 v2 e d ) +*> ( d ) ( v1 v2 v3 e d ) +*> +*> where d and e denote diagonal and off-diagonal elements of T, and vi +*> denotes an element of the vector defining H(i). +*> \endverbatim +*> +* ===================================================================== + SUBROUTINE DSYTD2( UPLO, N, A, LDA, D, E, TAU, INFO ) +* +* -- LAPACK computational routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), D( * ), E( * ), TAU( * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE, ZERO, HALF + PARAMETER ( ONE = 1.0D0, ZERO = 0.0D0, + $ HALF = 1.0D0 / 2.0D0 ) +* .. +* .. Local Scalars .. + LOGICAL UPPER + INTEGER I + DOUBLE PRECISION ALPHA, TAUI +* .. +* .. External Subroutines .. + EXTERNAL DAXPY, DLARFG, DSYMV, DSYR2, XERBLA +* .. +* .. External Functions .. + LOGICAL LSAME + DOUBLE PRECISION DDOT + EXTERNAL LSAME, DDOT +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX, MIN +* .. +* .. Executable Statements .. +* +* Test the input parameters +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + END IF + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DSYTD2', -INFO ) + RETURN + END IF +* +* Quick return if possible +* + IF( N.LE.0 ) + $ RETURN +* + IF( UPPER ) THEN +* +* Reduce the upper triangle of A +* + DO 10 I = N - 1, 1, -1 +* +* Generate elementary reflector H(i) = I - tau * v * v**T +* to annihilate A(1:i-1,i+1) +* + CALL DLARFG( I, A( I, I+1 ), A( 1, I+1 ), 1, TAUI ) + E( I ) = A( I, I+1 ) +* + IF( TAUI.NE.ZERO ) THEN +* +* Apply H(i) from both sides to A(1:i,1:i) +* + A( I, I+1 ) = ONE +* +* Compute x := tau * A * v storing x in TAU(1:i) +* + CALL DSYMV( UPLO, I, TAUI, A, LDA, A( 1, I+1 ), 1, + $ ZERO, + $ TAU, 1 ) +* +* Compute w := x - 1/2 * tau * (x**T * v) * v +* + ALPHA = -HALF*TAUI*DDOT( I, TAU, 1, A( 1, I+1 ), 1 ) + CALL DAXPY( I, ALPHA, A( 1, I+1 ), 1, TAU, 1 ) +* +* Apply the transformation as a rank-2 update: +* A := A - v * w**T - w * v**T +* + CALL DSYR2( UPLO, I, -ONE, A( 1, I+1 ), 1, TAU, 1, A, + $ LDA ) +* + A( I, I+1 ) = E( I ) + END IF + D( I+1 ) = A( I+1, I+1 ) + TAU( I ) = TAUI + 10 CONTINUE + D( 1 ) = A( 1, 1 ) + ELSE +* +* Reduce the lower triangle of A +* + DO 20 I = 1, N - 1 +* +* Generate elementary reflector H(i) = I - tau * v * v**T +* to annihilate A(i+2:n,i) +* + CALL DLARFG( N-I, A( I+1, I ), A( MIN( I+2, N ), I ), 1, + $ TAUI ) + E( I ) = A( I+1, I ) +* + IF( TAUI.NE.ZERO ) THEN +* +* Apply H(i) from both sides to A(i+1:n,i+1:n) +* + A( I+1, I ) = ONE +* +* Compute x := tau * A * v storing y in TAU(i:n-1) +* + CALL DSYMV( UPLO, N-I, TAUI, A( I+1, I+1 ), LDA, + $ A( I+1, I ), 1, ZERO, TAU( I ), 1 ) +* +* Compute w := x - 1/2 * tau * (x**T * v) * v +* + ALPHA = -HALF*TAUI*DDOT( N-I, TAU( I ), 1, A( I+1, + $ I ), + $ 1 ) + CALL DAXPY( N-I, ALPHA, A( I+1, I ), 1, TAU( I ), 1 ) +* +* Apply the transformation as a rank-2 update: +* A := A - v * w**T - w * v**T +* + CALL DSYR2( UPLO, N-I, -ONE, A( I+1, I ), 1, TAU( I ), + $ 1, + $ A( I+1, I+1 ), LDA ) +* + A( I+1, I ) = E( I ) + END IF + D( I ) = A( I, I ) + TAU( I ) = TAUI + 20 CONTINUE + D( N ) = A( N, N ) + END IF +* + RETURN +* +* End of DSYTD2 +* + END diff --git a/OTHER/LAPACK/dsytrd.f b/OTHER/LAPACK/dsytrd.f new file mode 100644 index 0000000000..2b56de494b --- /dev/null +++ b/OTHER/LAPACK/dsytrd.f @@ -0,0 +1,375 @@ +*> \brief \b DSYTRD +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download DSYTRD + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* SUBROUTINE DSYTRD( UPLO, N, A, LDA, D, E, TAU, WORK, LWORK, INFO ) +* +* .. Scalar Arguments .. +* CHARACTER UPLO +* INTEGER INFO, LDA, LWORK, N +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ), D( * ), E( * ), TAU( * ), +* $ WORK( * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> DSYTRD reduces a real symmetric matrix A to real symmetric +*> tridiagonal form T by an orthogonal similarity transformation: +*> Q**T * A * Q = T. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] UPLO +*> \verbatim +*> UPLO is CHARACTER*1 +*> = 'U': Upper triangle of A is stored; +*> = 'L': Lower triangle of A is stored. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The order of the matrix A. N >= 0. +*> \endverbatim +*> +*> \param[in,out] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> On entry, the symmetric matrix A. If UPLO = 'U', the leading +*> N-by-N upper triangular part of A contains the upper +*> triangular part of the matrix A, and the strictly lower +*> triangular part of A is not referenced. If UPLO = 'L', the +*> leading N-by-N lower triangular part of A contains the lower +*> triangular part of the matrix A, and the strictly upper +*> triangular part of A is not referenced. +*> On exit, if UPLO = 'U', the diagonal and first superdiagonal +*> of A are overwritten by the corresponding elements of the +*> tridiagonal matrix T, and the elements above the first +*> superdiagonal, with the array TAU, represent the orthogonal +*> matrix Q as a product of elementary reflectors; if UPLO +*> = 'L', the diagonal and first subdiagonal of A are over- +*> written by the corresponding elements of the tridiagonal +*> matrix T, and the elements below the first subdiagonal, with +*> the array TAU, represent the orthogonal matrix Q as a product +*> of elementary reflectors. See Further Details. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,N). +*> \endverbatim +*> +*> \param[out] D +*> \verbatim +*> D is DOUBLE PRECISION array, dimension (N) +*> The diagonal elements of the tridiagonal matrix T: +*> D(i) = A(i,i). +*> \endverbatim +*> +*> \param[out] E +*> \verbatim +*> E is DOUBLE PRECISION array, dimension (N-1) +*> The off-diagonal elements of the tridiagonal matrix T: +*> E(i) = A(i,i+1) if UPLO = 'U', E(i) = A(i+1,i) if UPLO = 'L'. +*> \endverbatim +*> +*> \param[out] TAU +*> \verbatim +*> TAU is DOUBLE PRECISION array, dimension (N-1) +*> The scalar factors of the elementary reflectors (see Further +*> Details). +*> \endverbatim +*> +*> \param[out] WORK +*> \verbatim +*> WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)) +*> On exit, if INFO = 0, WORK(1) returns the optimal LWORK. +*> \endverbatim +*> +*> \param[in] LWORK +*> \verbatim +*> LWORK is INTEGER +*> The dimension of the array WORK. LWORK >= 1. +*> For optimum performance LWORK >= N*NB, where NB is the +*> optimal blocksize. +*> +*> If LWORK = -1, then a workspace query is assumed; the routine +*> only calculates the optimal size of the WORK array, returns +*> this value as the first entry of the WORK array, and no error +*> message related to LWORK is issued by XERBLA. +*> \endverbatim +*> +*> \param[out] INFO +*> \verbatim +*> INFO is INTEGER +*> = 0: successful exit +*> < 0: if INFO = -i, the i-th argument had an illegal value +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup hetrd +* +*> \par Further Details: +* ===================== +*> +*> \verbatim +*> +*> If UPLO = 'U', the matrix Q is represented as a product of elementary +*> reflectors +*> +*> Q = H(n-1) . . . H(2) H(1). +*> +*> Each H(i) has the form +*> +*> H(i) = I - tau * v * v**T +*> +*> where tau is a real scalar, and v is a real vector with +*> v(i+1:n) = 0 and v(i) = 1; v(1:i-1) is stored on exit in +*> A(1:i-1,i+1), and tau in TAU(i). +*> +*> If UPLO = 'L', the matrix Q is represented as a product of elementary +*> reflectors +*> +*> Q = H(1) H(2) . . . H(n-1). +*> +*> Each H(i) has the form +*> +*> H(i) = I - tau * v * v**T +*> +*> where tau is a real scalar, and v is a real vector with +*> v(1:i) = 0 and v(i+1) = 1; v(i+2:n) is stored on exit in A(i+2:n,i), +*> and tau in TAU(i). +*> +*> The contents of A on exit are illustrated by the following examples +*> with n = 5: +*> +*> if UPLO = 'U': if UPLO = 'L': +*> +*> ( d e v2 v3 v4 ) ( d ) +*> ( d e v3 v4 ) ( e d ) +*> ( d e v4 ) ( v1 e d ) +*> ( d e ) ( v1 v2 e d ) +*> ( d ) ( v1 v2 v3 e d ) +*> +*> where d and e denote diagonal and off-diagonal elements of T, and vi +*> denotes an element of the vector defining H(i). +*> \endverbatim +*> +* ===================================================================== + SUBROUTINE DSYTRD( UPLO, N, A, LDA, D, E, TAU, WORK, LWORK, + $ INFO ) +* +* -- LAPACK computational routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + CHARACTER UPLO + INTEGER INFO, LDA, LWORK, N +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ), D( * ), E( * ), TAU( * ), + $ WORK( * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ONE + PARAMETER ( ONE = 1.0D+0 ) +* .. +* .. Local Scalars .. + LOGICAL LQUERY, UPPER + INTEGER I, IINFO, IWS, J, KK, LDWORK, LWKOPT, NB, + $ NBMIN, NX +* .. +* .. External Subroutines .. + EXTERNAL DLATRD, DSYR2K, DSYTD2, XERBLA +* .. +* .. Intrinsic Functions .. + INTRINSIC MAX +* .. +* .. External Functions .. + LOGICAL LSAME + INTEGER ILAENV + EXTERNAL LSAME, ILAENV +* .. +* .. Executable Statements .. +* +* Test the input parameters +* + INFO = 0 + UPPER = LSAME( UPLO, 'U' ) + LQUERY = ( LWORK.EQ.-1 ) + IF( .NOT.UPPER .AND. .NOT.LSAME( UPLO, 'L' ) ) THEN + INFO = -1 + ELSE IF( N.LT.0 ) THEN + INFO = -2 + ELSE IF( LDA.LT.MAX( 1, N ) ) THEN + INFO = -4 + ELSE IF( LWORK.LT.1 .AND. .NOT.LQUERY ) THEN + INFO = -9 + END IF +* + IF( INFO.EQ.0 ) THEN +* +* Determine the block size. +* + NB = ILAENV( 1, 'DSYTRD', UPLO, N, -1, -1, -1 ) + LWKOPT = MAX( 1, N*NB ) + WORK( 1 ) = LWKOPT + END IF +* + IF( INFO.NE.0 ) THEN + CALL XERBLA( 'DSYTRD', -INFO ) + RETURN + ELSE IF( LQUERY ) THEN + RETURN + END IF +* +* Quick return if possible +* + IF( N.EQ.0 ) THEN + WORK( 1 ) = 1 + RETURN + END IF +* + NX = N + IWS = 1 + IF( NB.GT.1 .AND. NB.LT.N ) THEN +* +* Determine when to cross over from blocked to unblocked code +* (last block is always handled by unblocked code). +* + NX = MAX( NB, ILAENV( 3, 'DSYTRD', UPLO, N, -1, -1, -1 ) ) + IF( NX.LT.N ) THEN +* +* Determine if workspace is large enough for blocked code. +* + LDWORK = N + IWS = LDWORK*NB + IF( LWORK.LT.IWS ) THEN +* +* Not enough workspace to use optimal NB: determine the +* minimum value of NB, and reduce NB or force use of +* unblocked code by setting NX = N. +* + NB = MAX( LWORK / LDWORK, 1 ) + NBMIN = ILAENV( 2, 'DSYTRD', UPLO, N, -1, -1, -1 ) + IF( NB.LT.NBMIN ) + $ NX = N + END IF + ELSE + NX = N + END IF + ELSE + NB = 1 + END IF +* + IF( UPPER ) THEN +* +* Reduce the upper triangle of A. +* Columns 1:kk are handled by the unblocked method. +* + KK = N - ( ( N-NX+NB-1 ) / NB )*NB + DO 20 I = N - NB + 1, KK + 1, -NB +* +* Reduce columns i:i+nb-1 to tridiagonal form and form the +* matrix W which is needed to update the unreduced part of +* the matrix +* + CALL DLATRD( UPLO, I+NB-1, NB, A, LDA, E, TAU, WORK, + $ LDWORK ) +* +* Update the unreduced submatrix A(1:i-1,1:i-1), using an +* update of the form: A := A - V*W**T - W*V**T +* + CALL DSYR2K( UPLO, 'No transpose', I-1, NB, -ONE, A( 1, + $ I ), + $ LDA, WORK, LDWORK, ONE, A, LDA ) +* +* Copy superdiagonal elements back into A, and diagonal +* elements into D +* + DO 10 J = I, I + NB - 1 + A( J-1, J ) = E( J-1 ) + D( J ) = A( J, J ) + 10 CONTINUE + 20 CONTINUE +* +* Use unblocked code to reduce the last or only block +* + CALL DSYTD2( UPLO, KK, A, LDA, D, E, TAU, IINFO ) + ELSE +* +* Reduce the lower triangle of A +* + DO 40 I = 1, N - NX, NB +* +* Reduce columns i:i+nb-1 to tridiagonal form and form the +* matrix W which is needed to update the unreduced part of +* the matrix +* + CALL DLATRD( UPLO, N-I+1, NB, A( I, I ), LDA, E( I ), + $ TAU( I ), WORK, LDWORK ) +* +* Update the unreduced submatrix A(i+ib:n,i+ib:n), using +* an update of the form: A := A - V*W**T - W*V**T +* + CALL DSYR2K( UPLO, 'No transpose', N-I-NB+1, NB, -ONE, + $ A( I+NB, I ), LDA, WORK( NB+1 ), LDWORK, ONE, + $ A( I+NB, I+NB ), LDA ) +* +* Copy subdiagonal elements back into A, and diagonal +* elements into D +* + DO 30 J = I, I + NB - 1 + A( J+1, J ) = E( J ) + D( J ) = A( J, J ) + 30 CONTINUE + 40 CONTINUE +* +* Use unblocked code to reduce the last or only block +* + CALL DSYTD2( UPLO, N-I+1, A( I, I ), LDA, D( I ), E( I ), + $ TAU( I ), IINFO ) + END IF +* + WORK( 1 ) = LWKOPT + RETURN +* +* End of DSYTRD +* + END diff --git a/OTHER/LAPACK/iladlc.f b/OTHER/LAPACK/iladlc.f new file mode 100644 index 0000000000..c5ef963c4b --- /dev/null +++ b/OTHER/LAPACK/iladlc.f @@ -0,0 +1,115 @@ +*> \brief \b ILADLC scans a matrix for its last non-zero column. +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download ILADLC + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* INTEGER FUNCTION ILADLC( M, N, A, LDA ) +* +* .. Scalar Arguments .. +* INTEGER M, N, LDA +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> ILADLC scans A for its last non-zero column. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] M +*> \verbatim +*> M is INTEGER +*> The number of rows of the matrix A. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The number of columns of the matrix A. +*> \endverbatim +*> +*> \param[in] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> The m by n matrix A. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,M). +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup ilalc +* +* ===================================================================== + INTEGER FUNCTION ILADLC( M, N, A, LDA ) +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + INTEGER M, N, LDA +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ZERO + PARAMETER ( ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + INTEGER I +* .. +* .. Executable Statements .. +* +* Quick test for the common case where one corner is non-zero. + IF( N.EQ.0 ) THEN + ILADLC = N + ELSE IF( A(1, N).NE.ZERO .OR. A(M, N).NE.ZERO ) THEN + ILADLC = N + ELSE +* Now scan each column from the end, returning with the first non-zero. + DO ILADLC = N, 1, -1 + DO I = 1, M + IF( A(I, ILADLC).NE.ZERO ) RETURN + END DO + END DO + END IF + RETURN + END diff --git a/OTHER/LAPACK/iladlr.f b/OTHER/LAPACK/iladlr.f new file mode 100644 index 0000000000..900df1c1a7 --- /dev/null +++ b/OTHER/LAPACK/iladlr.f @@ -0,0 +1,118 @@ +*> \brief \b ILADLR scans a matrix for its last non-zero row. +* +* =========== DOCUMENTATION =========== +* +* Online html documentation available at +* http://www.netlib.org/lapack/explore-html/ +* +*> \htmlonly +*> Download ILADLR + dependencies +*> +*> [TGZ] +*> +*> [ZIP] +*> +*> [TXT] +*> \endhtmlonly +* +* Definition: +* =========== +* +* INTEGER FUNCTION ILADLR( M, N, A, LDA ) +* +* .. Scalar Arguments .. +* INTEGER M, N, LDA +* .. +* .. Array Arguments .. +* DOUBLE PRECISION A( LDA, * ) +* .. +* +* +*> \par Purpose: +* ============= +*> +*> \verbatim +*> +*> ILADLR scans A for its last non-zero row. +*> \endverbatim +* +* Arguments: +* ========== +* +*> \param[in] M +*> \verbatim +*> M is INTEGER +*> The number of rows of the matrix A. +*> \endverbatim +*> +*> \param[in] N +*> \verbatim +*> N is INTEGER +*> The number of columns of the matrix A. +*> \endverbatim +*> +*> \param[in] A +*> \verbatim +*> A is DOUBLE PRECISION array, dimension (LDA,N) +*> The m by n matrix A. +*> \endverbatim +*> +*> \param[in] LDA +*> \verbatim +*> LDA is INTEGER +*> The leading dimension of the array A. LDA >= max(1,M). +*> \endverbatim +* +* Authors: +* ======== +* +*> \author Univ. of Tennessee +*> \author Univ. of California Berkeley +*> \author Univ. of Colorado Denver +*> \author NAG Ltd. +* +*> \ingroup ilalr +* +* ===================================================================== + INTEGER FUNCTION ILADLR( M, N, A, LDA ) +* +* -- LAPACK auxiliary routine -- +* -- LAPACK is a software package provided by Univ. of Tennessee, -- +* -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- +* +* .. Scalar Arguments .. + INTEGER M, N, LDA +* .. +* .. Array Arguments .. + DOUBLE PRECISION A( LDA, * ) +* .. +* +* ===================================================================== +* +* .. Parameters .. + DOUBLE PRECISION ZERO + PARAMETER ( ZERO = 0.0D+0 ) +* .. +* .. Local Scalars .. + INTEGER I, J +* .. +* .. Executable Statements .. +* +* Quick test for the common case where one corner is non-zero. + IF( M.EQ.0 ) THEN + ILADLR = M + ELSE IF( A(M, 1).NE.ZERO .OR. A(M, N).NE.ZERO ) THEN + ILADLR = M + ELSE +* Scan up each column tracking the last zero row seen. + ILADLR = 0 + DO J = 1, N + I=M + DO WHILE((A(MAX(I,1),J).EQ.ZERO).AND.(I.GE.1)) + I=I-1 + ENDDO + ILADLR = MAX( ILADLR, I ) + END DO + END IF + RETURN + END diff --git a/SRC/Makefile b/SRC/Makefile index fee49cb0dc..173931f25b 100644 --- a/SRC/Makefile +++ b/SRC/Makefile @@ -432,7 +432,7 @@ RECORDER_LIBS = $(FE)/recorder/Recorder.o \ $(FE)/recorder/ElementRecorderRMS.o \ $(FE)/recorder/NodeRecorderRMS.o \ $(FE)/recorder/MPCORecorder.o \ - $(FE)/recorder/VTK_Recorder.o + $(FE)/recorder/VTK_Recorder.o DATABASE_LIBS = $(FE)/database/FileDatastore.o \ @@ -683,6 +683,7 @@ ELE_LIBS = $(FE)/element/Element.o \ $(FE)/element/UWelements/Tcl_generateInterfacePoints.o \ $(FE)/element/PML/pml_3d.o \ $(FE)/element/PML/PML3D.o \ + $(FE)/element/PML/PML3DVISCOUS.o \ $(FE)/element/PML/pml_2d.o \ $(FE)/element/PML/PML2D.o \ $(FE)/element/PML/PML2D_3.o \ @@ -775,6 +776,7 @@ MATERIAL_LIBS = $(FE)/material/Material.o \ $(FE)/material/uniaxial/Neoprene.o \ $(FE)/material/uniaxial/ASD_SMA_3K.o \ $(FE)/material/uniaxial/ASDConcrete1DMaterial.o \ + $(FE)/material/uniaxial/ASDSteel1DMaterial.o \ $(FE)/material/uniaxial/Concrete01.o \ $(FE)/material/uniaxial/Concrete02.o \ $(FE)/material/uniaxial/Concrete02IS.o \ @@ -886,6 +888,7 @@ MATERIAL_LIBS = $(FE)/material/Material.o \ $(FE)/material/uniaxial/TDConcreteMC10.o \ $(FE)/material/uniaxial/TDConcreteMC10NL.o \ $(FE)/material/uniaxial/CreepMaterial.o \ + $(FE)/material/uniaxial/CreepShrinkageACI209.o \ $(FE)/material/uniaxial/DegradingPinchedBW.o \ $(FE)/material/uniaxial/HystereticPoly.o \ $(FE)/material/uniaxial/HystereticSmooth.o \ @@ -971,6 +974,7 @@ MATERIAL_LIBS = $(FE)/material/Material.o \ $(FE)/material/nD/PlasticDamageConcretePlaneStress.o \ $(FE)/element/PML/pml_3d.o \ $(FE)/element/PML/PML3D.o \ + $(FE)/element/PML/PML3DVISCOUS.o \ $(FE)/element/PML/pml_2d.o \ $(FE)/element/PML/PML2D.o \ $(FE)/element/PML/PML2D_3.o \ @@ -1004,6 +1008,7 @@ MATERIAL_LIBS = $(FE)/material/Material.o \ $(FE)/material/nD/UWmaterials/J2CyclicBoundingSurfacePlaneStrain.o \ $(FE)/material/nD/UWmaterials/PM4Sand.o \ $(FE)/material/nD/UWmaterials/PM4Silt.o \ + $(FE)/material/nD/UWmaterials/LinearElasticGGmax.o \ $(FE)/material/nD/UANDESmaterials/SAniSandMS.o \ $(FE)/material/nD/UANDESmaterials/SAniSandMS3D.o \ $(FE)/material/nD/UANDESmaterials/SAniSandMSPlaneStrain.o \ @@ -1265,7 +1270,9 @@ SequentialSysOfEqn_LIBS = $(FE)/system_of_eqn/linearSOE/LinearSOE.o \ $(FE)/system_of_eqn/linearSOE/umfGEN/UmfpackGenLinSOE.o \ $(FE)/system_of_eqn/linearSOE/umfGEN/UmfpackGenLinSolver.o \ $(FE)/system_of_eqn/eigenSOE/FullGenEigenSOE.o \ - $(FE)/system_of_eqn/eigenSOE/FullGenEigenSolver.o + $(FE)/system_of_eqn/eigenSOE/FullGenEigenSolver.o \ + $(FE)/system_of_eqn/eigenSOE/SymmGeneralizedEigenSOE.o \ + $(FE)/system_of_eqn/eigenSOE/SymmGeneralizedEigenSolver.o ifeq ($(PROGRAMMING_MODE), PARALLEL_INTERPRETERS) SysOfEqn_LIBS = $(SequentialSysOfEqn_LIBS) \ @@ -1323,6 +1330,7 @@ DOMAIN_LIBS = $(FE)/domain/component/DomainComponent.o \ $(FE)/domain/load/Beam2dPointLoad.o \ $(FE)/domain/load/Beam2dTempLoad.o \ $(FE)/domain/load/Beam2dThermalAction.o \ + $(FE)/domain/load/BeamUniformMoment.o \ $(FE)/domain/load/NodalThermalAction.o \ $(FE)/domain/load/ThermalActionWrapper.o \ $(FE)/domain/load/Beam3dThermalAction.o \ diff --git a/SRC/OPS_Globals.h b/SRC/OPS_Globals.h index 916a67046c..194c5a2ebb 100644 --- a/SRC/OPS_Globals.h +++ b/SRC/OPS_Globals.h @@ -27,7 +27,7 @@ // Description: This file contains global variables used in OpenSees files. // if you change some of the variables, you must recompile ALL the code. -#define OPS_VERSION "3.7.1" +#define OPS_VERSION "3.7.2" #ifdef _WIN32 #ifndef _WIN64 diff --git a/SRC/actor/objectBroker/FEM_ObjectBrokerAllClasses.cpp b/SRC/actor/objectBroker/FEM_ObjectBrokerAllClasses.cpp index 3f68d3b046..8ce18bc3af 100644 --- a/SRC/actor/objectBroker/FEM_ObjectBrokerAllClasses.cpp +++ b/SRC/actor/objectBroker/FEM_ObjectBrokerAllClasses.cpp @@ -74,6 +74,7 @@ #include "TensionOnlyMaterial.h" #include "ASD_SMA_3K.h" #include "ASDConcrete1DMaterial.h" +#include "ASDSteel1DMaterial.h" #include "Concrete01.h" #include "Concrete01WithSITC.h" #include "Concrete02.h" @@ -296,6 +297,7 @@ #include "J2CyclicBoundingSurface.h" #include "J2CyclicBoundingSurface3D.h" #include "J2CyclicBoundingSurfacePlaneStrain.h" +#include "UWmaterials/LinearElasticGGmax.h" #include "UWmaterials/InitialStateAnalysisWrapper.h" #include "stressDensityModel/stressDensity.h" #include "InitStressNDMaterial.h" @@ -420,6 +422,7 @@ #include "PML/PML2D_5.h" #include "PML/PML2D_12.h" #include "PML/PML2DVISCOUS.h" +#include "PML/PML3DVISCOUS.h" #include "UP-ucsd/Nine_Four_Node_QuadUP.h" @@ -560,6 +563,7 @@ #include "DriftRecorder.h" #ifdef _HDF5 #include "MPCORecorder.h" +#include "VTKHDF_Recorder.h" #endif // _HDF5 #include "VTK_Recorder.h" #include "GmshRecorder.h" @@ -586,6 +590,7 @@ #include "Beam2dPointLoad.h" #include "Beam3dUniformLoad.h" #include "Beam3dPointLoad.h" +#include "BeamUniformMoment.h" #include "BrickSelfWeight.h" #include "SelfWeight.h" #include "SurfaceLoader.h" @@ -880,7 +885,7 @@ FEM_ObjectBrokerAllClasses::getNewElement(int classTag) return new InertiaTruss(); case ELE_TAG_ZeroLength: - return new ZeroLength(); + return new ZeroLength(); case ELE_TAG_CoupledZeroLength: return new CoupledZeroLength(); @@ -910,13 +915,13 @@ FEM_ObjectBrokerAllClasses::getNewElement(int classTag) return new FourNodeQuadUP(); case ELE_TAG_FourNodeQuad: - return new FourNodeQuad(); + return new FourNodeQuad(); case ELE_TAG_FourNodeQuad3d: return new FourNodeQuad3d(); case ELE_TAG_Tri31: - return new Tri31(); + return new Tri31(); case ELE_TAG_SixNodeTri: return new SixNodeTri(); @@ -1029,7 +1034,7 @@ FEM_ObjectBrokerAllClasses::getNewElement(int classTag) case ELE_TAG_TriSurfaceLoad: return new TriSurfaceLoad(); - + case ELE_TAG_Quad4FiberOverlay: return new Quad4FiberOverlay(); //Amin Pakzad @@ -1041,7 +1046,7 @@ FEM_ObjectBrokerAllClasses::getNewElement(int classTag) case ELE_TAG_FourNodeTetrahedron: return new FourNodeTetrahedron(); - + case ELE_TAG_PML2D: return new PML2D(); @@ -1060,6 +1065,9 @@ FEM_ObjectBrokerAllClasses::getNewElement(int classTag) case ELE_TAG_PML2DVISCOUS: return new PML2DVISCOUS(); // Amin Pakzad + case ELE_TAG_PML3DVISCOUS: + return new PML3DVISCOUS(); // Amin Pakzad + case ELE_TAG_BeamContact2D: return new BeamContact2D(); @@ -1086,13 +1094,13 @@ FEM_ObjectBrokerAllClasses::getNewElement(int classTag) case ELE_TAG_ShellMITC9: return new ShellMITC9(); - + case ELE_TAG_ShellDKGQ: //Added by Lisha Wang, Xinzheng Lu, Linlin Xie, Song Cen & Quan Gu return new ShellDKGQ(); //Added by Lisha Wang, Xinzheng Lu, Linlin Xie, Song Cen & Quan Gu case ELE_TAG_ShellNLDKGQ: //Added by Lisha Wang, Xinzheng Lu, Linlin Xie, Song Cen & Quan Gu return new ShellNLDKGQ(); //Added by Lisha Wang, Xinzheng Lu, Linlin Xie, Song Cen & Quan Gu - + case ELE_TAG_ShellDKGT: return new ShellDKGT(); @@ -1104,7 +1112,7 @@ FEM_ObjectBrokerAllClasses::getNewElement(int classTag) case ELE_TAG_ASDShellT3: // Massimo Petracca return new ASDShellT3(); // Massimo Petracca - + case ELE_TAG_BbarBrick: return new BbarBrick(); @@ -1115,7 +1123,7 @@ FEM_ObjectBrokerAllClasses::getNewElement(int classTag) return new Inno3DPnPJoint(); // Cristian Miculas case ELE_TAG_TwoNodeLink: - return new TwoNodeLink(); + return new TwoNodeLink(); case ELE_TAG_TwoNodeLinkSection: return new TwoNodeLinkSection(); @@ -1356,6 +1364,9 @@ FEM_ObjectBrokerAllClasses::getNewElementalLoad(int classTag) case LOAD_TAG_Beam3dPointLoad: return new Beam3dPointLoad(); + + case LOAD_TAG_BeamUniformMoment: + return new BeamUniformMoment(); case LOAD_TAG_BrickSelfWeight: return new BrickSelfWeight(); @@ -1522,7 +1533,7 @@ FEM_ObjectBrokerAllClasses::getNewSectionIntegration(int classTag) case SECTION_INTEGRATION_TAG_HSS: return new HSSSectionIntegration(); - + default: opserr << "FEM_ObjectBrokerAllClasses::getSectionIntegration - "; opserr << " - no SectionIntegration type exists for class tag "; @@ -1726,6 +1737,9 @@ FEM_ObjectBrokerAllClasses::getNewUniaxialMaterial(int classTag) case MAT_TAG_ASDConcrete1DMaterial: return new ASDConcrete1DMaterial(); + case MAT_TAG_ASDSteel1DMaterial: + return new ASDSteel1DMaterial(); + case MAT_TAG_Concrete01: return new Concrete01(); @@ -1767,7 +1781,7 @@ FEM_ObjectBrokerAllClasses::getNewUniaxialMaterial(int classTag) case MAT_TAG_TDConcreteMC10NL: return new TDConcreteMC10NL(); - + case MAT_TAG_Steel01: return new Steel01(); @@ -1781,7 +1795,7 @@ FEM_ObjectBrokerAllClasses::getNewUniaxialMaterial(int classTag) return new Steel2(); case MAT_TAG_Steel4: - return new Steel4(); + return new Steel4(); case MAT_TAG_RambergOsgoodSteel: return new RambergOsgoodSteel(); @@ -1824,7 +1838,7 @@ FEM_ObjectBrokerAllClasses::getNewUniaxialMaterial(int classTag) case MAT_TAG_SelfCentering: return new SelfCenteringMaterial(); - + case MAT_TAG_TzLiq1: return new TzLiq1(); @@ -1887,7 +1901,7 @@ FEM_ObjectBrokerAllClasses::getNewUniaxialMaterial(int classTag) case MAT_TAG_HookGap: return new HookGap(); - + case MAT_TAG_Viscous: return new ViscousMaterial(); @@ -1928,7 +1942,7 @@ FEM_ObjectBrokerAllClasses::getNewUniaxialMaterial(int classTag) return new ENTMaterial(); case MAT_TAG_GNG: - return new GNGMaterial(); + return new GNGMaterial(); case MAT_TAG_Ratchet: return new Ratchet(); @@ -2022,7 +2036,7 @@ FEM_ObjectBrokerAllClasses::getNewUniaxialMaterial(int classTag) case MAT_TAG_BarSlip: return new BarSlipMaterial(); - + case MAT_TAG_HystereticPoly: // Salvatore Sessa return new HystereticPoly(); @@ -2043,7 +2057,7 @@ FEM_ObjectBrokerAllClasses::getNewUniaxialMaterial(int classTag) case MAT_TAG_Pinching4: return new Pinching4Material(); - + case MAT_TAG_CFSSSWP: return new CFSSSWP(); @@ -2096,14 +2110,14 @@ FEM_ObjectBrokerAllClasses::getNewSection(int classTag) return new ElasticBDShearSection2d(); case SEC_TAG_ElasticShear3d: - return new ElasticShearSection3d(); - + return new ElasticShearSection3d(); + case SEC_TAG_ElasticTube3d: return new ElasticTubeSection3d(); case SEC_TAG_ElasticWarpingShear2d: return new ElasticWarpingShearSection2d(); - + case SEC_TAG_Generic1d: return new GenericSection1d(); @@ -2145,7 +2159,7 @@ FEM_ObjectBrokerAllClasses::getNewSection(int classTag) case SEC_TAG_FiberSectionWarping3d: return new FiberSectionWarping3d(); - + case SEC_TAG_ElasticPlateSection: return new ElasticPlateSection(); @@ -2206,7 +2220,7 @@ FEM_ObjectBrokerAllClasses::getNewNDMaterial(int classTag) return new ElasticIsotropicPlateFiber(); case ND_TAG_ElasticIsotropicBeamFiber: - return new ElasticIsotropicBeamFiber(); + return new ElasticIsotropicBeamFiber(); case ND_TAG_ElasticIsotropicBeamFiber2d: return new ElasticIsotropicBeamFiber2d(); @@ -2362,6 +2376,9 @@ FEM_ObjectBrokerAllClasses::getNewNDMaterial(int classTag) case ND_TAG_J2CyclicBoundingSurfacePlaneStrain: return new J2CyclicBoundingSurfacePlaneStrain(); + case ND_TAG_LinearElasticGGmax: + return new LinearElasticGGmax(); + case ND_TAG_InitialStateAnalysisWrapper: return new InitialStateAnalysisWrapper(); case ND_TAG_stressDensity: @@ -2735,6 +2752,9 @@ FEM_ObjectBrokerAllClasses::getPtrNewRecorder(int classTag) #ifdef _HDF5 case RECORDER_TAGS_MPCORecorder: return new MPCORecorder(); + + case RECORDER_TAGS_VTKHDF_Recorder: + return new VTKHDF_Recorder(); #endif // _HDF5 default: opserr << "FEM_ObjectBrokerAllClasses::getNewRecordr - "; @@ -2768,7 +2788,7 @@ FEM_ObjectBrokerAllClasses::getNewConstraintHandler(int classTag) case HANDLER_TAG_TransformationConstraintHandler: return new TransformationConstraintHandler(); - + case HANDLER_TAG_AutoConstraintHandler: return new AutoConstraintHandler(); diff --git a/SRC/analysis/algorithm/equiSolnAlgo/ExpressNewton.cpp b/SRC/analysis/algorithm/equiSolnAlgo/ExpressNewton.cpp index d187e4441f..01308c7b29 100644 --- a/SRC/analysis/algorithm/equiSolnAlgo/ExpressNewton.cpp +++ b/SRC/analysis/algorithm/equiSolnAlgo/ExpressNewton.cpp @@ -165,8 +165,8 @@ ExpressNewton::sendSelf(int cTag, Channel &theChannel) static Vector data(4); data(0) = nIter; data(1) = kMultiplier1; - data(1) = kMultiplier2; - data(2) = factorOnce; + data(2) = kMultiplier2; + data(3) = factorOnce; return theChannel.sendVector(this->getDbTag(), cTag, data); diff --git a/SRC/analysis/analysis/SDFAnalysis.cpp b/SRC/analysis/analysis/SDFAnalysis.cpp index e8d58e2601..7410d67d63 100644 --- a/SRC/analysis/analysis/SDFAnalysis.cpp +++ b/SRC/analysis/analysis/SDFAnalysis.cpp @@ -31,8 +31,21 @@ int OPS_sdfResponse() int numOptionalArgs = 0; int numArgs = OPS_GetNumRemainingInputArgs(); + double t_end = 0.0; bool t_end_specified = false; while (OPS_GetNumRemainingInputArgs() > 0) { std::string type = OPS_GetString(); + if (type == "-tend") { + numOptionalArgs++; + if (OPS_GetNumRemainingInputArgs() > 0) { + numData = 1; + if (OPS_GetDoubleInput(&numData, &t_end) < 0) { + opserr << "ERROR sdfResponse - failed to read tend" << endln; + return 0; + } + numOptionalArgs++; + t_end_specified = true; + } + } if (type == "-uresid" || type == "-uresidual") { numOptionalArgs++; if (OPS_GetNumRemainingInputArgs() > 0) { @@ -64,8 +77,8 @@ int OPS_sdfResponse() if (numArgs < 7 || numArgs > 8) { opserr << "Incorrect number of arguments to sdfResponse --"; - opserr << "m, zeta, k, Fy, alpha, dtF, filename, dt, <-uresidual, uresid, -umaxprev, umaxp>" << endln; - opserr << "m, zeta, k, Fy, alpha, tsTag, dt, <-uresidual, uresid, -umaxprev, umaxp>" << endln; + opserr << "m, zeta, k, Fy, alpha, dtF, filename, dt, <-uresidual, uresid, -umaxprev, umaxp, -tend, tend>" << endln; + opserr << "m, zeta, k, Fy, alpha, tsTag, dt, <-uresidual, uresid, -umaxprev, umaxp, -tend, tend>" << endln; return -1; } @@ -171,7 +184,7 @@ int OPS_sdfResponse() int i = 0; double ft, u=0, du, v, a, fs, zs, ftrial, kT, kTeff, dg, phat, R, R0, accel; double time = accelSeries->getStartTime(); - double Tend = accelSeries->getDuration(); + double Tend = t_end_specified ? t_end : accelSeries->getDuration(); while (time < Tend) { ft = accelSeries->getFactor(time); diff --git a/SRC/analysis/dof_grp/DOF_Group.cpp b/SRC/analysis/dof_grp/DOF_Group.cpp index def7dc9b33..44f9bbdd38 100644 --- a/SRC/analysis/dof_grp/DOF_Group.cpp +++ b/SRC/analysis/dof_grp/DOF_Group.cpp @@ -650,14 +650,14 @@ void DOF_Group::incrNodeDisp(const Vector &u) { if (myNode == 0) { - opserr << "DOF_Group::setNodeDisp: 0 Node Pointer\n"; + opserr << "DOF_Group::incrNodeDisp: 0 Node Pointer\n"; exit(-1); } Vector &disp = *unbalance;; if (disp.Size() == 0) { - opserr << "DOF_Group::setNodeIncrDisp - out of space\n"; + opserr << "DOF_Group::incrNodeDisp - out of space\n"; return; } int i; @@ -683,7 +683,7 @@ DOF_Group::incrNodeVel(const Vector &udot) { if (myNode == 0) { - opserr << "DOF_Group::setNodeVel: 0 Node Pointer\n"; + opserr << "DOF_Group::incrNodeVel: 0 Node Pointer\n"; exit(-1); } @@ -711,7 +711,7 @@ DOF_Group::incrNodeAccel(const Vector &udotdot) { if (myNode == 0) { - opserr << "DOF_Group::setNodeAccel: 0 Node Pointer\n"; + opserr << "DOF_Group::incrNodeAccel: 0 Node Pointer\n"; exit(-1); } @@ -769,7 +769,7 @@ DOF_Group::setEigenvector(int mode, const Vector &theVector) { if (myNode == 0) { - opserr << "DOF_Group::setNodeAccel: 0 Node Pointer\n"; + opserr << "DOF_Group::setEigenvector: 0 Node Pointer\n"; exit(-1); } @@ -792,7 +792,7 @@ const Matrix & DOF_Group::getEigenvectors(void) { if (myNode == 0) { - opserr << "DOF_Group::setNodeAccel: 0 Node Pointer\n"; + opserr << "DOF_Group::getEigenvectors: 0 Node Pointer\n"; exit(-1); } diff --git a/SRC/analysis/dof_grp/LagrangeDOF_Group.cpp b/SRC/analysis/dof_grp/LagrangeDOF_Group.cpp index a85d03cbff..2a00e1b9cd 100644 --- a/SRC/analysis/dof_grp/LagrangeDOF_Group.cpp +++ b/SRC/analysis/dof_grp/LagrangeDOF_Group.cpp @@ -186,6 +186,11 @@ LagrangeDOF_Group::incrNodeAccel(const Vector &udotdot) return; } +void +LagrangeDOF_Group::setEigenvector(int mode, const Vector &eigenvector) +{ + return; +} const Vector & LagrangeDOF_Group::getCommittedDisp(void) diff --git a/SRC/analysis/dof_grp/LagrangeDOF_Group.h b/SRC/analysis/dof_grp/LagrangeDOF_Group.h index 57b90115c9..bad60a58c7 100644 --- a/SRC/analysis/dof_grp/LagrangeDOF_Group.h +++ b/SRC/analysis/dof_grp/LagrangeDOF_Group.h @@ -73,6 +73,8 @@ class LagrangeDOF_Group: public DOF_Group virtual void incrNodeVel(const Vector &udot); virtual void incrNodeAccel(const Vector &udotdot); + virtual void setEigenvector(int mode, const Vector &eigenvector); + virtual void zeroTangent(void); virtual void addMtoTang(double fact = 1.0); virtual void zeroUnbalance(void); diff --git a/SRC/analysis/handler/AutoConstraintHandler.cpp b/SRC/analysis/handler/AutoConstraintHandler.cpp index 14bf7cdca7..b3ebd1bc8e 100644 --- a/SRC/analysis/handler/AutoConstraintHandler.cpp +++ b/SRC/analysis/handler/AutoConstraintHandler.cpp @@ -63,6 +63,16 @@ #include #include #include +#include + +// for parallel +#ifdef _PARALLEL_PROCESSING +extern bool OPS_PARTITIONED; +#include +#endif // _PARALLEL_PROCESSING +#ifdef _PARALLEL_INTERPRETERS +#include +#endif // _PARALLEL_INTERPRETERS void* OPS_AutoConstraintHandler() { @@ -152,41 +162,49 @@ namespace { */ PenaltyEvaluator(Domain* domain, const std::vector mps, double penalty_oom) { - // store nodes involved in the input mps and init penalty to 0 + // store nodes involved in the input mps and init their local penalty to 0 for (auto* mp : mps) { if (mp) { m_node_penalty[mp->getNodeRetained()] = 0.0; m_node_penalty[mp->getNodeConstrained()] = 0.0; } } - // eval elements connected to those nodes + // evaluate global and local stiffness info + m_gp_min = 0.0; + m_gp_max = 0.0; + m_gp_avg = 0.0; + m_gp_cnt = 0.0; Element* elePtr; ElementIter& theEles = domain->getElements(); while ((elePtr = theEles()) != 0) { if (!elePtr->isSubdomain()) { - // element nodes. process only if at least one node is involved - const ID& elenodes = elePtr->getExternalNodes(); - bool found = false; - for (int i = 0; i < elenodes.Size(); ++i) { - if (m_node_penalty.count(elenodes(i)) > 0) { - found = true; - break; - } - } - if (!found) continue; - // eval max diagonal entry for this element + // eval max diagonal entry for this element ... const Matrix& K = elePtr->getInitialStiff(); double kmax = 0.0; for (int i = 0; i < K.noRows(); ++i) { double ki = std::abs(K(i, i)); kmax = std::max(kmax, ki); } - // and accumulte the same to each node (it's just an approximation) + // ... and accumulte the same kmax to each node (it's just an approximation) + // (process only if at least one node is involved) + const ID& elenodes = elePtr->getExternalNodes(); for (int i = 0; i < elenodes.Size(); ++i) { auto iter = m_node_penalty.find(elenodes(i)); if (iter != m_node_penalty.end()) iter->second += kmax; } + // now eval the global min/max/avg stiffness + m_gp_max = std::max(m_gp_max, kmax); + m_gp_min = m_gp_max; + double k_tol = 1.0e-12 * kmax; + for (int i = 0; i < K.noRows(); ++i) { + double ki = std::abs(K(i, i)); + if (ki > k_tol) { + m_gp_min = std::min(m_gp_min, ki); + m_gp_avg += ki; + m_gp_cnt += 1.0; + } + } } } // now m_node_penalty contains the accumulated max diagonal stiffness entry @@ -200,6 +218,42 @@ namespace { // compute the penalty value item.second = std::pow(10.0, koom + penalty_oom); } + // finalize the global stiffness info for global penalty +#if defined(_PARALLEL_PROCESSING) || defined(_PARALLEL_INTERPRETERS) + int pid = 0; + int np = 1; + MPI_Comm_rank(MPI_COMM_WORLD, &pid); + MPI_Comm_size(MPI_COMM_WORLD, &np); + // quick return for 1 process or for non-partitioned cases (should not happen) + bool do_allreduce = true; + if (np == 1) do_allreduce = false; +#if defined(_PARALLEL_PROCESSING) + if (pid == 0 && !OPS_PARTITIONED) do_allreduce = false; +#endif // defined(_PARALLEL_PROCESSING) + if (do_allreduce) { + double local_min = m_gp_min; + double local_max = m_gp_max; + double local_avg = m_gp_avg; + double local_cnt = m_gp_cnt; + if (MPI_Allreduce(&local_min, &m_gp_min, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD) != MPI_SUCCESS) { + opserr << "AutoConstraintHandler Warning: MPI_Allreduce failed to get MIN\n"; + } + if (MPI_Allreduce(&local_max, &m_gp_max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD) != MPI_SUCCESS) { + opserr << "AutoConstraintHandler Warning: MPI_Allreduce failed to get MAX\n"; + } + if (MPI_Allreduce(&local_avg, &m_gp_avg, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD) != MPI_SUCCESS) { + opserr << "AutoConstraintHandler Warning: MPI_Allreduce failed to get SUM\n"; + } + if (MPI_Allreduce(&local_cnt, &m_gp_cnt, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD) != MPI_SUCCESS) { + opserr << "AutoConstraintHandler Warning: MPI_Allreduce failed to get CNT\n"; + } + } +#endif // defined(_PARALLEL_PROCESSING) || defined(_PARALLEL_INTERPRETERS) + // finalize the average + if (m_gp_cnt > 0.0) m_gp_avg /= m_gp_cnt; + // compute the global penalty as function of the average + double gp_koom = std::round(std::log10(m_gp_avg)); + m_global_penalty = std::pow(10.0, gp_koom + penalty_oom); } /** returns the penalty value for the input mp constraint @@ -212,12 +266,19 @@ namespace { if (itr != m_node_penalty.end()) value = std::max(value, itr->second); auto itc = m_node_penalty.find(mp->getNodeConstrained()); if (itc != m_node_penalty.end()) value = std::max(value, itc->second); + if (value == 0.0) value = m_global_penalty; return value; } public: // maps a node id to the penalty value at that node std::unordered_map m_node_penalty; + // global penalty data + double m_gp_min = 0.0; + double m_gp_max = 0.0; + double m_gp_avg = 0.0; + double m_gp_cnt = 0.0; + double m_global_penalty = 0.0; }; } @@ -390,7 +451,6 @@ AutoConstraintHandler::handle(const ID* nodesLast) MP_Constraint* mpPtr; while ((mpPtr = theMPs()) != 0) mps_penalty.push_back(mpPtr); - } std::shared_ptr peval; if (auto_penalty) @@ -440,6 +500,12 @@ AutoConstraintHandler::handle(const ID* nodesLast) ss << "+ MP Constraints:\n"; ss << " + " << mps_penalty.size() << " constraints handled with the Penalty method\n"; if (auto_penalty) { + ss << " + Global Penalty values:\n"; + ss << " + KMIN = " << std::scientific << peval->m_gp_min << "\n"; + ss << " + KMAX = " << std::scientific << peval->m_gp_max << "\n"; + ss << " + KAVG = " << std::scientific << peval->m_gp_avg << "\n"; + ss << " + PVAL = " << std::scientific << peval->m_global_penalty + << std::defaultfloat << " ( Selected penalty value = 10^(round(log10(KAVG))+" << auto_penalty_oom << ") )\n"; ss << " + Automatic Penalty values for each MP Constraint:\n"; for (MP_Constraint* mp : mps_penalty) ss << " + MP(tag = " << mp->getTag() << ") = " << std::scientific << peval->getPenaltyValue(mp) << "\n"; diff --git a/SRC/classTags.h b/SRC/classTags.h index 46ec11f767..ea09a891d1 100644 --- a/SRC/classTags.h +++ b/SRC/classTags.h @@ -51,12 +51,14 @@ #define EigenSOE_TAGS_FullGenEigenSOE 4 #define EigenSOE_TAGS_ArpackSOE 5 #define EigenSOE_TAGS_GeneralArpackSOE 6 +#define EigenSOE_TAGS_SymmGeneralizedEigenSOE 7 #define EigenSOLVER_TAGS_BandArpackSolver 1 #define EigenSOLVER_TAGS_SymArpackSolver 2 #define EigenSOLVER_TAGS_SymBandEigenSolver 3 #define EigenSOLVER_TAGS_FullGenEigenSolver 4 #define EigenSOLVER_TAGS_ArpackSolver 5 #define EigenSOLVER_TAGS_GeneralArpackSolver 6 +#define EigenSOLVER_TAGS_SymmGeneralizedEigenSolver 7 #define EigenALGORITHM_TAGS_Frequency 1 #define EigenALGORITHM_TAGS_Standard 2 @@ -258,6 +260,8 @@ #define MAT_TAG_PipeMaterial 232 #define MAT_TAG_TzSandCPT 233 #define MAT_TAG_QbSandCPT 234 +#define MAT_TAG_ASDSteel1DMaterial 235 +#define MAT_TAG_CreepShrinkageACI209 236 #define MAT_TAG_FedeasMaterial 1000 #define MAT_TAG_FedeasBond1 1001 @@ -517,11 +521,12 @@ #define ND_TAG_PM4Sand 14021 // PM4Silt material - L.Chen #define ND_TAG_PM4Silt 14022 -// J2CyclicBoundingSurface material - P. Arduino, D.Turello +// J2CyclicBoundingSurface material - P. Arduino #define ND_TAG_J2CyclicBoundingSurface 14023 #define ND_TAG_J2CyclicBoundingSurface3D 14024 #define ND_TAG_J2CyclicBoundingSurfacePlaneStrain 14025 - +// LinearElasticGGmax material - P. Arduino +#define ND_TAG_LinearElasticGGmax 14026 // MultiaxialCyclicPlasticity, add by Gang Wang #define ND_TAG_MultiaxialCyclicPlasticity 10031 #define ND_TAG_MultiaxialCyclicPlasticity3D 10032 @@ -607,7 +612,7 @@ #define PATTERN_TAG_LoadPattern 1 #define PATTERN_TAG_MultiSupportPattern 3 #define PATTERN_TAG_UniformExcitation 2 -#define PATTERN_TAG_FirePattern 3 +#define PATTERN_TAG_FirePattern 7 #define PATTERN_TAG_PBowlLoading 4 #define PATTERN_TAG_DRMLoadPattern 5 #define PATTERN_TAG_H5DRM 6 @@ -616,6 +621,7 @@ #define LOAD_TAG_Beam2dPointLoad 4 #define LOAD_TAG_Beam3dUniformLoad 5 #define LOAD_TAG_Beam3dPointLoad 6 +#define LOAD_TAG_BeamUniformMoment 60 #define LOAD_TAG_BrickSelfWeight 7 #define LOAD_TAG_Beam2dTempLoad 8 #define LOAD_TAG_SurfaceLoader 9 // C.McGann, U.W. @@ -895,6 +901,7 @@ #define ELE_TAG_ShellNLDKGTThermal 268 // Giovanni Rinaldin #define ELE_TAG_Pipe 269 #define ELE_TAG_CurvedPipe 270 +#define ELE_TAG_PML3DVISCOUS 271 // Amin Pakzad #define FRN_TAG_Coulomb 1 @@ -1190,6 +1197,7 @@ #define RECORDER_TAGS_VTK_Recorder 22 #define RECORDER_TAGS_NodeRecorderRMS 23 #define RECORDER_TAGS_ElementRecorderRMS 24 +#define RECORDER_TAGS_VTKHDF_Recorder 25 #define OPS_STREAM_TAGS_FileStream 1 #define OPS_STREAM_TAGS_StandardStream 2 diff --git a/SRC/coordTransformation/Frame/BasicFrameTransf.h b/SRC/coordTransformation/Frame/BasicFrameTransf.h new file mode 100644 index 0000000000..18a23dc1c7 --- /dev/null +++ b/SRC/coordTransformation/Frame/BasicFrameTransf.h @@ -0,0 +1,146 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// The purpose of this class is to wrap the more general FrameTransform<> +// templates to reproduce the legacy CrdTransf classes that were derived +// for elements in a "basic" coordinate system. +// +// Written: Claudio M. Perez +// +#ifndef BasicFrameTransf3d_h +#define BasicFrameTransf3d_h + +#include +#include +#include + +class Vector; +class Matrix; + +namespace OpenSees { + +template +class BasicFrameTransf3d: public CrdTransf +{ +public: + explicit BasicFrameTransf3d(FrameTransform<2,ndf> *t); + + ~BasicFrameTransf3d() override; + + int getLocalAxes(Vector &x, Vector &y, Vector &z) final; + + CrdTransf *getCopy3d() final; + + double getInitialLength() final; + double getDeformedLength() final; + + int initialize(Node *ni, Node *nj) final; + int update() final; + int commitState() final; + int revertToLastCommit() final; + int revertToStart() final; + + const Vector &getBasicTrialDisp() final; + const Vector &getBasicIncrDisp() final; + const Vector &getBasicIncrDeltaDisp() final; + const Vector &getBasicTrialVel() final; + + const Vector &getGlobalResistingForce(const Vector &basicForce, const Vector &p0) final; + const Matrix &getGlobalStiffMatrix(const Matrix &basicStiff, const Vector &basicForce) final; + const Matrix &getInitialGlobalStiffMatrix(const Matrix &basicStiff) final; + + // rotate consistent mass matrix + const Matrix &getGlobalMatrixFromLocal(const Matrix &local) final; + + // methods used in post-processing only + const Vector &getPointGlobalCoordFromLocal(const Vector &localCoords); + const Vector &getPointGlobalDisplFromBasic(double xi, const Vector &basicDisps); + const Vector &getPointLocalDisplFromBasic(double xi, const Vector &basicDisps); + + // + // Sensitivity + // + const Vector & getBasicTrialDispShapeSensitivity() final; + const Vector & getBasicDisplSensitivity(int grad) final; + const Vector &getGlobalResistingForceShapeSensitivity(const Vector &basicForce, + const Vector &p0, int grad) final; + bool isShapeSensitivity() final; + double getdLdh() final; + double getd1overLdh() final; + + + // MovableObject + int sendSelf(int tag, Channel &) final; + int recvSelf(int tag, Channel &, FEM_ObjectBroker &) final; + const char *getClassType() const final { + return "BasicFrameTransf3d"; + } + + // TaggedObject + void Print(OPS_Stream &s, int flag) final; + + + +private: + using Operation = typename FrameTransform<2,ndf>::Operation; + constexpr static int NBV = 6; + constexpr static int NDF = ndf; + enum : int { + inx = -12, // 0 + iny = -12, // 1 + inz = -12, // 2 + imx = -12, // 3 + imy = 3, // 4 + imz = 1, // 5 + iwx = 6, // 6 + jnx = 0, // 6 + jny = -12, // 7 + jnz = -12, // 8 + jmx = 5, // 9 + jmy = 4, // 10 + jmz = 2, // 11 + jwx = 7, + }; + + + static constexpr std::array set_indices() { + if constexpr (ndf-6 > 0) { + return { + inx, iny, inz, imx, imy, imz, iwx, + jnx, jny, jnz, jmx, jmy, jmz, jwx + }; + } else { + return { + inx, iny, inz, imx, imy, imz, + jnx, jny, jnz, jmx, jmy, jmz + }; + } + } + static constexpr auto iq = set_indices(); + + FrameTransform<2,ndf> &t; + LinearFrameTransf<2,ndf> linear; +}; +} // namespace OpenSees + +#include "BasicFrameTransf.tpp" +#endif diff --git a/SRC/coordTransformation/Frame/BasicFrameTransf.tpp b/SRC/coordTransformation/Frame/BasicFrameTransf.tpp new file mode 100644 index 0000000000..82425ba438 --- /dev/null +++ b/SRC/coordTransformation/Frame/BasicFrameTransf.tpp @@ -0,0 +1,490 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include "FrameTransform.h" +#include + +namespace OpenSees { + +namespace { + template + const Vector& + ShapeBasic(const VectorND<2*ndf>& ul) + { + static VectorND<6+(ndf-6)*2> ub; + static Vector wrapper(ub); + ub[0] = ul[1*ndf+0]; // Nj + ub[1] = ul[0*ndf+5]; + ub[2] = ul[1*ndf+5]; + ub[3] = ul[0*ndf+4]; + ub[4] = ul[1*ndf+4]; + ub[5] = ul[1*ndf+3] - ul[0*ndf+3]; + return wrapper; + } +} + + +template +BasicFrameTransf3d::BasicFrameTransf3d(FrameTransform<2,ndf> *t) +: CrdTransf(t->getTag(), 0), + t(*t), + linear(t->getTag(), t->getNormalVector(), t->getRigidOffsets()) +{ + +} + +template +BasicFrameTransf3d::~BasicFrameTransf3d() +{ + delete &t; +} + +template +int +BasicFrameTransf3d::commitState() +{ + return t.commit(); +} + +template +int +BasicFrameTransf3d::revertToLastCommit() +{ + return t.revertToLastCommit(); +} + +template +int +BasicFrameTransf3d::revertToStart() +{ + return t.revertToStart(); +} + +template +int +BasicFrameTransf3d::update() +{ + return t.update(); +} + + +template +int +BasicFrameTransf3d::initialize(Node *i, Node *j) +{ + std::array nodes = {i, j}; + linear.initialize(nodes); + return t.initialize(nodes); +} + +template +int +BasicFrameTransf3d::getLocalAxes(Vector &XAxis, Vector &YAxis, Vector &ZAxis) +{ + Vector3D x, y, z; + int s = t.getLocalAxes(x, y, z); + for (int i=0; i<3; i++) { + XAxis(i) = x[i]; + YAxis(i) = y[i]; + ZAxis(i) = z[i]; + } + return s; +} + +template +double +BasicFrameTransf3d::getInitialLength() +{ + return linear.getInitialLength(); +} + +template +double +BasicFrameTransf3d::getDeformedLength() +{ + return t.getDeformedLength(); +} + + +template +const Vector & +BasicFrameTransf3d::getBasicTrialDisp() +{ + static VectorND<6> ub; + static Vector wrapper(ub); + Vector3D wi = t.getNodeRotationLogarithm(0), + wj = t.getNodeRotationLogarithm(1); + ub[0] = t.getDeformedLength() - t.getInitialLength(); // t.getNodePosition(1)[0]; // + ub[1] = wi[2]; + ub[2] = wj[2]; + ub[3] = wi[1]; + ub[4] = wj[1]; + ub[5] = wj[0] - wi[0]; + return wrapper; +} + + +template +const Vector & +BasicFrameTransf3d::getBasicIncrDeltaDisp() +{ + return ShapeBasic(t.getStateVariation()); +} + +template +const Vector & +BasicFrameTransf3d::getBasicIncrDisp() +{ + static VectorND<6> ub; + static Vector wrapper(ub); + opserr << "Unimplemented method\n"; + return wrapper; +} + +template +const Vector & +BasicFrameTransf3d::getBasicTrialVel() +{ + static VectorND<6> ub; + static Vector wrapper(ub); + opserr << "Unimplemented method\n"; + return wrapper; +} + + +template +const Vector & +BasicFrameTransf3d::getGlobalResistingForce(const Vector &q_pres, const Vector &p0) +{ + // transform resisting forces from the basic system to local coordinates + + static constexpr int nwm = ndf - 6; // Number of warping DOFs + + static constexpr double c = 1.0; + + static VectorND pl{}; + static Vector wrapper(pl); // to return reference + pl.zero(); + pl[0*NDF+0] = -q_pres[jnx] + p0[0]*c; // Ni + pl[0*NDF+1] = p0[1]*c; // + pl[0*NDF+2] = p0[3]*c; // + pl[0*NDF+3] = -q_pres[jmx]; // Ti + pl[0*NDF+4] = q_pres[imy]; + pl[0*NDF+5] = q_pres[imz]; + pl[1*NDF+0] = q_pres[jnx]; // Nj + pl[1*NDF+1] = p0[2]*c; + pl[1*NDF+2] = p0[4]*c; + pl[1*NDF+3] = q_pres[jmx]; // Tj + pl[1*NDF+4] = q_pres[jmy]; + pl[1*NDF+5] = q_pres[jmz]; + + if constexpr (nwm > 0) // Warping DOFs + for (int i=0; i +const Matrix & +BasicFrameTransf3d::getGlobalStiffMatrix(const Matrix &kb, const Vector &q_pres) +{ + static constexpr int nwm = ndf - 6; // Number of warping DOFs + + static VectorND pl{}; + pl.zero(); + pl[0*NDF+4] = q_pres[imy]; + pl[0*NDF+5] = q_pres[imz]; + pl[1*NDF+0] = q_pres[jnx]; // Nj + pl[1*NDF+3] = q_pres[jmx]; // Tj + pl[1*NDF+4] = q_pres[jmy]; + pl[1*NDF+5] = q_pres[jmz]; + // + pl[0*NDF+0] = -q_pres[jnx]; // Ni + pl[0*NDF+3] = -q_pres[jmx]; // Ti + + if constexpr (nwm > 0) // Warping DOFs + for (int i=0; i kl; + static Matrix Wrapper(kl); + + Repeat ([&](auto j_) { + constexpr static int j = j_.value; + constexpr int jj = iq[j] >= 0 ? iq[j] : -iq[j]; + + Repeat ([&](auto i_) { + constexpr static int i = i_.value; + constexpr int ii = iq[i] >= 0 ? iq[i] : -iq[i]; + if constexpr (ii >= NBV || jj >= NBV) { + kl(i,j) = 0.0; + return; + } + + kl(i,j) = kb(ii, jj); + }); + }); + + Repeat ([&](auto i_) { + constexpr static int i = i_.value; + kl(0*NDF+0, i) = kl(i, 0*NDF+0) = i==0? kl(NDF+0, NDF+0): (i==3? kl(NDF+0, NDF+3) : -kl( NDF+0, i)); + kl(0*NDF+3, i) = kl(i, 0*NDF+3) = i==0? kl(NDF+3, NDF+0): (i==3? kl(NDF+3, NDF+3) : -kl( NDF+3, i)); + }); + + t.push(kl, pl, Operation::Total); + + return Wrapper; +} + + +template +const Matrix & +BasicFrameTransf3d::getInitialGlobalStiffMatrix(const Matrix &KB) +{ + static double kb[6][6]; // Basic stiffness + + static MatrixND<2*ndf,2*ndf> kl; // Local stiffness + + double tmp[6][12]{}; + + for (int i = 0; i < 6; i++) + for (int j = 0; j < 6; j++) + kb[i][j] = KB(i, j); + + // Transform basic stiffness to local system + // First compute kb*T_{bl} + for (int i = 0; i < 6; i++) { + tmp[i][0] = -kb[i][0]; + tmp[i][3] = -kb[i][5]; + tmp[i][4] = kb[i][3]; + tmp[i][5] = kb[i][1]; + tmp[i][6] = kb[i][0]; + tmp[i][9] = kb[i][5]; + tmp[i][10] = kb[i][4]; + tmp[i][11] = kb[i][2]; + } + + kl.zero(); + // Now compute T'_{bl}*(kb*T_{bl}) + for (int i = 0; i < 12; i++) { + kl( 0, i) = -tmp[0][i]; + kl( 3, i) = -tmp[5][i]; + kl( 4, i) = tmp[3][i]; + kl( 5, i) = tmp[1][i]; + + kl( 6, i) = tmp[0][i]; + kl( 9, i) = tmp[5][i]; + kl(10, i) = tmp[4][i]; + kl(11, i) = tmp[2][i]; + } + + static MatrixND kg; + static Matrix M(kg); + static constexpr VectorND p0{}; + + kg = linear.pushResponse(kl, p0); + + return M; +} + + +template +CrdTransf * +BasicFrameTransf3d::getCopy3d() +{ + return new BasicFrameTransf3d(t.getCopy()); +} + + +template +const Matrix & +BasicFrameTransf3d::getGlobalMatrixFromLocal(const Matrix &M) +{ + // + // Do diag(R)*M*diag(R)' + // + static MatrixND Kout; + static Matrix wrapper(Kout); + static constexpr VectorND p0{}; + wrapper = M; + MatrixND Kg = linear.pushResponse(Kout, p0); + Kout = Kg; + return wrapper; +} + + +template +const Vector & +BasicFrameTransf3d::getPointGlobalCoordFromLocal(const Vector &xl) +{ + static Vector xg(3); + return xg; +} + + +template +const Vector & +BasicFrameTransf3d::getPointGlobalDisplFromBasic(double xi, const Vector &uxb) +{ + static Vector uxg(3); + return uxg; +} + +template +const Vector & +BasicFrameTransf3d::getPointLocalDisplFromBasic(double xi, const Vector &uxb) +{ + static Vector uxl(3); + return uxl; +} + +// +// Sensitivity +// +template +bool +BasicFrameTransf3d::isShapeSensitivity() +{ + return t.isShapeSensitivity(); +} + + +template +double +BasicFrameTransf3d::getdLdh() +{ + return t.getLengthGrad(); +} + +template +double +BasicFrameTransf3d::getd1overLdh() +{ + double L = t.getInitialLength(); + return -getLengthGrad()/(L*L); +} + +template +const Vector & +BasicFrameTransf3d::getGlobalResistingForceShapeSensitivity(const Vector &q_pres, + const Vector &p0, + int gradNumber) +{ + // return t.getGlobalResistingForceShapeSensitivity(pb, p0, gradNumber); + + static constexpr int nwm = ndf - 6; // Number of warping DOFs + + static constexpr double c = 1.0; + + static VectorND pl{}; + pl.zero(); + pl[0*NDF+0] = -q_pres[jnx] + p0[0]*c; // Ni + pl[0*NDF+1] = p0[1]*c; // + pl[0*NDF+2] = p0[3]*c; // + pl[0*NDF+3] = -q_pres[jmx]; // Ti + pl[0*NDF+4] = q_pres[imy]; + pl[0*NDF+5] = q_pres[imz]; + pl[1*NDF+0] = q_pres[jnx]; // Nj + pl[1*NDF+1] = p0[2]*c; + pl[1*NDF+2] = p0[4]*c; + pl[1*NDF+3] = q_pres[jmx]; // Tj + pl[1*NDF+4] = q_pres[jmy]; + pl[1*NDF+5] = q_pres[jmz]; + + if constexpr (nwm > 0) // Warping DOFs + for (int i=0; i dp; + static Vector wrapper(dp); // to return reference + dp.zero(); + + t.pushGrad(dp, pl); + + return wrapper; +} + + +template +const Vector & +BasicFrameTransf3d::getBasicTrialDispShapeSensitivity() +{ + static VectorND<2*ndf> du; + t.pullFixedGrad(du); + return ShapeBasic(du); +} + +template +const Vector & +BasicFrameTransf3d::getBasicDisplSensitivity(int gradNumber) +{ + static VectorND<2*ndf> du; + t.pullTotalGrad(du, gradNumber); + return ShapeBasic(du); +} + + +template +void +BasicFrameTransf3d::Print(OPS_Stream &s, int flag) +{ + t.Print(s, flag); +} + + +template +int +BasicFrameTransf3d::sendSelf(int cTag, Channel &theChannel) +{ + return -1; +} + + +template +int +BasicFrameTransf3d::recvSelf(int cTag, Channel &, + FEM_ObjectBroker &theBroker) +{ + return -1; +} + +} diff --git a/SRC/runtime/runtime/SectionBuilder/reinfBar/CMakeLists.txt b/SRC/coordTransformation/Frame/CMakeLists.txt similarity index 62% rename from SRC/runtime/runtime/SectionBuilder/reinfBar/CMakeLists.txt rename to SRC/coordTransformation/Frame/CMakeLists.txt index 36a8f2fd20..3ad768efbd 100644 --- a/SRC/runtime/runtime/SectionBuilder/reinfBar/CMakeLists.txt +++ b/SRC/coordTransformation/Frame/CMakeLists.txt @@ -5,11 +5,4 @@ # #============================================================================== -target_sources(OPS_Section_Repres - PRIVATE - ReinfBar.cpp - PUBLIC - ReinfBar.h -) -target_include_directories(OPS_Section_Repres PUBLIC ${CMAKE_CURRENT_LIST_DIR}) - +target_include_directories(OPS_Transform PUBLIC ${CMAKE_CURRENT_LIST_DIR}) diff --git a/SRC/coordTransformation/Frame/EuclidFrameTransf.h b/SRC/coordTransformation/Frame/EuclidFrameTransf.h new file mode 100644 index 0000000000..9d128c8b54 --- /dev/null +++ b/SRC/coordTransformation/Frame/EuclidFrameTransf.h @@ -0,0 +1,156 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// Description: This file contains the implementation for the +// EuclidFrameTransf class. EuclidFrameTransf is a euclidean transformation +// of 3D space. +// When used with the RankinIsometry, it furnishes an improved corotational +// transformation for 3D frames. +// +// +// Written: Claudio M. Perez +// Created: 04/2025 +// +#ifndef EuclidFrameTransf_hpp +#define EuclidFrameTransf_hpp + +#include +#include +#include +#include +#include + +namespace OpenSees { + +template +class EuclidFrameTransf: public FrameTransform +{ +public: + constexpr static int n = nn*ndf; + + EuclidFrameTransf(int tag, + const Vector3D &vecxz, + const std::array *offset=nullptr, + int offset_flags = 0); + + ~EuclidFrameTransf(); + + using Operation = typename FrameTransform::Operation; + + const char *getClassType() const {return "EuclidFrameTransf";} + + virtual int getLocalAxes(Vector3D &x, Vector3D &y, Vector3D &z) const; + + FrameTransform *getCopy() const final; + + double getInitialLength() final; + double getDeformedLength() final; + const std::array *getRigidOffsets() const final {return offsets;} + + int initialize(std::array& new_nodes) final; + int update() final; + int commit() final; + int revertToLastCommit() final; + int revertToStart() final; + + VectorND getStateVariation() final; + Vector3D getNodePosition(int tag) final; + Versor getNodeRotation(int tag) /* final */; + Vector3D getNodeRotationLogarithm(int tag) final; + + int push(VectorND&pl, Operation) final; + int push(MatrixND& kl, const VectorND& pl, Operation) final; + + // Sensitivity + bool isShapeSensitivity() final; + double getLengthGrad() final; + double getd1overLdh() final; + + // TaggedObject + void Print(OPS_Stream &s, int flag) final; + + +private: + + Vector3D getNodeLocation(int tag); + + inline MatrixND + getProjection() { + + MatrixND A{}; + A.addDiagonal(1.0); + + MatrixND<3,ndf> Gb{}; + for (int a = 0; a(basis.getRotationGradient(b), 1.0); + Matrix3D Xa = Hat(this->getNodeLocation(a)); + A.assemble(Xa*Gb, a*ndf , b*ndf, 1.0); + A.assemble( Gb, a*ndf+3, b*ndf, -1.0); + } + } + + return A; + } + + template + const Vector3D + pullPosition(int node) + { + const Vector &u = (nodes[node]->*Getter)(); + + Vector3D v; + for (int i=0; i<3; i++) + v[i] = u[i]; + + // 1) Offsets + if (offsets) [[unlikely]] { + if (!(offset_flags&OffsetLocal)) { + Vector3D w {u[3], u[4], u[5]}; + v -= offsets->at(node).cross(w); + } + } + + // 2) Constant Rotation + Matrix3D R = basis.getRotation(); + return R^v; + } + + std::array nodes; + std::array ur; // rotation vector + // std::array ux; // displacement vector + + std::array *offsets; + int offset_flags; + Matrix3D R0; + Vector3D xi, xj, vz; + double L; // undeformed element length + + IsoT basis; +}; + +} // namespace OpenSees + +#include "EuclidFrameTransf.tpp" + +#endif diff --git a/SRC/coordTransformation/Frame/EuclidFrameTransf.tpp b/SRC/coordTransformation/Frame/EuclidFrameTransf.tpp new file mode 100644 index 0000000000..d02edd381d --- /dev/null +++ b/SRC/coordTransformation/Frame/EuclidFrameTransf.tpp @@ -0,0 +1,519 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// Written: Claudio M. Perez +// Created: 04/2025 +// + +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "EuclidFrameTransf.h" + +namespace OpenSees { + +template +EuclidFrameTransf::EuclidFrameTransf(int tag, + const Vector3D &vecxz, + const std::array *offset, + int offset_flags) + : FrameTransform(tag), + L(0), + nodes{}, + ur{}, + offsets{nullptr}, + offset_flags(offset_flags), + basis{vecxz} +{ + R0.zero(); + R0.addDiagonal(1.0); + double nz = vecxz.norm(); + for (int i=0; i<3; i++) + vz[i] = vecxz[i]/nz; + + // Rigid joint offsets + if (offset != nullptr) { + offsets = new std::array{}; + *offsets = *offset; + basis.setOffsets(offsets); + } +} + + + +template +EuclidFrameTransf::~EuclidFrameTransf() +{ + if (offsets != nullptr) + delete offsets; +} + +template +int +EuclidFrameTransf::commit() +{ + return 0; +} + +template +int +EuclidFrameTransf::revertToLastCommit() +{ + return 0; +} + +template +int +EuclidFrameTransf::revertToStart() +{ + return 0; +} + + +template +int +EuclidFrameTransf::initialize(std::array& new_nodes) +{ + for (int i=0; igetTrialRotation(); + } + + const Vector &XI = nodes[ 0]->getCrds(); + const Vector &XJ = nodes[nn-1]->getCrds(); + + for (int i=0; i<3; i++) { + xi[i] = XI[i]; + xj[i] = XJ[i]; + } + + Vector3D dx = xj - xi; + + if (offsets != nullptr) { + for (int i=0; i<3; i++) + dx(i) -= (*offsets)[ 0][i]; + for (int i=0; i<3; i++) + dx(i) += (*offsets)[nn-1][i]; + } + + // calculate the element length + L = dx.norm(); + + if (L == 0.0) + return -2; + + int error = basis.initialize(nodes); + + R0 = basis.getRotation(); + return error; +} + + +template +FrameTransform * +EuclidFrameTransf::getCopy() const +{ + return new EuclidFrameTransf(this->getTag(), vz, offsets); +} + + +template +int +EuclidFrameTransf::getLocalAxes(Vector3D &e1, Vector3D &e2, Vector3D &e3) const +{ + Matrix3D R = basis.getRotation(); + for (int i = 0; i < 3; i++) { + e1[i] = R(i,0); + e2[i] = R(i,1); + e3[i] = R(i,2); + } + return 0; +} + +template +double +EuclidFrameTransf::getInitialLength() +{ + return L; +} + +template +double +EuclidFrameTransf::getDeformedLength() +{ + return basis.getLength(); +} + + +// +// Pull +// +template +int +EuclidFrameTransf::update() +{ + if (basis.update(nodes) < 0) + return -1; + + const Matrix3D R = basis.getRotation(); + + for (int i=0; igetTrialRotation(); + ur[i] = AxisAngle(R^(MatrixFromVersor(q)*R0)); + } + + return 0; +} + +template +Versor +EuclidFrameTransf::getNodeRotation(int tag) +{ + return nodes[tag]->getTrialRotation(); +} + + +template +Vector3D +EuclidFrameTransf::getNodeLocation(int node) +{ + Vector3D xn = basis.getRotation()^nodes[node]->getCrds(); + + xn += this->pullPosition<&Node::getTrialDisp>(node); + + return xn - basis.getLocation(); +} + + +template +Vector3D +EuclidFrameTransf::getNodePosition(int node) +{ + Vector3D u = this->pullPosition<&Node::getTrialDisp>(node); + u -= basis.getPosition(); + u += basis.getRotationDelta()^(nodes[node]->getCrds()); + return u; +} + + +template +Vector3D +EuclidFrameTransf::getNodeRotationLogarithm(int node) +{ + return ur[node].vector; +} + + +template +VectorND +EuclidFrameTransf::getStateVariation() +{ + + static VectorND ul; + for (int i=0; igetIncrDeltaDisp(); + for (int j = 0; j < ndf; j++) { + ul[i*ndf+j] = ddu(j); + } + } + + const Matrix3D R = basis.getRotation(); + + // (1) Global Offsets + // Do ui -= ri x wi + if constexpr (ndf >= 6) + if (offsets && !(offset_flags&OffsetLocal)) [[unlikely]] { + const std::array& offset = *offsets; + for (int i=0; igetNodePosition(i); + ul.assemble(i*ndf+0, dc, -1.0); + ul.assemble(i*ndf+0, ui.cross(wr), 1.0); + ul.assemble(i*ndf+3, wr, -1.0); + } + } + + // 3) Offsets + if constexpr (ndf >= 6) + if (offsets && (offset_flags&OffsetLocal)) [[unlikely]] { + const std::array& offset = *offsets; + for (int i=0; i +int +EuclidFrameTransf::push(VectorND&p, Operation op) +{ + VectorND& pa = p; + + // 1) Logarithm + for (int i=0; igetNodeLocation(i).cross(Vector3D{pa[i*ndf+0], pa[i*ndf+1], pa[i*ndf+2]}); + } + // 2.2) Adjust + for (int i=0; i(i*ndf, basis.getRotationGradient(i)^m, -1.0); + + + // 3,4) Rotate and joint offsets + Matrix3D R = basis.getRotation(); + for (int i=0; i +int +EuclidFrameTransf::push(MatrixND&kb, + const VectorND& pb, + Operation op) +{ + VectorND p = pb; + + MatrixND Kb = kb; + if (1) {//!(offset_flags & LogIter)) { + for (int i=0; i& Kl = kb; + const MatrixND A = getProjection(); + Kl.addMatrixTripleProduct(0, A, Kb, 1); + + + const VectorND Ap = A^p; + + // Kl += Kw * A + Kb.zero(); + VectorND<12> qwx{}; + for (int i=0; i Kw = basis.getRotationJacobian(qwx); + Kb.assemble(Kw.template extract<0, 6, 0, 6>(), 0, 0, 1.0); + Kb.assemble(Kw.template extract<0, 6, 6,12>(), 0, ndf, 1.0); + Kb.assemble(Kw.template extract<6,12, 0, 6>(), ndf, 0, 1.0); + Kb.assemble(Kw.template extract<6,12, 6,12>(), ndf, ndf, 1.0); + Kl.addMatrixProduct(Kb, A, 1.0); + } + + // + // Kl += -W'*Pn'*A - Pnm * W + // + Kb.zero(); + for (int j=0; j Gj = basis.getRotationGradient(j); + for (int i=0; i::pushRotation(Kl, basis.getRotation()); + return 0; +} + + + +// +// Sensitivity +// +template +bool +EuclidFrameTransf::isShapeSensitivity() +{ + int nodeParameterI = nodes[ 0]->getCrdsSensitivity(); + int nodeParameterJ = nodes[nn-1]->getCrdsSensitivity(); + // TODO(sensitivity): implement dvz + + return (nodeParameterI != 0 || nodeParameterJ != 0); +} + + +template +double +EuclidFrameTransf::getLengthGrad() +{ + const int di = nodes[0]->getCrdsSensitivity(); + const int dj = nodes[1]->getCrdsSensitivity(); + + Vector3D dxi{0.0}; + Vector3D dxj{0.0}; + + if (di != 0) + dxi(di-1) = 1.0; + if (dj != 0) + dxj(dj-1) = 1.0; + + return 1/L*(xj - xi).dot(dxj - dxi); +} + +template +double +EuclidFrameTransf::getd1overLdh() +{ + return -getLengthGrad()/(L*L); +} + + +template +void +EuclidFrameTransf::Print(OPS_Stream &s, int flag) +{ + if (flag == OPS_PRINT_PRINTMODEL_JSON) { + s << OPS_PRINT_JSON_MATE_INDENT << "{"; + s << "\"name\": " << this->getTag() << ", "; + s << "\"type\": \"EuclidFrameTransf\""; + s << ", \"vecxz\": [" + << vz[0] << ", " + << vz[1] << ", " + << vz[2] << "]"; + if (offsets != nullptr) { + s << ", \"offsets\": ["; + for (int i=0; i +#include +#include +#include + +using OpenSees::VectorND; +using OpenSees::MatrixND; +using OpenSees::Matrix3D; +class Information; +class Response; +class Node; + +enum { + CRDTR_TAG_CorotFrameTransfWarping3d, + CRDTR_TAG_CorotFrameTransf3d, + CRDTR_TAG_LinearFrameTransf3d, + CRDTR_TAG_PDeltaFrameTransf3d +}; + +enum { + OffsetGlobal = 0, // 1<<0, + OffsetLocal = 1, // 1<<1, + OffsetNormalized = 2, // 1<<2, + + LogIter = 1<<3, + LogIncr = 1<<4, + LogInit = 1<<5, + LogDefault = 1<<6 +}; + +namespace OpenSees { + +template +class FrameTransform : public TaggedObject +{ +public: + explicit FrameTransform(int tag) : TaggedObject(tag) {} + + enum class Operation { + Total = 0, + Logarithm = 1<<0, + LocalOffset = 1<<1, + Isometry = 1<<2, + Rotation, + GlobalOffset, + Exponential + }; + + virtual FrameTransform *getCopy() const =0; + + + virtual int initialize(std::array& nodes)=0; + virtual int update() =0; + virtual int commit() =0; + virtual int revertToLastCommit() =0; + virtual int revertToStart() =0; + + virtual Vector3D getNodePosition(int tag) =0; + virtual Vector3D getNodeRotationLogarithm(int tag) =0; + virtual VectorND getStateVariation() =0; // pull + virtual int push(VectorND&pl, Operation=0) =0; + virtual int push(MatrixND& kl, const VectorND& pl, Operation=0) =0; + + virtual double getInitialLength() =0; + virtual double getDeformedLength() =0; + virtual const std::array *getRigidOffsets() const =0; + + // + virtual int getLocalAxes(Vector3D &x, Vector3D &y, Vector3D &z) const =0; + + Vector3D getNormalVector() const { + Vector3D x, y, z; + if (getLocalAxes(x, y, z) < 0) + return Vector3D{{0.0, 0.0, 1.0}}; + return z; + } + + // Recorders + virtual Response *setResponse(const char **argv, int argc, OPS_Stream &) { + return nullptr; + } + virtual int getResponse(int responseID, Information &) { + return -1; + } + + // Sensitivity + virtual void pushGrad(VectorND& dp, VectorND& pl) {} + virtual void pullFixedGrad(VectorND&) {} + virtual void pullTotalGrad(VectorND&, int) {} + virtual bool isShapeSensitivity() {return false;} + virtual double getLengthGrad() {return 0.0;} + virtual double getd1overLdh() {return 0.0;} + + + // deprecatred API + virtual VectorND pushResponse(VectorND&pl) final { + VectorND pg{pl}; + push(pg, Operation::Total); + return pg; + } + + virtual MatrixND pushResponse(MatrixND& kl, + const VectorND& pl) final { + MatrixND kg{kl}; + push(kg, pl, Operation::Total); + return kg; + } + + + +protected: + constexpr static int ndm = 3; + static inline constexpr void + pushRotation(MatrixND& Kg, const Matrix3D& R); + + static inline constexpr void + pushOffsets(MatrixND& Kg, const std::array& offsets); + + static int + Orient(const Vector3D& dx, const Vector3D& vz, Matrix3D &R) { + + // calculate the element local x axis components wrt to the global coordinates + + Vector3D e1 = dx/dx.norm(); + + // + Vector3D e2 = vz.cross(e1); + + const double ynorm = e2.norm(); + + if (ynorm == 0.0) + return -1; + + e2 /= ynorm; + + Vector3D e3 = e1.cross(e2); + + for (int i = 0; i < 3; i++) { + R(i,0) = e1[i]; + R(i,1) = e2[i]; + R(i,2) = e3[i]; + } + return 0; + } + + VectorND pushConstant(const VectorND&pl); + MatrixND pushConstant(const MatrixND& kl); + +}; +} +#include "FrameTransform.tpp" + +#endif // include guard diff --git a/SRC/coordTransformation/Frame/FrameTransform.tpp b/SRC/coordTransformation/Frame/FrameTransform.tpp new file mode 100644 index 0000000000..f491979bbb --- /dev/null +++ b/SRC/coordTransformation/Frame/FrameTransform.tpp @@ -0,0 +1,179 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// +// +#pragma once +#include "FrameTransform.h" +#include +#include + +namespace OpenSees { + +template +VectorND +FrameTransform::pushConstant(const VectorND& pl) +{ + Matrix3D R; + Vector3D x, y, z; + getLocalAxes(x, y, z); + for (int i=0; i<3; i++) { + R(i,0) = x[i]; + R(i,1) = y[i]; + R(i,2) = z[i]; + } + + constexpr int N = nn * ndf; + + // + // Initialize + // + VectorND pg = pl; + + // (A) First pass: just do the direct transformations + for (int i=0; i *offset = this->getRigidOffsets(); + if (offset) { + const std::array& offsets = *offset; + for (int i=0; i +MatrixND +FrameTransform::pushConstant(const MatrixND& kl) +{ + // + // Do diag(R)*M*diag(R)' + // + static MatrixND Kg; + Kg = kl; + + Matrix3D R; + Vector3D x, y, z; + getLocalAxes(x, y, z); + for (int i=0; i<3; i++) { + R(i,0) = x[i]; + R(i,1) = y[i]; + R(i,2) = z[i]; + } + + this->pushRotation(Kg, R); + + const std::array *offset = this->getRigidOffsets(); + if (offset) [[unlikely]] { + this->pushOffsets(Kg, *offset); + } + return Kg; +} + +template +constexpr void +FrameTransform::pushRotation(MatrixND& Kg, const Matrix3D& R) +{ + // + // Do diag(R)*M*diag(R)' + // + const Matrix3D RT = R.transpose(); + for (int i=0; i +constexpr void +FrameTransform::pushOffsets(MatrixND& Kg, + const std::array& offsets) +{ + for (int i=0; i(i*ndf+3, j*ndf), offsets[j], -1.0); + Kg.assemble(KmnW, i*ndf+3, j*ndf+3, 1.0); + } + { + Matrix3D WKnm{}; + WKnm.addSpinMatrixProduct(offsets[i], Kg.template extract<3,3>(i*ndf, j*ndf+3), 1.0); + Kg.assemble(WKnm, i*ndf+3, j*ndf+3, 1.0); + } + { + Matrix3D WKnn{}; + { + Matrix3D Knn = Kg.template extract<3,3>(i*ndf, j*ndf); + { + Matrix3D KnnW{}; + KnnW.addMatrixSpinProduct(Knn, offsets[j], -1.0); + Kg.assemble(KnnW, i*ndf, j*ndf+3, 1.0); + } + WKnn.addSpinMatrixProduct(offsets[i], Knn, 1.0); + Kg.assemble(WKnn, i*ndf+3, j*ndf, 1.0); + } + Matrix3D WKmmW{}; + WKmmW.addMatrixSpinProduct(WKnn, offsets[j], -1.0); + Kg.assemble(WKmmW, i*ndf+3, j*ndf+3, 1.0); + } + } + } +} + +} // namespace OpenSees \ No newline at end of file diff --git a/SRC/coordTransformation/Frame/Isometry/BattiniIsometry.h b/SRC/coordTransformation/Frame/Isometry/BattiniIsometry.h new file mode 100644 index 0000000000..c8e0cd66c3 --- /dev/null +++ b/SRC/coordTransformation/Frame/Isometry/BattiniIsometry.h @@ -0,0 +1,135 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// Written: Claudio M. Perez, +// Filip C. Filippou +// University of California, Berkeley +// +// Developed with FEDEASLab [2]. +// +// References: +// +// [2] Filippou, F.C. (1998) +// "FEDEASLab: Finite Elements for Design Evaluation and Analysis of Structures" +// +// [3] Battini, J.-M. and Pacoste, C. (2002) +// "Co-rotational beam elements with warping effects in instability problems", +// Computer Methods in Applied Mechanics and Engineering, 191(17–18), +// pp. 1755–1789. Available at: https://doi.org/10.1016/S0045-7825(01)00352-8. +// +#pragma once +#include +#include +#include +#include +#include "EuclidIsometry.h" + +class Node; + +namespace OpenSees { + +template +class BattiniIsometry : public AlignedIsometry +{ +public: + BattiniIsometry(const Vector3D& vecxz) + : AlignedIsometry(vecxz), + n(0) + { + } + + using AlignedIsometry::init; + using AlignedIsometry::pres; + + Matrix3D + update_basis(const Matrix3D& RI, const Matrix3D& RJ, const Vector3D& dx) final + { + Matrix3D R; + { + Vector3D e1 = dx; + e1 /= e1.norm(); + + constexpr static Vector3D D2 {0,1,0}; + const Vector3D E2 = this->AlignedIsometry::R[init]*D2; + q = RI*E2; //*R[init]; + q.addVector(0.5, RJ*E2, 0.5); + + + Vector3D e3 = e1.cross(q); + e3 /= e3.norm(); + + Vector3D e2 = e3.cross(e1); + + for (int i = 0; i < 3; i++) { + R(i,0) = e1[i]; + R(i,1) = e2[i]; + R(i,2) = e3[i]; + } + + Vector3D Q = R^q; + n = Q[0]/Q[1]; + + Vector3D QI = R^(RI*E2); + Vector3D QJ = R^(RJ*E2); + n11 = QI[0]/Q[1]; + n12 = QI[1]/Q[1]; + n21 = QJ[0]/Q[1]; + n22 = QJ[1]/Q[1]; + } + return R; + } + + + MatrixND<3,6> + getRotationGradient(int node) final { + MatrixND<3,6> Gb{}; + + constexpr Vector3D axis{1, 0, 0}; + constexpr Matrix3D ix = Hat(axis); + + double Ln = this->getLength(); + + if (node == 0) { + Gb.template insert<0,0>( ix, -1.0/Ln); + Gb(0,2) = n/Ln; + Gb(0,3) = n12/2.0; // - n; + Gb(0,4) = -n11/2.0; + } + else if (node == nn-1) { + Gb.template insert<0,0>( ix, 1.0/Ln); + Gb(0,2) = - n/Ln; + Gb(0,3) = n22/2.0; + Gb(0,4) = -n12/2.0; + } + + return Gb; + } + +private: + Vector3D q {0,1,0}; + double n = 0, + n11 = 0, + n12 = 1, + n21 = 0, + n22 = 1; +}; +} // namespace OpenSees \ No newline at end of file diff --git a/SRC/coordTransformation/Frame/Isometry/CrisfieldIsometry.h b/SRC/coordTransformation/Frame/Isometry/CrisfieldIsometry.h new file mode 100644 index 0000000000..a4429f4abc --- /dev/null +++ b/SRC/coordTransformation/Frame/Isometry/CrisfieldIsometry.h @@ -0,0 +1,872 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// Written: Claudio M. Perez, +// Filip C. Filippou +// University of California, Berkeley +// +// Developed with FEDEASLab [2]. +// +// References: +// +// [2] Filippou, F.C. (1998) +// "FEDEASLab: Finite Elements for Design Evaluation and Analysis of Structures" +// +// [3] Crisfield, M.A. (1990) "A consistent co-rotational formulation for +// non-linear, three-dimensional, beam-elements", Computer Methods in Applied +// Mechanics and Engineering, 81(2), pp. 131–150. Available at: +// https://doi.org/10.1016/0045-7825(90)90106-V. +// +#pragma once +#include +#include +#include +#include +#include +#include "EuclidIsometry.h" + +class Node; + +namespace OpenSees { + +namespace { +struct Triad { + + Triad(const OpenSees::Matrix3D &E) + : e{{E(0,0),E(1,0),E(2,0)}, // e1 + {E(0,1),E(1,1),E(2,1)}, // e2 + {E(0,2),E(1,2),E(2,2)}} // e3 + { + } + + constexpr inline + const Vector3D& operator[](int i) const { + return e[i-1]; + } + + const Vector3D e[3]; +}; +} + +template +class CrisfieldIsometry : public AlignedIsometry { +public: + CrisfieldIsometry(const Vector3D& vecxz) + : AlignedIsometry{vecxz}, + // Lr2{}, Lr3{}, + v{} + { + + } + + Matrix3D + update_basis(const Matrix3D& RI, const Matrix3D& RJ, const Vector3D& dx) + { + // Ln = dx.norm(); + this->AlignedIsometry::Ln = dx.norm(); + double Ln = this->getLength(); + { + const Triad TrI{RI}, TrJ{RJ}; + rI[0] = TrI[1]; + rI[1] = TrI[2]; + rI[2] = TrI[3]; + rJ[0] = TrJ[1]; + rJ[1] = TrJ[2]; + rJ[2] = TrJ[3]; + } + + { + // const Versor qI = Versor::from_matrix(RI); + // const Versor qJ = Versor::from_matrix(RJ); + // Versor qij = qJ.mult_conj(qI); + // qij.normalize(); + Versor qij = Versor::from_matrix(RJ*RI.transpose()); + Vector3D gw = CayleyFromVersor(qij); + + gw *= 0.5; + + Rbar = CaySO3(gw)*RI; + + const Triad r{Rbar}; + r1 = r[1]; + r2 = r[2]; + r3 = r[3]; + } + + e[0] = dx; + e[0] /= Ln; + + // + // Compute the base vectors e2, e3 + // + // 'rotate' the mean rotation matrix Rbar on to e1 to + // obtain e2 and e3 + + Matrix3D E; + if constexpr (orthogonal) + { + constexpr double ktol = 1.0*std::numeric_limits::epsilon(); + Vector3D r1 { Rbar(0,0), Rbar(1,0), Rbar(2,0) }; + + // Clamp to avoid NaNs from acos + double dot = std::max(-1.0, std::min(1.0, r1.dot(e[0]))); + + if (std::fabs(dot - 1.0) < ktol) { // Rbar already aligned + v.zero(); + for (int i=0; i<3; i++) { + E(i,0) = e[0][i]; + E(i,1) = Rbar(i,1); + E(i,2) = Rbar(i,2); + } + } + else if (std::fabs(dot + 1.0) < ktol) { // opposite direction + static constexpr double pi = 3.14159265358979323846; + // choose any axis with numerical separation from r1 + v = r1.cross(Vector3D{1.0, 0.0, 0.0}); + if (v.dot(v) < ktol) + v = r1.cross(Vector3D{0.0, 1.0, 0.0}); + v *= pi / v.norm(); + E = ExpSO3(v)*Rbar; + } + else { // general case + v = r1.cross(e[0]); + double angle = std::atan2(v.norm(), dot); + v *= angle / v.norm(); + E = ExpSO3(v)*Rbar; + } + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + e[j][i] = E(i,j); + } + else + { + // Not working with frame-1007? + // + // Use the 'mid-point' procedure + + // e2 = r2 - (e1 + r1)*((r2^e1)*0.5); + + Vector3D tmp; + tmp = e[0]; + tmp += r1; + + e[1] = tmp; + { + e[1] *= 0.5*r2.dot(e[0]); + e[1].addVector(-1.0, r2, 1.0); + } + + // e3 = r3 - (e1 + r1)*((r3^e1)*0.5); + e[2] = tmp; + { + e[2] *= r3.dot(e[0])*0.5; + e[2].addVector(-1.0, r3, 1.0); + } + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + E(i,j) = e[j][i]; + } + + + // + // + // + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + A(i,j) = (double(i==j) - e[0][i]*e[0][j])/Ln; + + return E; + } + + MatrixND<12,12> + getRotationJacobian(const VectorND<12>&pl) final { + MatrixND<12,12> dG{}; + + return dG; + } + + // MatrixND<3,6> getRotationGradient(int node) final; + + MatrixND<3,6> + getRotationGradient(int node) final { + constexpr static Vector3D e1{1, 0, 0}; + + double Ln = this->getLength(); + + static constexpr + MatrixND<1,3> E3 {{0.0, 0.0, 1.0}}, + E2 {{0.0, 1.0, 0.0}}; + + const Matrix3D& Tr = this->getRotation(); + Triad r{Tr^Rbar}; + Vector3D r1 = r[1], r3 = r[3]; + + + Matrix3D A{}; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + A(i,j) = (double(i==j) - e1[i]*e1[j])/Ln; + + MatrixND<3,12> de3; + if constexpr (!orthogonal) + de3 = this->getLMatrix(r3, r1, e1, A).transpose(); + else + de3 = this->getBasisVariation(r3, r1, e1, v, A); + + MatrixND<3,12> de1{}; + de1.template insert<0,0>(A, -1.0); + de1.template insert<0,6>(A, 1.0); + + MatrixND<3,12> G{}; + G.template insert<0,0, 1,12>(E2*de3, -1.0); + G.template insert<1,0, 1,12>(E3*de1, -1.0); + G.template insert<2,0, 1,12>(E2*de1, 1.0); + + if (node == 0) + return G.template extract<0,3, 0, 6>(); + else if (node == nn-1) + return G.template extract<0,3, 6,12>(); + else + return MatrixND<3,6>{}; + + } + + // + // + // + inline MatrixND<12,12> + compute_tangent(const VectorND<12> &ul) + { + // extract columns of rotation matrices + const Vector3D + &e1 = e[0], + &e2 = e[1], + &e3 = e[2], + + &rI1 = rI[0], + &rI2 = rI[1], + &rI3 = rI[2], + &rJ1 = rJ[0], + &rJ2 = rJ[1], + &rJ3 = rJ[2]; + MatrixND<12,3> Lr2,Lr3; + Lr2 = this->getLMatrix(r2, r1, e[0], A); + Lr3 = this->getLMatrix(r3, r1, e[0], A); + // + // + // + MatrixND<12,12> T{}; + + // T1 = [ O', (-S(rI3)*e2 + S(rI2)*e3)', O', O']'; + + // (-S(rI3)*e2 + S(rI2)*e3) + Vector3D rxe = rI2.cross(e3); + rxe -= rI3.cross(e2); + for (int i = 0; i < 3; i++) + T(imx,i+3) = rxe[i]; + + // T2 = [(A*rI2)', (-S(rI2)*e1 + S(rI1)*e2)', -(A*rI2)', O']'; + + Vector3D At = A*rI2; + + // (-S(rI2)*e1 + S(rI1)*e2)' + rxe = rI1.cross(e2); + rxe -= rI2.cross(e1); + for (int i = 0; i < 3; i++) { + T(imz,i ) = At[i]; + T(imz,i+3) = rxe[i]; + T(imz,i+6) = -At[i]; + } + + // T3 = [(A*rI3)', (-S(rI3)*e1 + S(rI1)*e3)', -(A*rI3)', O']'; + + At = A*rI3; + + // -S(rI3)*e1 + S(rI1)*e3 + rxe = rI1.cross(e3); + rxe -= rI3.cross(e1); + for (int i = 0; i < 3; i++) { + T(imy,i ) = - At[i]; + T(imy,i+3) = -rxe[i]; + T(imy,i+6) = At[i]; + } + + // T4 = [ O', O', O', (-S(rJ3)*e2 + S(rJ2)*e3)']'; + rxe = rJ2.cross(e3); + rxe -= rJ3.cross(e2); + for (int i = 0; i < 3; i++) + T(jmx, i+9) = rxe[i]; // S(rJ2)*e3 - S(rJ3)*e2 + + // T5 = [(A*rJ2)', O', -(A*rJ2)', (-S(rJ2)*e1 + S(rJ1)*e2)']'; + At = A*rJ2; + rxe = rJ1.cross(e2); + rxe -= rJ2.cross(e1); + for (int i = 0; i < 3; i++) { + T(jmz, i ) = At[i]; + T(jmz, i+6) = -At[i]; + T(jmz, i+9) = rxe[i]; // (-S(rJ2)*e1 + S(rJ1)*e2) + } + + // T6 = [(A*rJ3)', O', -(A*rJ3)', (-S(rJ3)*e1 + S(rJ1)*e3)']' + At = A*rJ3; + rxe = rJ1.cross(e3); // (-S(rJ3)*e1 + S(rJ1)*e3) + rxe -= rJ3.cross(e1); + for (int i = 0; i < 3; i++) { + T(jmy,i ) = -At[i]; + T(jmy,i+6) = At[i]; + T(jmy,i+9) = -rxe[i]; + } + + // + // Second part + // + + // T(:,1) += Lr3*rI2 - Lr2*rI3; + // T(:,2) += Lr2*rI1; z + // T(:,3) += Lr3*rI1 ; y + + // T(:,4) += Lr3*rJ2 - Lr2*rJ3; + // T(:,5) += Lr2*rJ1 ; z // TODO ?????? check sign + // T(:,6) += Lr3*rJ1 ; y // TODO ?????? check sign + + // Bending Z + for (int i = 0; i < 12; i++) { + double T1i = 0; + for (int k=0; k<3; k++) + T1i += Lr2(i,k)*rI1[k]; + T(imz,i) += T1i; + } + + for (int i = 0; i < 12; i++) { + double T4i = 0; + for (int k=0; k<3; k++) + T4i += Lr2(i,k)*rJ1[k]; // Lr[i]; + T(jmz,i) += T4i; + } + + // Torsion + for (int i = 0; i < 12; i++) { + double T0i = 0; + for (int k=0; k<3; k++) + T0i += Lr3(i,k)*rI2[k] - Lr2(i,k)*rI3[k]; + // T(jmx,i) += -T0i; + T(imx,i) += T0i; + } + for (int i = 0; i < 12; i++) { + double T3i = 0; + for (int k=0; k<3; k++) + T3i += Lr3(i,k)*rJ2[k] - Lr2(i,k)*rJ3[k]; + T(jmx,i) += T3i; + } + // Bending Y + for (int i = 0; i < 12; i++) { + double T2i = 0; + for (int k=0; k<3; k++) + T2i += Lr3(i,k)*rI1[k]; // Lr[i]; + T(imy,i) += T2i*-1; + } + for (int i = 0; i < 12; i++) { + double T5i = 0; + for (int k=0; k<3; k++) + T5i += Lr3(i,k)*rJ1[k]; // Lr[i]; + T(jmy,i) += T5i*-1; + } + + // + // + // + for (int node=0; node < 2; node++) + for (int j = 0; j < 3; j++) { + const double c = 0.5 / std::cos(ul[(node? jmx : imx) + j]); + for (int i = 0; i < 12; i++) + T((node? jmx : imx) + j, i) *= c; + } + + // Axial + // T(:,7) = [-e1' O' e1' O']'; + for (int i = 0; i < 3; i++) { + T(jnx,i ) = -e1[i]; + T(jnx,i+6) = e1[i]; + } + + return T; + } + + + // + // Add geometric part of the transformation tangent + // + // kg += T'*kl*T + ks1 + T * diag(m.*tan(thetal))*T' + // + m(4)*(ks2r2t3_u3 + ks2r3u2_t2) + // + m(2)*ks2r2t1 + m(3)*ks2r3t1 + // + m(5)*ks2r2u1 + m(6)*ks2r3u1 + // + ks3 + ks3' + ks4 + ks5; + // + int addTangent(MatrixND<12,12>& kg, + const VectorND<12>& pl, + const VectorND<12>& ul) + { + const Vector3D + &e1 = e[0], + &e2 = e[1], + &e3 = e[2], + + &rI1 = rI[0], + &rI2 = rI[1], + &rI3 = rI[2], + &rJ1 = rJ[0], + &rJ2 = rJ[1], + &rJ3 = rJ[2]; + + double Ln = this->getLength(); + + // + // Ksigma1 + // + { + const double N = -pl[0]; // Axial force + this->getKs1Matrix(kg, N); + } + + // + // Ksigma3 + // + VectorND<6> m; + m[0] = 0.5*pl[imx]/std::cos(ul(imx)); + m[2] = -0.5*pl[imy]/std::cos(ul(imy)); + m[1] = 0.5*pl[imz]/std::cos(ul(imz)); + + m[3] = 0.5*pl[jmx]/std::cos(ul(jmx)); + m[5] = -0.5*pl[jmy]/std::cos(ul(jmy)); + m[4] = 0.5*pl[jmz]/std::cos(ul(jmz)); + + this->getKs3Matrix(kg, m); + + // + // Ksigma4 + // + { + Matrix3D ks33; + ks33.zero(); + ks33.addSpinProduct(e2, rI3, m[3]); + ks33.addSpinProduct(e3, rI2, -m[3]); + ks33.addSpinProduct(e2, rI1, m[1]); + ks33.addSpinProduct(e1, rI2, -m[1]); + ks33.addSpinProduct(e3, rI1, m[2]); + ks33.addSpinProduct(e1, rI3, -m[2]); + kg.assemble(ks33, 3, 3, 1.0); + } + + { + Matrix3D ks99; + ks99.zero(); + ks99.addSpinProduct(e2, rJ3, -m[3]); + ks99.addSpinProduct(e3, rJ2, m[3]); + ks99.addSpinProduct(e2, rJ1, m[4]); + ks99.addSpinProduct(e1, rJ2, -m[4]); + ks99.addSpinProduct(e3, rJ1, m[5]); + ks99.addSpinProduct(e1, rJ3, -m[5]); + + kg.assemble(ks99, 9, 9, 1.0); + } + + // + // Ksigma5 + // + // Ks5 = [ Ks5_11 Ks5_12 | -Ks5_11 Ks5_14; + // Ks5_12' O | -Ks5_12' O; + // -Ks5_11 -Ks5_12 | Ks5_11 -Ks5_14; + // Ks5_14t O | -Ks5_14' O]; + // + // + // v = (1/Ln)*(m(2)*rI2 + m(3)*rI3 + m(5)*rJ2 + m(6)*rJ3); + // = 1/Ln * (m[1]*rI2 + m[2]*rI3) + // + 1/Ln * (m[4]*rJ2 + m[5]*rJ3); + // = vi + vj + // + { + Vector3D v; + v.addVector(0.0, rI2, m[1]); + v.addVector(1.0, rI3, m[2]); + v.addVector(1.0, rJ2, m[4]); + v.addVector(1.0, rJ3, m[5]); + v /= Ln; + + // Ks5_11 = A*v*e1' + e1*v'*A + (e1'*v)*A; + // = A*vi*e1' + e1*vi'*A + (e1'*vi)*A + // + A*vj*e1' + e1*vj'*A + (e1'*vj)*A; + // + Matrix3D ks33{}; + ks33.addMatrix(A, e1.dot(v)); + + Matrix3D m33{}; + m33.addTensorProduct(v, e1, 1.0); + + ks33.addMatrixProduct(A, m33, 1.0); + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m33(i,j) = e1[i]*v[j]; + + ks33.addMatrixProduct(m33, A, 1.0); + + kg.assemble(ks33, 0, 0, 1.0); + kg.assemble(ks33, 0, 6, -1.0); + kg.assemble(ks33, 6, 0, -1.0); + kg.assemble(ks33, 6, 6, 1.0); + } + + // Ks5_12 = -(m(2)*A*S(rI2) + m(3)*A*S(rI3)); + { + Matrix3D ks33; + ks33.zero(); + ks33.addMatrixSpinProduct(A, rI2, -m[1]); + ks33.addMatrixSpinProduct(A, rI3, -m[2]); + + kg.assemble(ks33, 0, 3, 1.0); + kg.assemble(ks33, 6, 3, -1.0); + kg.assembleTranspose(ks33, 3, 0, 1.0); + kg.assembleTranspose(ks33, 3, 6, -1.0); + + // Ks5_14 = -(m(5)*A*S(rJ2) + m(6)*A*S(rJ3)); + + ks33.zero(); + ks33.addMatrixSpinProduct(A, rJ2, -m[4]); + ks33.addMatrixSpinProduct(A, rJ3, -m[5]); + + kg.assemble(ks33, 0, 9, 1.0); + kg.assemble(ks33, 6, 9, -1.0); + + kg.assembleTranspose(ks33, 9, 0, 1.0); + kg.assembleTranspose(ks33, 9, 6, -1.0); + } + + // Ksigma + + this->getKs2Matrix(kg, r2, rI3-rJ3, m[3]); + this->getKs2Matrix(kg, r3, rJ2-rI2, m[3]); + this->getKs2Matrix(kg, r2, rI1, m[1]); + this->getKs2Matrix(kg, r3, rI1, m[2]); + this->getKs2Matrix(kg, r2, rJ1, m[4]); + this->getKs2Matrix(kg, r3, rJ1, m[5]); + + return 0; + } + + +private: + + inline MatrixND<3,12> + getBasisVariation(const Vector3D &ri, + const Vector3D& r1, + const Vector3D& e1, + const Vector3D& v, + const Matrix3D& A) const noexcept + { + double nu = v.norm(); + Matrix3D L1 = ExpSO3(v)^dExpSO3(v, ri)*Hat(r1)*A; // nu + Matrix3D L2 = ExpSO3(v)^dExpSO3(v, ri)*Hat(e1)*Hat(r1); // nu/2.0 + Matrix3D L3 = Hat(ri); + + MatrixND<3,12> L{}; + // i + L.assemble(L1, 0, 0, -nu); + L.assemble(L2, 0, 3, nu/2.0); + L.assemble(L3, 0, 3, -0.5); + // j + L.assemble(L1, 0, 6, nu); + L.assemble(L2, 0, 9, nu/2.0); + L.assemble(L3, 0, 9, -0.5); + + return L; + } + + [[nodiscard]] inline MatrixND<12,3> + getLMatrix(const Vector3D &ri, + const Vector3D& r1, + const Vector3D& e1, + const Matrix3D& A) const noexcept + { + + static Matrix3D rie1r1; + static Matrix3D e1e1r1; + + const double rie1 = ri.dot(e1); + + for (int k = 0; k < 3; k++) { + const double e1r1k = (e1[k] + r1[k]); + for (int j = 0; j < 3; j++) { + rie1r1(j,k) = ri[j]*e1r1k; + e1e1r1(j,k) = e1[j]*e1r1k; + } + } + + static Matrix3D L1, L2; + // L1 = ri'*e1 * A/2 + A*ri*(e1 + r1)'/2; + L1.zero(); + L1.addMatrix(A, rie1*0.5); + L1.addMatrixProduct(A, rie1r1, 0.5); + + // L2 = Sri/2 - ri'*e1*S(r1)/4 - Sri*e1*(e1 + r1)'/4; + L2.zero(); + L2.addSpin(ri, 0.5); + L2.addSpin(r1, -rie1/4.0); + L2.addSpinMatrixProduct(ri, e1e1r1, -0.25); + + // L = [L1 + // L2 + // -L1 + // L2]; + + MatrixND<12,3> L{}; + L.assemble(L1, 0, 0, 1.0); + L.assemble(L2, 3, 0, 1.0); + L.assemble(L1, 6, 0, -1.0); + L.assemble(L2, 9, 0, 1.0); + + return L; + } + + inline void + getKs1Matrix(MatrixND<12,12> &Kg, double N) const noexcept + { + // a=0 + Kg.assemble(A, 0, 0, N); + Kg.assemble(A, 0, 6, -N); + // a=1 + Kg.assemble(A, 6, 0, -N); + Kg.assemble(A, 6, 6, N); + } + + inline void + getKs3Matrix(MatrixND<12,12> &Kg, const VectorND<6>& m) const noexcept + { + // + // Ksigma3 + // + // ks3 = [o kbar2 | o kbar4]; + // + // where + // + // kbar2 = -Lr2*(m(3)*S(rI3) + m(1)*S(rI1)) + Lr3*(m(3)*S(rI2) - m(2)*S(rI1)) ; + // + // kbar4 = Lr2*(m(3)*S(rJ3) - m(4)*S(rJ1)) - Lr3*(m(3)*S(rJ2) + m(5)*S(rJ1)); + // + // or + // + // ks3 = [o ka+kb | o kc+kd]; + // = [o ka | o kc] + [o kb | o kd]; + // + // where + // + // ka = -Lr2*S(rI3)*m(3) + // +Lr2*S(rI1)*m(1); + // kb = Lr3*S(rI2)*m(3) + // -Lr3*S(rI1)*m(2); + // + // kc = Lr2*S(rJ3)*m(3) + // -Lr2*S(rJ1)*m(4); + // kd = -Lr3*S(rJ2)*m(3) + // +Lr3*S(rJ1)*m(5); + + const Vector3D &rI1 = rI[0], + &rI2 = rI[1], + &rI3 = rI[2], + &rJ1 = rJ[0], + &rJ2 = rJ[1], + &rJ3 = rJ[2]; + + + MatrixND<12,3> Lr2,Lr3; + Lr2 = this->getLMatrix(r2, r1, e[0], A); + Lr3 = this->getLMatrix(r3, r1, e[0], A); + + Matrix3D Sm{}; + Sm.addSpin(rI3, m[3]); + Sm.addSpin(rI1, m[1]); + static MatrixND<12,3> kbar; + kbar.zero(); + kbar.addMatrixProduct(Lr2, Sm, -1.0); + + Sm.zero(); + Sm.addSpin(rI2, m[3]); + Sm.addSpin(rI1, -m[2]); + kbar.addMatrixProduct(Lr3, Sm, 1.0); + + Kg.assemble(kbar, 0, 3, 1.0); + Kg.assembleTranspose(kbar, 3, 0, 1.0); + + Sm.zero(); + Sm.addSpin(rJ3, m[3]); + Sm.addSpin(rJ1, -m[4]); + kbar.zero(); + kbar.addMatrixProduct(Lr2, Sm, 1.0); + + Sm.zero(); + Sm.addSpin(rJ2, m[3]); + Sm.addSpin(rJ1, m[5]); + kbar.addMatrixProduct(Lr3, Sm, -1.0); + + Kg.assemble(kbar, 0, 9, 1.0); + Kg.assembleTranspose(kbar, 9, 0, 1.0); + } + + inline void + getKs2Matrix(MatrixND<12,12> &Kg, + const Vector3D &ri, + const Vector3D &z, + double scale) const noexcept + { + const Vector3D &e1 = e[0]; + + const double Ln = this->getLength(); + + // Ksigma2 = [ K11 K12 -K11 K12 + // K12' K22 -K12' K22 + // -K11 -K12 K11 -K12 + // K12' K22 -K12' K22]; + + // U = (-1/2)*A*z*ri'*A + ri'*e1*A*z*e1'/(2*Ln)+... + // z'*(e1+r1)*A*ri*e1'/(2*Ln); + + const double rite1 = ri.dot(e1); + const double zte1 = z.dot(e1); + const double ztr1 = z.dot(r1); + + static Matrix3D zrit, ze1t; + static Matrix rizt(3,3), rie1t(3,3); + static Matrix3D e1zt; + + // const Matrix3D e1zt = e1.bun(z); + + // Chrystal's looping order + for (int j = 0; j < 3; j++) { + for (int i = 0; i < 3; i++) { + zrit(i,j) = z[i]*ri[j]; + rizt(i,j) = ri[i]*z[j]; + ze1t(i,j) = z[i]*e1[j]; + e1zt(i,j) = e1[i]*z[j]; + rie1t(i,j) = ri[i]*e1[j]; + } + } + + Matrix3D U; + U.addMatrixTripleProduct(0.0, A, zrit, -0.5); + U.addMatrixProduct(A, ze1t, rite1/(2*Ln)); + U.addMatrixProduct(A, rie1t, (zte1 + ztr1)/(2*Ln)); + + + // K11 = U + U' + ri'*e1*(2*(e1'*z)+z'*r1)*A/(2*Ln); + + Matrix3D ks{}; + ks.addMatrix(U, 1.0); + + // Add matrix U transpose + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + ks(i,j) += U(j,i); + + ks.addMatrix(A, rite1*(2*zte1 + ztr1)/(2*Ln)); + + Kg.assemble(ks, 0, 0, scale); + Kg.assemble(ks, 0, 6, -scale); + Kg.assemble(ks, 6, 0, -scale); + Kg.assemble(ks, 6, 6, scale); + + // K12 = (1/4)*(-A*z*e1'*Sri - A*ri*z'*Sr1 - z'*(e1+r1)*A*Sri); + Matrix3D m1{}; + m1.addMatrixProduct(A, ze1t, -1.0); + ks.zero(); + ks.addMatrixSpinProduct(m1, ri, 0.25); + + m1.zero(); + m1.addMatrixProduct(A, rizt, -1.0); + ks.addMatrixSpinProduct(m1, r1, 0.25); + ks.addMatrixSpinProduct(A, ri, -0.25*(zte1+ztr1)); + + Kg.assemble(ks, 0, 3, scale); + Kg.assemble(ks, 0, 9, scale); + Kg.assemble(ks, 6, 3, -scale); + Kg.assemble(ks, 6, 9, -scale); + + Kg.assembleTranspose(ks, 3, 0, scale); + Kg.assembleTranspose(ks, 3, 6, -scale); + Kg.assembleTranspose(ks, 9, 0, scale); + Kg.assembleTranspose(ks, 9, 6, -scale); + + // K22 = (1/8)*((-ri'*e1)*Sz*Sr1 + Sr1*z*e1'*Sri + ... + // Sri*e1*z'*Sr1 - (e1+r1)'*z*S(e1)*Sri + 2*Sz*Sri); + + ks.zero(); + ks.addSpinProduct(z, r1, -0.125*(rite1)); + + m1.zero(); + m1.addSpinMatrixProduct( r1, ze1t, 1.0); + ks.addMatrixSpinProduct( m1, ri, 0.125); + + m1.zero(); + m1.addSpinMatrixProduct(ri, e1zt, 1.0); + ks.addMatrixSpinProduct(m1, r1, 0.125); + + ks.addSpinProduct(e1, ri, -0.125*(zte1 + ztr1)); + ks.addSpinProduct( z, ri, 0.25); + + // Ksigma2 = [ K11 K12 -K11 K12; + // K12t K22 -K12t K22; + // -K11 -K12 K11 -K12; + // K12t K22 -K12t K22]; + + Kg.assemble(ks, 3, 3, scale); + Kg.assemble(ks, 3, 9, scale); + Kg.assemble(ks, 9, 3, scale); + Kg.assemble(ks, 9, 9, scale); + } + + +private: + + enum { + inx= 0, // axial + iny= 1, // Vy + inz= 2, // Vz + imx= 3, // torsion + imy= 4, // rot y I + imz= 5, // rot z I + + jnx= 6, // axial + jny= 7, + jnz= 8, + jmx= 9, // torsion + jmy=10, // rot y J + jmz=11, // rot z J + }; + + Matrix3D A; + Matrix3D Rbar; + Vector3D v; + Vector3D r1, r2, r3; + Vector3D e[3], rI[3], rJ[3]; + // MatrixND<12,3> Lr2, Lr3; + // double Ln; +}; +} diff --git a/SRC/coordTransformation/Frame/Isometry/EuclidIsometry.h b/SRC/coordTransformation/Frame/Isometry/EuclidIsometry.h new file mode 100644 index 0000000000..733cfc9392 --- /dev/null +++ b/SRC/coordTransformation/Frame/Isometry/EuclidIsometry.h @@ -0,0 +1,241 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// +// +// Written: Claudio M. Perez +// +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +namespace OpenSees { + +template +class Isometry +{ +public: + virtual int initialize(std::array& nodes) =0; + virtual int update(std::array& nodes) =0; + + virtual int update(const Matrix3D& RI, + const Matrix3D& RJ, const Vector3D& dx, + std::array& nodes) =0; + + virtual double getLength() const =0; + + virtual Matrix3D getRotation() const =0; + virtual Vector3D getPosition() =0; + + virtual Vector3D getPositionVariation(int ndf, double* du) =0; + virtual Vector3D getRotationVariation(int ndf, double* du) =0; + virtual MatrixND<12,12> getRotationJacobian(const VectorND<12>&pl) { + return MatrixND<12,12> {}; + } + virtual Matrix3D getRotationDelta() =0; + virtual MatrixND<3,6> getRotationGradient(int node) =0; +}; + + +template +class AlignedIsometry : public Isometry +{ +public: + + AlignedIsometry(const Vector3D& vecxz) + : vz(vecxz), Xc{}, c{}, R{} + { + } + + void + setOffsets(std::array* offsets) { + this->offsets = offsets; + } + + + virtual int + initialize(std::array& nodes) final + { + for (int i=0; igetTrialRotation(); + + const Vector &XI = nodes[ 0]->getCrds(); + const Vector &XJ = nodes[nn-1]->getCrds(); + + for (int i=0; i<3; i++) + dX[i] = XJ[i] - XI[i]; + + L = dX.norm(); + Ln = L; + Vector3D e1 = dX/L; + + // + Vector3D e2 = vz.cross(e1); + + const double ynorm = e2.norm(); + + if (ynorm == 0.0) + return -1; + + e2 /= ynorm; + + Vector3D e3 = e1.cross(e2); + + e2 = e3.cross(e1); + + for (int i = 0; i < 3; i++) { + R[init](i,0) = e1[i]; + R[init](i,1) = e2[i]; + R[init](i,2) = e3[i]; + } + + Xc = nodes[ic]->getCrds(); + c[init] = R[init]^Xc; + + return this->update(nodes); + } + + virtual + int update(std::array& nodes) final { + Matrix3D RI = MatrixFromVersor(nodes[0]->getTrialRotation()); + Matrix3D RJ = MatrixFromVersor(nodes[nn-1]->getTrialRotation()); + + Vector3D dx = dX; + // + // Update position + // + { + const Vector& uI = nodes[ 0]->getTrialDisp(); + const Vector& uJ = nodes[nn-1]->getTrialDisp(); + for (int k = 0; k < 3; k++) + dx[k] += uJ(k) - uI(k); + + if (offsets != nullptr) [[unlikely]] { + dx.addVector(1.0, (*offsets)[ 0], 1.0); + dx.addVector(1.0, RI*((*offsets)[0]), -1.0); + dx.addVector(1.0, (*offsets)[nn-1], -1.0); + dx.addVector(1.0, RJ*((*offsets)[nn-1]), 1.0); + } + } + + return this->update(RI, RJ, dx, nodes); + } + + + int + update(const Matrix3D& RI, const Matrix3D& RJ, const Vector3D& dx, std::array& nodes) final + { + // Calculate the deformed length + Ln = dx.norm(); + + if (Ln == 0.0) [[unlikely]] { + opserr << "\nSouzaFrameTransf: deformed length is 0.0\n"; + return -2; + } + + // + // + // + R[pres] = this->update_basis(RI, RJ, dx); + + // + // + // + Vector3D uc = nodes[ic]->getTrialDisp(); + if (offsets != nullptr) { + uc.addVector(1.0, (*offsets)[ic], -1.0); + uc.addVector(1.0, nodes[ic]->getTrialRotation().rotate((*offsets)[ic]), 1.0); + } + + c[pres] = R[pres]^(Xc + uc); + return 0; + } + + virtual Vector3D + getRotationVariation(int ndf, double* du) final { + // psi_r = omega + Vector3D w{}; + for (int i=0; igetRotationGradient(i); + for (int j=0; j<3; j++) + for (int k=0; k<6; k++) + w[j] += Wi(j,k) * du[ndf*i + k]; + } + return w; + } + + double + getLength() const override { + return Ln; + } + + Matrix3D + getRotation() const final { + return R[pres]; + } + + Matrix3D + getInitialRotation() const { + return R[init]; + } + + virtual Matrix3D + getRotationDelta() { + return R[pres] - R[init]; + } + + Vector3D + getLocation() { + return c[pres]; + } + + virtual Vector3D + getPosition() { + // Return Delta c + Vector3D Dc = c[pres] - (R[init]^Xc) ; // (R[pres]^c[init]); + return Dc; + } + + virtual Vector3D + getPositionVariation(int ndf, double* du) { + return Vector3D {du[ndf*ic+0], du[ndf*ic+1], du[ndf*ic+2]}; + } + + virtual + Matrix3D + update_basis(const Matrix3D& RI, const Matrix3D& RJ, const Vector3D& dx) = 0; + +protected: + constexpr static int ic = 0; // std::floor(0.5*(nn+1)); + enum {pres, init}; + double L, Ln; + Vector3D vz, dX, Xc; + Matrix3D R[2]; + Vector3D c[2]; + Matrix3D dR; + std::array* offsets = nullptr; // offsets +}; + +} // namespace OpenSees diff --git a/SRC/coordTransformation/Frame/Isometry/LinearIsometry.h b/SRC/coordTransformation/Frame/Isometry/LinearIsometry.h new file mode 100644 index 0000000000..bf37ad2e22 --- /dev/null +++ b/SRC/coordTransformation/Frame/Isometry/LinearIsometry.h @@ -0,0 +1,91 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// Written: Claudio M. Perez, +// Filip C. Filippou +// University of California, Berkeley +// +// Developed with FEDEASLab [2]. +// +// References: +// +// [1] Perez, C.M., and Filippou F.C. (2024) +// "On Nonlinear Geometric Transformations of Finite Elements" +// Int. J. Numer. Meth. Engrg.; https://doi.org/10.1002/nme.7506 +// +// [2] Filippou, F.C. (1998) +// "FEDEASLab: Finite Elements for Design Evaluation and Analysis of Structures" +// +// [3] Nour-Omid, B. and Rankin, C.C. (1991) "Finite rotation analysis and +// consistent linearization using projectors", +// Computer Methods in Applied Mechanics and Engineering, 93(3), pp. 353–384. +// Available at: https://doi.org/10.1016/0045-7825(91)90248-5. +// +#pragma once +#include +#include +#include +#include "EuclidIsometry.h" + +class Node; +#define TRIAD C2 + +namespace OpenSees { + +template +class LinearIsometry : public AlignedIsometry +{ +public: + LinearIsometry(const Vector3D& vecxz) + : AlignedIsometry(vecxz) + { + } + + Matrix3D + update_basis(const Matrix3D&, const Matrix3D&, const Vector3D&) final + { + return this->AlignedIsometry::R[init]; + } + + MatrixND<3,6> + getRotationGradient(int node) final { + MatrixND<3,6> Gb{}; + + constexpr Matrix3D ix = Hat(Vector3D {1, 0, 0}); + + const double Ln = this->getLength(); + + if (node == 0) { + Gb.template insert<0,0>( ix, -1.0/Ln); + Gb(0,3) = 0.5; + } + else if (node == nn-1) { + Gb.template insert<0,0>( ix, 1.0/Ln); + Gb(0,3) = 0.5; + } + return Gb; + } +private: + using AlignedIsometry::init; + double L; +}; +} // namespace OpenSees \ No newline at end of file diff --git a/SRC/coordTransformation/Frame/Isometry/RankinIsometry.h b/SRC/coordTransformation/Frame/Isometry/RankinIsometry.h new file mode 100644 index 0000000000..5bfe8bab5f --- /dev/null +++ b/SRC/coordTransformation/Frame/Isometry/RankinIsometry.h @@ -0,0 +1,209 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// Written: Claudio M. Perez, +// Filip C. Filippou +// University of California, Berkeley +// +// Developed with FEDEASLab [2]. +// +// References: +// +// [1] Perez, C.M., and Filippou F.C. (2024) +// "On Nonlinear Geometric Transformations of Finite Elements" +// Int. J. Numer. Meth. Engrg.; https://doi.org/10.1002/nme.7506 +// +// [2] Filippou, F.C. (1998) +// "FEDEASLab: Finite Elements for Design Evaluation and Analysis of Structures" +// +// [3] Nour-Omid, B. and Rankin, C.C. (1991) "Finite rotation analysis and +// consistent linearization using projectors", +// Computer Methods in Applied Mechanics and Engineering, 93(3), pp. 353–384. +// Available at: https://doi.org/10.1016/0045-7825(91)90248-5. +// +#pragma once +#include +#include +#include +#include "EuclidIsometry.h" + +class Node; + +namespace OpenSees { + +template +class RankinIsometry : public AlignedIsometry +{ +public: + RankinIsometry(const Vector3D& vecxz) + : AlignedIsometry(vecxz), + n(0) + { + } + + using AlignedIsometry::init; + using AlignedIsometry::pres; + + Matrix3D + update_basis(const Matrix3D& RI, const Matrix3D& RJ, const Vector3D& dx) final + { + Matrix3D R; + { + Vector3D e1 = dx; + e1 /= e1.norm(); + + constexpr static Vector3D D2 {0,1,0}; + const Vector3D E2 = this->AlignedIsometry::R[init]*D2; + q = RI*E2; + Vector3D e3 = e1.cross(q); + e3 /= e3.norm(); + + Vector3D e2 = e3.cross(e1); + + for (int i = 0; i < 3; i++) { + R(i,0) = e1[i]; + R(i,1) = e2[i]; + R(i,2) = e3[i]; + } + + Vector3D Q = R^q; + n = Q[0]/Q[1]; + } + return R; + } + + + MatrixND<12,12> + getRotationJacobian(const VectorND<12>&pwx) final + { + MatrixND<3,12> NWL{}; + const double Ln = this->getLength(); + + constexpr static Matrix3D ex = Hat(Vector3D {1,0,0}); + + for (int i=0; i= 202000L + static constinit MatrixND<12,3> Gamma = MakeGamma(); + static constinit MatrixND<12,3> Psi0 = MakePsi(); + MatrixND<12,3> Psi = Psi0; + Psi.template insert<6,0>(ex, -Ln); +#else + MatrixND<12,3> Gamma{}; + Gamma.template insert<0,0>(ex, 1.0); + Gamma(3,0) = -1.0; + Gamma.template insert<6,0>(ex, -1.0); + + MatrixND<12,3> Psi{}; + Psi.template insert<3,0>(Eye3, 1.0); + Psi.template insert<6,0>(ex, -Ln); + Psi.template insert<9,0>(Eye3, 1.0); +#endif + Matrix3D B = Gamma^Psi; + Matrix3D A; + B.invert(A); + return Gamma*A.transpose()*NWL; + } + + MatrixND<3,6> + getBasisVariation(int ie, int node) + { + MatrixND<3,6> dei{}; + if (ie == 1) { + Matrix3D A{}; + A(1,1) = A(2,2) = 1.0/this->getLength(); + if (node == 0) { + dei.template insert<0,0>(A, -1.0); + } + else if (node == nn-1) { + dei.template insert<0,0>(A, 1.0); + } + } + + else if (ie == 3) { + Matrix3D A{}; + Vector3D q = this->getRotation()^this->q; + Vector3D v = q.cross(Vector3D{1,0,0}); + + A(0,0) = A(1,1) = 1.0/v.norm(); + Matrix3D Q = Hat(q); + dei = A*( + Hat(Vector3D{1,0,0})*Q + +Q*this->getBasisVariation(1, node) + ); + } + return dei; + } + + MatrixND<3,6> + getRotationGradient(int node) final { + MatrixND<3,6> Gb{}; + + constexpr Vector3D axis{1, 0, 0}; + constexpr Matrix3D ix = Hat(axis); + + const double Ln = this->getLength(); + + if (node == 0) { + Gb.template insert<0,0>( ix, -1.0/Ln); + Gb(0,2) = n/Ln; + Gb(0,3) = 1.0; + Gb(0,4) = -n; + } + else if (node == nn-1) { + Gb.template insert<0,0>( ix, 1.0/Ln); + Gb(0,2) = -n/Ln; + Gb(0,3) = 0.0; + } + return Gb; + } + +private: + Vector3D q; + double n = 0; + + +#if __cplusplus >= 202000L + static inline consteval MatrixND<12,3> + MakePsi() + { + MatrixND<12,3> Psi{}; + Psi.template insert<3,0>(Eye3, 1.0); + Psi.template insert<9,0>(Eye3, 1.0); + return Psi; + } + + static inline consteval MatrixND<12,3> + MakeGamma() + { + MatrixND<12,3> Gamma{}; + constexpr Matrix3D ex = Hat(Vector3D {1,0,0}); + Gamma.template insert<0,0>(ex, 1.0); + Gamma(3,0) = -1.0; + Gamma.template insert<6,0>(ex, -1.0); + return Gamma; + } +#endif + +}; +} // namespace OpenSees \ No newline at end of file diff --git a/SRC/coordTransformation/Frame/Isometry/SphericalIsometry.h b/SRC/coordTransformation/Frame/Isometry/SphericalIsometry.h new file mode 100644 index 0000000000..bb704a7757 --- /dev/null +++ b/SRC/coordTransformation/Frame/Isometry/SphericalIsometry.h @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// Written: Claudio M. Perez, +// Filip C. Filippou +// University of California, Berkeley +// +// Developed with FEDEASLab [2]. +// +// References: +// +// [1] Perez, C.M., and Filippou F.C.. (2024) +// "On Nonlinear Geometric Transformations of Finite Elements" +// Int. J. Numer. Meth. Engrg.; https://doi.org/10.1002/nme.7506 +// +// [2] Filippou, F.C. (1998) +// "FEDEASLab: Finite Elements for Design Evaluation and Analysis of Structures" +// +#pragma once +#include +#include +#include +#include +#include "EuclidIsometry.h" + +template +class SphericalIsometry : public Isometry { +public: + SphericalIsometry(std::array& nodes, const Vector3D& vecxz); + + int initialize() final; + int update() final; + + double getLength() const final; + Matrix3D getRotation() const final; + Vector3D getPosition() final; + Vector3D getPositionVariation(int ndf, double* du) final; + Vector3D getRotationVariation(int ndf, double* du) final; + Matrix3D getRotationDelta() final; + MatrixND<3,6> getRotationGradient(int node) final; +private: + double L; + double Ln; + std::array nodes; + Vector3D vz; // vector in the x-z plane + Vector3D dX; // deformed length vector + Vector3D c[2]; // current position of the center + Matrix3D R[2]; // rotation matrices at the current and previous time step + Vector3D Xc; // center of the isometry +}; + + +template +SphericalIsometry::SphericalIsometry(std::array& nodes, const Vector3D& vecxz) +: nodes(nodes), vz(vecxz), Xc{}, + c{}, R{}, dX{}, Ln(0.0), L(0.0), + offsets(nullptr), offset_flags(0), ic(0) +{ + +} + + +template +int +SphericalIsometry::update() { + + Vector3D e1 = dX; + { + // + // Update state + // + const Vector& uI = nodes[ 0]->getTrialDisp(); + const Vector& uJ = nodes[nn-1]->getTrialDisp(); + for (int k = 0; k < 3; k++) + e1[k] += uJ(k) - uI(k); + + if (offsets != nullptr) [[unlikely]] { + e1.addVector(1.0, (*offsets)[ 0], 1.0); + e1.addVector(1.0, nodes[0]->getTrialRotation().rotate((*offsets)[0]), -1.0); + e1.addVector(1.0, (*offsets)[nn-1], -1.0); + e1.addVector(1.0, nodes[nn-1]->getTrialRotation().rotate((*offsets)[nn-1]), 1.0); + } + + // Calculate the deformed length + Ln = e1.norm(); + + if (Ln == 0.0) [[unlikely]] { + opserr << "\nSouzaFrameTransf: deformed length is 0.0\n"; + return -2; + } + + e1 /= Ln; + } + + { + constexpr static Vector3D D2 {0,1,0}; + const Vector3D E2 = R[init]*D2; + Vector3D e2 = MatrixFromVersor(nodes[0]->getTrialRotation())*E2; //*R[init]; + e2.addVector(0.5, MatrixFromVersor(nodes[1]->getTrialRotation())*E2, 0.5); + n = e2[0]/e2[1]; + Vector3D e3 = e1.cross(e2); + e3 /= e3.norm(); + + e2 = e3.cross(e1); + + for (int i = 0; i < 3; i++) { + R[pres](i,0) = e1[i]; + R[pres](i,1) = e2[i]; + R[pres](i,2) = e3[i]; + } + Vector3D e2 = vz.cross(e1); + } + + Vector3D uc = nodes[ic]->getTrialDisp(); + if (offsets != nullptr) { + uc.addVector(1.0, (*offsets)[ic], -1.0); + uc.addVector(1.0, nodes[ic]->getTrialRotation().rotate((*offsets)[ic]), 1.0); + } + Vector3D X = nodes[ic]->getCrds(); + c[pres] = R[pres]^(X + uc); + return 0; +} \ No newline at end of file diff --git a/SRC/coordTransformation/Frame/LinearFrameTransf.h b/SRC/coordTransformation/Frame/LinearFrameTransf.h new file mode 100644 index 0000000000..b2d845366f --- /dev/null +++ b/SRC/coordTransformation/Frame/LinearFrameTransf.h @@ -0,0 +1,157 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resources in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// Description: LinearFrameTransf implements a linearized euclidean transformation +// for a spatial frame +// +// Written: Claudio Perez +// +// References: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +// Haukaas, Terje, and Michael H. Scott. +// “Shape Sensitivities in the Reliability Analysis of Nonlinear Frame Structures.” +// Computers & Structures 84, nos. 15–16 (2006): 964–77. +// https://doi.org/10.1016/j.compstruc.2006.02.014. +// +// Scott, Michael H., Paolo Franchin, Gregory L. Fenves, and Filip C. Filippou. +// “Response Sensitivity for Nonlinear Beam–Column Elements.” +// Journal of Structural Engineering 130, no. 9 (2004): 1281–88. +// https://doi.org/10.1061/(asce)0733-9445(2004)130:9(1281). +// +#ifndef LinearFrameTransf_hpp +#define LinearFrameTransf_hpp + +#include +#include +#include +#include + +namespace OpenSees { + +template +class LinearFrameTransf: public FrameTransform +{ +public: + constexpr static int n = nn*ndf; + + LinearFrameTransf(int tag, + const Vector3D &vecxz, + const std::array *offset=nullptr, + int offset_flags = 0); + + ~LinearFrameTransf(); + + + const char *getClassType() const {return "LinearFrameTransf";} + + virtual int getLocalAxes(Vector3D &x, Vector3D &y, Vector3D &z) const; + + virtual FrameTransform *getCopy() const; + + double getInitialLength() final; + double getDeformedLength() final; + const std::array *getRigidOffsets() const final {return offsets;} + + int initialize(std::array& new_nodes) final; + int update() final; + int commit() final; + int revertToLastCommit() final; + int revertToStart() final; + + Vector3D getNodePosition(int tag) final; + Vector3D getNodeRotationLogarithm(int tag) final; + VectorND getStateVariation() final; + + using Operation = typename FrameTransform::Operation; + + int push(VectorND&pl, Operation) final; + int push(MatrixND& kl, const VectorND& pl, Operation) final; + + + // Sensitivity + // + void pushGrad(VectorND& dp, VectorND& pl) override; + void pullFixedGrad(VectorND&) override; + void pullTotalGrad(VectorND&, int) override; + bool isShapeSensitivity() final; + double getLengthGrad() final; + double getd1overLdh() final; + + // TaggedObject + void Print(OPS_Stream &s, int flag) final; + + // Personal + Vector3D getDelta() {return Du;} + +private: + + inline int + pull(VectorND& ug, + const Matrix3D& R, + const std::array *offset = nullptr, + int offset_flags = 0); + + + template + const Vector3D + pullPosition(int node) + { + const Vector &u = (nodes[node]->*Getter)(); + + Vector3D v; + for (int i=0; i<3; i++) + v[i] = u[i]; + + // 1) Offsets + if (offsets) { + if (!(offset_flags&OffsetLocal)) { + Vector3D w {u[3], u[4], u[5]}; + v -= offsets->at(node).cross(w); + } + } + + // 2) Constant Rotation + return R^v; + } + + std::array nodes; + Vector3D Du, ur[nn]; + + std::array *offsets; + int offset_flags; + + Vector3D xi, xj, vz; + Matrix3D R; // rotation matrix + double L; // undeformed element length + + std::array*, nn> u_init; + bool initialDispChecked; +}; +} + +#include "LinearFrameTransf.tpp" +#endif + diff --git a/SRC/coordTransformation/Frame/LinearFrameTransf.tpp b/SRC/coordTransformation/Frame/LinearFrameTransf.tpp new file mode 100644 index 0000000000..72650b7d5c --- /dev/null +++ b/SRC/coordTransformation/Frame/LinearFrameTransf.tpp @@ -0,0 +1,688 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// Description: LinearFrameTransf is a linear +// transformation for a space frame between the global +// and basic coordinate systems +// +// Written: Claudio M. Perez +// +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include "LinearFrameTransf.h" + +namespace OpenSees { + +static inline MatrixND<3,3> +FrameOrientationGradient(const Vector3D& xi, + const Vector3D& xj, + const Vector3D& vz, + int di, int dj, int dv) +{ + Vector3D v1 = xj - xi; + const double L = v1.norm(); + Vector3D e1 = v1/L; + + Vector3D v2 = vz.cross(e1); + + Vector3D e2 = v2 / v2.norm(); + + // + Vector3D dvz{0.0}; + Vector3D dxi{0.0}; + Vector3D dxj{0.0}; + + if (di != 0) + dxi(di-1) = 1.0; + if (dj != 0) + dxj(dj-1) = 1.0; + if (dv != 0) + dvz(dv-1) = 1.0; + + double dL = 1/L*(xj - xi).dot(dxj - dxi); + Vector3D dv1 = dxj - dxi; + Vector3D de1 = 1/(L*L)*(dv1*L - v1*dL); + + double L2 = v2.norm(); + Vector3D dv2 = dvz.cross(e1) + vz.cross(de1); + double dL2 = 1/L2*v2.dot(dv2); + Vector3D de2 = 1/(L2*L2)*(dv2*L2 - v2*dL2); + + Vector3D de3 = de1.cross(e2) + e1.cross(de2); + + MatrixND<3,3> dR; + dR(0,0) = de1(0); + dR(1,0) = de1(1); + dR(2,0) = de1(2); + + dR(0,1) = de2(0); + dR(1,1) = de2(1); + dR(2,1) = de2(2); + + dR(0,2) = de3(0); + dR(1,2) = de3(1); + dR(2,2) = de3(2); + + return dR; +} + +template +LinearFrameTransf::LinearFrameTransf(int tag, + const Vector3D &vecxz, + const std::array *offset, + int offset_flags) + : FrameTransform(tag), + Du{}, + ur{}, + L(0.0), + offsets{nullptr}, + offset_flags(offset_flags), + u_init{nullptr}, + initialDispChecked(false) +{ + R.zero(); + + for (int i=0; i<3; i++) + vz[i] = vecxz[i]; + + R(0,2) = vz(0); + R(1,2) = vz(1); + R(2,2) = vz(2); + + // Rigid joint offsets + if (offset != nullptr) { + offsets = new std::array{}; + *offsets = *offset; + } +} + + + +template +LinearFrameTransf::~LinearFrameTransf() +{ + if (offsets != nullptr) + delete offsets; + + for (int i=0; i +int +LinearFrameTransf::commit() +{ + return 0; +} + + +template +int +LinearFrameTransf::revertToLastCommit() +{ + return 0; +} + +template +int +LinearFrameTransf::revertToStart() +{ + return 0; +} + + +template +int +LinearFrameTransf::initialize(std::array& new_nodes) +{ + + for (int i=0; igetDisp(); + + for (int j = 0; j < ndf; j++) + if (u(j) != 0.0) { + u_init[i] = new VectorND{}; + for (int l = 0; l < ndf; l++) + (*u_init[i])[l] = u(l); + // break out + j = ndf; + } + } + initialDispChecked = true; + } + + { + const Vector &XI = nodes[ 0]->getCrds(); + const Vector &XJ = nodes[nn-1]->getCrds(); + + for (int i=0; i<3; i++) { + xi[i] = XI[i]; + xj[i] = XJ[i]; + } + + Vector3D dx = xj - xi; + + if (offsets != nullptr) { + for (int i=0; i<3; i++) + dx(i) -= (*offsets)[ 0][i]; + for (int i=0; i<3; i++) + dx(i) += (*offsets)[nn-1][i]; + } + + + if (u_init[0] != 0) { + for (int i=0; i<3; i++) + dx(i) -= (*u_init[0])[i]; + } + + if (u_init[nn-1] != 0) { + for (int i=0; i<3; i++) + dx(i) += (*u_init[nn-1])[i]; + } + + L = dx.norm(); + + if (L == 0.0) + return -2; + + return FrameTransform::Orient(dx, vz, R); + } +} + + +template +int +LinearFrameTransf::getLocalAxes(Vector3D &e1, Vector3D &e2, Vector3D &e3) const +{ + for (int i = 0; i < 3; i++) { + e1[i] = R(i,0); + e2[i] = R(i,1); + e3[i] = R(i,2); + } + return 0; +} + +template +double +LinearFrameTransf::getInitialLength() +{ + return L; +} + +template +double +LinearFrameTransf::getDeformedLength() +{ + return L+Du[0]; +} + + +// +// Pull +// + +template +int +LinearFrameTransf::update() +{ + constexpr Vector3D iv{1, 0, 0}; + + Du = this->pullPosition<&Node::getTrialDisp>(nn-1); + Du -= this->pullPosition<&Node::getTrialDisp>(0); + + for (int node =0 ; node < nn; node++) { + const Vector& u = nodes[node]->getTrialDisp(); + for (int i=0; i<3; i++) { + ur[node][i] = 0; + for (int j=0; j<3; j++) + ur[node][i] += R(j,i) * u[3+j]; + } + + ur[node].addCrossProduct(iv, Du, -1.0/L); + } + return 0; +} + + +template +int +LinearFrameTransf::pull(VectorND& ul, + const Matrix3D& R, + const std::array *offset, + int offset_flags) +{ + + // (1) + + // (2) Global offsets + // + // Do ui -= ri x wi + if constexpr (ndf >= 6) + if (offset && !(offset_flags&OffsetLocal)) [[unlikely]] { + const std::array& offsets = *offset; + for (int i=0; i= 6) + if (offset && (offset_flags&OffsetLocal)) [[unlikely]] { + const std::array& offsets = *offset; + for (int i=0; i2) + constexpr static Vector3D iv {1,0,0}; + Vector3D uI = ul.template extract<3>(0); + Vector3D Du = ul.template extract<3>((nn-1)*ndf) - uI; + Vector3D ixDu = iv.cross(Du); + for (int i=0; i +VectorND +LinearFrameTransf::getStateVariation() +{ + VectorND ug; + for (int i=0; igetIncrDeltaDisp(); + for (int j = 0; j < ndf; j++) { + ug[i*ndf+j] = ddu(j); + } + } + LinearFrameTransf::pull(ug, R, offsets, offset_flags); + return ug; +} + + +template +Vector3D +LinearFrameTransf::getNodePosition(int node) +{ + Vector3D v{}; + if (node == nn-1) { + v[0] = Du[0]; + } + // TODO(nn>2) + return v; +} + + +template +Vector3D +LinearFrameTransf::getNodeRotationLogarithm(int node) +{ + return ur[node]; +} + + +// +// Push +// +template +int +LinearFrameTransf::push(VectorND&p, Operation op) +{ + VectorND pa = p; // NOTE + constexpr Vector3D iv{1, 0, 0}; + + // 1.1) Sum of moments: m = sum_i mi + sum_i (xi x ni) + Vector3D m{}; + for (int i=0; iFrameTransform::pushConstant(pa); + return 0; +} + +template +int +LinearFrameTransf::push(MatrixND&kb, + const VectorND&, + Operation op) +{ + + static constexpr Vector3D axis{1, 0, 0}; + static constexpr Matrix3D ix = Hat(Vector3D{1, 0, 0}); + static constexpr Matrix3D ioi = axis.bun(Vector3D{1, 0, 0}); + const Matrix3D RT = R.transpose(); + const Matrix3D ixRT = ix*RT; + + MatrixND A{}; + if constexpr (ndf > 6) + A.addDiagonal(1.0); + + { + MatrixND<3,ndf> Gb{}; + Gb.template insert<0, 3>(ioi*RT, 0.5); + Repeat ([&](auto a_) { + constexpr static int a = a_.value; + A.template insert(RT); + A.template insert(RT); + Repeat ([&](auto b_) { + constexpr static int b = b_.value; + + // TODO(nn>2): Interpolate coordinate + if constexpr (b == 0) + Gb.template insert<0,0>(ixRT, -1/L); + else if constexpr (b == nn-1) + Gb.template insert<0,0>(ixRT, 1/L); + + // TODO(nn>2): Interpolate coordinate + A.assemble(ix*Gb, a*ndf , b*ndf, double(a)/double(nn-1)*L); + A.assemble( Gb, a*ndf+3, b*ndf, -1.0); + }); + }); + } + + // MatrixND kl = kb; + const MatrixND KA = kb*A; + kb.addMatrixTransposeProduct(0.0, A, KA, 1.0); + + if (offsets != nullptr) [[unlikely]] + this->pushOffsets(kb, *offsets); + + return 0; +} + + +template +FrameTransform * +LinearFrameTransf::getCopy() const +{ + + Vector3D xz; + xz(0) = R(0,2); + xz(1) = R(1,2); + xz(2) = R(2,2); + + LinearFrameTransf *theCopy = new LinearFrameTransf(this->getTag(), xz, offsets); + + theCopy->nodes = nodes; + theCopy->L = L; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + theCopy->R(j,i) = R(j,i); + + return theCopy; +} + + +// +// Sensitivity +// +template +bool +LinearFrameTransf::isShapeSensitivity() +{ + int nodeParameterI = nodes[ 0]->getCrdsSensitivity(); + int nodeParameterJ = nodes[nn-1]->getCrdsSensitivity(); + // TODO(sensitivity): implement dvz + + return (nodeParameterI != 0 || nodeParameterJ != 0); +} + + +template +double +LinearFrameTransf::getLengthGrad() +{ + const int di = nodes[0]->getCrdsSensitivity(); + const int dj = nodes[1]->getCrdsSensitivity(); + + Vector3D dxi{0.0}; + Vector3D dxj{0.0}; + + if (di != 0) + dxi(di-1) = 1.0; + if (dj != 0) + dxj(dj-1) = 1.0; + + return 1/L*(xj - xi).dot(dxj - dxi); +} + + +template +double +LinearFrameTransf::getd1overLdh() +{ + return -getLengthGrad()/(L*L); +} + +template +void +LinearFrameTransf::pushGrad(VectorND& dp, + VectorND& pl) +{ + // + // dp += T_{gl} dpl + // + double dL = this->getLengthGrad(); + double doneOverL = -dL/(L*L); + + constexpr Vector3D iv{1, 0, 0}; + + // 1.1) Sum of moments: m = sum_i mi + sum_i (xi x ni) + Vector3D m{}; + for (int i=0; igetCrdsSensitivity(); + int dj = nodes[1]->getCrdsSensitivity(); + + for (int i=0; ipush(pl, Operation::Isometry); + Matrix3D dR = FrameOrientationGradient(xi, xj, vz, di, dj, dv); + + for (int i=0; i +void +LinearFrameTransf::pullFixedGrad(VectorND& du) +{ + // + // dub += (T_{bl}' T_{lg} + T_{bl} T_{lg}') * ug + // + + // + // Form ug + // + VectorND ug; + for (int i = 0; i < nn; i++) { + const Vector& u = nodes[i]->getTrialDisp(); + for (int j = 0; j < ndf; j++) { + ug[i*ndf+j] = u(j); + } + } + + int dv = 0; // TODO(sensitivity) + + int di = nodes[0]->getCrdsSensitivity(); + int dj = nodes[1]->getCrdsSensitivity(); + + // + // du = Tbl dR^ug + { + Matrix3D dR = FrameOrientationGradient(xi, xj, vz, di, dj, dv); + + VectorND u1 = ug; + LinearFrameTransf::pull(u1, dR, offsets, offset_flags); + du += u1; + } + return; +} + + +template +void +LinearFrameTransf::pullTotalGrad(VectorND& du, int gradNumber) +{ + for (int n=0; ngetDispSensitivity((i + 1), gradNumber); + } + + // dub = T_{bl} T_{lg} * ug' + LinearFrameTransf::pull(du, R, offsets, offset_flags); + + // dub += (T_{bl}' T_{lg} + T_{bl} T_{lg}') * ug + pullFixedGrad(du); + + return; +} + + +template +void +LinearFrameTransf::Print(OPS_Stream &s, int flag) +{ + if (flag == OPS_PRINT_PRINTMODEL_JSON) { + s << OPS_PRINT_JSON_MATE_INDENT << "{"; + s << "\"name\": " << this->getTag() << ", "; + s << "\"type\": \"LinearFrameTransf\""; + s << ", \"vecxz\": [" + << R(0,2) << ", " + << R(1,2) << ", " + << R(2,2) << "]"; + if (offsets != nullptr) { + s << ", \"offsets\": ["; + for (int i=0; igetTag() << " Type: LinearFrameTransf\n"; + s << "\tOrientation: " << Matrix(&R(0,0), 3,3) << "\n"; + } +} + +} // namespace OpenSees diff --git a/SRC/coordTransformation/Frame/PDeltaFrameTransf3d.h b/SRC/coordTransformation/Frame/PDeltaFrameTransf3d.h new file mode 100644 index 0000000000..113ea44b07 --- /dev/null +++ b/SRC/coordTransformation/Frame/PDeltaFrameTransf3d.h @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// +// +// OpenSees - Open System for Earthquake Engineering Simulation +// +//===----------------------------------------------------------------------===// + +// +// Description: PDeltaFrameTransf generalizes the original PDeltaCrdTransf3d +// class to a more general FrameTransform interface. +// +// Adapted: Remo Magalhaes de Souza (rmsouza@ce.berkeley.edu) +// Created: 04/2000 +// +#ifndef PDeltaFrameTransf_h +#define PDeltaFrameTransf_h + +#include +#include +#include "LinearFrameTransf.h" +#include +#include + +class Vector; +class Matrix; + +namespace OpenSees { + +template +class PDeltaFrameTransf: public FrameTransform +{ +public: + + PDeltaFrameTransf(int tag, + const Vector3D &vecxz, + const std::array *offset=nullptr, + int offset_flags = 0); + + ~PDeltaFrameTransf(); + + const char *getClassType() const {return "PDeltaFrameTransf";} + + double getInitialLength() final; + double getDeformedLength() final; + + int initialize(std::array& new_nodes) final; + int update() final; + int commit() final; + int revertToLastCommit() final; + int revertToStart() final; + + VectorND getStateVariation() final; + Vector3D getNodePosition(int tag) final; + Vector3D getNodeRotationLogarithm(int tag) final; + const std::array *getRigidOffsets() const final { return linear.getRigidOffsets();} + + using Operation = typename FrameTransform::Operation; + int push(VectorND&pl, Operation) final; + int push(MatrixND& kl, const VectorND& pl, Operation) final; + + + FrameTransform *getCopy() const final; + + int getLocalAxes(Vector3D &x, Vector3D &y, Vector3D &z) const final; + + // Sensitivity + double getLengthGrad() final; + + // Tagged Object + void Print(OPS_Stream &s, int flag) final; + +private: + int offset_flags; + LinearFrameTransf linear; + +}; + +} // namespace OpenSees + +#include "PDeltaFrameTransf3d.tpp" +#endif diff --git a/SRC/coordTransformation/Frame/PDeltaFrameTransf3d.tpp b/SRC/coordTransformation/Frame/PDeltaFrameTransf3d.tpp new file mode 100644 index 0000000000..6063424799 --- /dev/null +++ b/SRC/coordTransformation/Frame/PDeltaFrameTransf3d.tpp @@ -0,0 +1,211 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// +// +// OpenSees - Open System for Earthquake Engineering Simulation +// +//===----------------------------------------------------------------------===// + +// +// Adapted: Remo Magalhaes de Souza +// 04/2000 +// +// Written: cmp +// +#include +#include +#include +#include + +#include "PDeltaFrameTransf3d.h" + +namespace OpenSees { + +template +PDeltaFrameTransf::PDeltaFrameTransf(int tag, + const Vector3D &vecxz, + const std::array *offset, + int offset_flags) + : FrameTransform(tag), + offset_flags(offset_flags), + linear(tag, vecxz, offset, offset_flags) +{ + +} + + +template +PDeltaFrameTransf::~PDeltaFrameTransf() +{ + +} + +template +int +PDeltaFrameTransf::commit() +{ + return linear.commit(); +} + +template +int +PDeltaFrameTransf::revertToLastCommit() +{ + return linear.revertToLastCommit(); +} + +template +int +PDeltaFrameTransf::revertToStart() +{ + return linear.revertToStart(); +} + +template +int +PDeltaFrameTransf::initialize(std::array& new_nodes) +{ + return linear.initialize(new_nodes); +} + +template +int +PDeltaFrameTransf::update() +{ + return linear.update(); +} + +template +int +PDeltaFrameTransf::getLocalAxes(Vector3D &XAxis, Vector3D &YAxis, Vector3D &ZAxis) const +{ + return linear.getLocalAxes(XAxis, YAxis, ZAxis); +} + +template +double +PDeltaFrameTransf::getInitialLength() +{ + return linear.getInitialLength(); +} + +template +double +PDeltaFrameTransf::getDeformedLength() +{ + return linear.getDeformedLength(); +} + + +template +// VectorND +int +PDeltaFrameTransf::push(VectorND&pl, Operation op) +{ + // + // Include leaning column effects (P-Delta) + // + // Axial force + const double N = pl[1*ndf+0]; + + const Vector3D Du = linear.getDelta()/linear.getInitialLength(); + + pl[0*ndf+1] -= Du[1] * N; + pl[1*ndf+1] += Du[1] * N; + + pl[0*ndf+2] -= Du[2] * N; + pl[1*ndf+2] += Du[2] * N; + + return linear.push(pl, op); +} + + +template +// MatrixND +int +PDeltaFrameTransf::push(MatrixND& kl, const VectorND &pl, Operation op) +{ + // Include geometric stiffness effects in local system; + // + // Kl += [ ] + double NoverL = pl[6] / linear.getInitialLength(); + kl(1, 1) += NoverL; + kl(2, 2) += NoverL; + kl(7, 7) += NoverL; + kl(8, 8) += NoverL; + + kl(1, 7) -= NoverL; + kl(7, 1) -= NoverL; + kl(2, 8) -= NoverL; + kl(8, 2) -= NoverL; + return linear.push(kl, pl, op); +} + + +template +VectorND +PDeltaFrameTransf::getStateVariation() +{ + return linear.getStateVariation(); +} + +template +Vector3D +PDeltaFrameTransf::getNodePosition(int tag) +{ + return linear.getNodePosition(tag); +} + +template +Vector3D +PDeltaFrameTransf::getNodeRotationLogarithm(int tag) +{ + return linear.getNodeRotationLogarithm(tag); +} + +template +FrameTransform * +PDeltaFrameTransf::getCopy() const +{ + Vector3D e1, e2, e3; + linear.getLocalAxes(e1, e2, e3); + + return new PDeltaFrameTransf(this->getTag(), + e3, + linear.getRigidOffsets(), + offset_flags); +} + + +template +double +PDeltaFrameTransf::getLengthGrad() +{ + return linear.getLengthGrad(); +} + +template +void +PDeltaFrameTransf::Print(OPS_Stream &s, int flag) +{ + linear.Print(s, flag); +} + +} // namespace OpenSees \ No newline at end of file diff --git a/SRC/coordTransformation/Frame/SouzaFrameTransf.h b/SRC/coordTransformation/Frame/SouzaFrameTransf.h new file mode 100644 index 0000000000..a41f84ba39 --- /dev/null +++ b/SRC/coordTransformation/Frame/SouzaFrameTransf.h @@ -0,0 +1,208 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// OpenSees - Open System for Earthquake Engineering Simulation +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// Copyright @ 1999-2020 The Regents of the University of California (The Regents). +// All Rights Reserved. +// +// The Regents grants permission, without fee and without a written license +// agreement, for (a) use, reproduction, modification, and distribution of this +// software and its documentation by educational, research, and non-profit +// entities for noncommercial purposes only; and (b) use, reproduction and +// modification of this software by other entities for internal purposes only. +// The above copyright notice, this paragraph and the following three +// paragraphs must appear in all copies and modifications of the software +// and/or documentation. +// +// Permission to incorporate this software into products for commercial +// distribution may be obtained by contacting the University of California +// Office of Technology Licensing +// 2150 Shattuck Avenue #510, +// Berkeley, CA 94720-1620, +// (510) 643-7201. +// +// This software program and documentation are copyrighted by The Regents of +// the University of California. The Regents does not warrant that the +// operation of the program will be uninterrupted or error-free. The end-user +// understands that the program was developed for research purposes and is +// advised not to rely exclusively on the program for any reason. +// +// IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS GRANTS +// NO EXPRESS OR IMPLIED LICENSE IN ANY PATENT RIGHTS OF REGENTS BUT HAS +// IMPLEMENTED AN INDIVIDUAL CONTRIBUTOR LICENSE AGREEMENT FOR THE OPENSEES +// PROJECT AT THE UNIVERISTY OF CALIFORNIA, BERKELEY TO BENEFIT THE END USER. +// +// REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED +// HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE +// MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +//===----------------------------------------------------------------------===// + +// +// Description: SouzaFrameTransf implements the formulation +// of Crisfield (1990) with the objective of maintaining the +// original "Corotational" implementation by Remo Magalhaes de Souza, within +// the new framework proposed by Perez and Filippou (2024). +// +// Written: cmp +// Created: March 2024 +// +// Adapted from work by: Remo Magalhaes de Souza (rmsouza@ce.berkeley.edu) +// +// [1] Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +// [2] Crisfield, M.A. (1990) "A consistent co-rotational formulation for +// non-linear, three-dimensional, beam-elements", Computer Methods in Applied +// Mechanics and Engineering, 81(2), pp. 131–150. Available at: +// https://doi.org/10.1016/0045-7825(90)90106-V. +// +#ifndef SouzaFrameTransf_hpp +#define SouzaFrameTransf_hpp + +#include +#include "FrameTransform.h" +#include +#include +#include +#include +#include +#include "Isometry/CrisfieldIsometry.h" + + +namespace OpenSees { + +template +class SouzaFrameTransf: public FrameTransform +{ +public: + SouzaFrameTransf(int tag, + const Vector3D &vecxz, + const std::array *offset=nullptr, + int offset_flags = 0); + + ~SouzaFrameTransf(); + + const char *getClassType() const { + return "SouzaFrameTransf"; + } + + // NOTE: maybe add arg for rotation parameterization + FrameTransform *getCopy() const final; + + int initialize(std::array& new_nodes) final; + int update() final; + int commit() final; + int revertToLastCommit() final; + int revertToStart() final; + int getLocalAxes(Vector3D &x, Vector3D &y, Vector3D &z) const final; + const std::array *getRigidOffsets() const final { return offsets; } + + double getInitialLength() final; + double getDeformedLength() final; + + VectorND getStateVariation() final; + Vector3D getNodePosition(int tag) final; + Vector3D getNodeRotationLogarithm(int tag) final; + + using Operation = typename FrameTransform::Operation; + int push(VectorND&pl, Operation) final; + int push(MatrixND& kl, const VectorND& pl, Operation) final; + + // Sensitivity + double getLengthGrad() final; + const Vector &getBasicDisplTotalGrad(int grad); // final; + const Vector &getBasicDisplFixedGrad(); + const Vector &getGlobalResistingForceShapeSensitivity(const Vector &pb, const Vector &p0, int gradNumber); + + // Tagged Object + void Print(OPS_Stream &s, int flag) final; + +private: + constexpr static int n = nn*ndf; + + int addTangent(MatrixND<12,12>& M, const VectorND<12>& pl, const VectorND<12>&ul); + + enum { + inx= 0, // axial + iny= 1, // Vy + inz= 2, // Vz + imx= 3, // torsion + imy= 4, // rot y I + imz= 5, // rot z I + + jnx= 6, // axial + jny= 7, + jnz= 8, + jmx= 9, // torsion + jmy=10, // rot y J + jmz=11, // rot z J + }; + + // + // Member data + // + std::array nodes; + + Vector3D xAxis; // local x axis + Vector3D vz; // Vector that lies in local plane xz + Vector3D dX; + + std::array *offsets; + + double *nodeIInitialDisp, *nodeJInitialDisp; + bool initialDispChecked; + + double L; // initial element length + double Ln; // current element length (at trial state) + + Versor Q_past[nn]; // commited rotations + Versor Q_pres[nn]; // trial rotations + + Vector3D alphaI; // last trial rotations end i + Vector3D alphaJ; // last trial rotatations end j + + VectorND ul; // local displacements + Vector3D vr[nn]; // + VectorND ulcommit; // commited local displacements + VectorND ulpr; // previous local displacements + + OpenSees::MatrixND T; // transformation from local to global system + + OpenSees::Matrix3D R0; // rotation from local to global coordinates + CrisfieldIsometry<2,false> crs; + +}; + +} // namespace OpenSees + +#include "SouzaFrameTransf.tpp" +#endif diff --git a/SRC/coordTransformation/Frame/SouzaFrameTransf.tpp b/SRC/coordTransformation/Frame/SouzaFrameTransf.tpp new file mode 100644 index 0000000000..1a79fffbc8 --- /dev/null +++ b/SRC/coordTransformation/Frame/SouzaFrameTransf.tpp @@ -0,0 +1,592 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// +// +// Copyright @ 1999-2020 The Regents of the University of California (The Regents). +// All Rights Reserved. +// +// The Regents grants permission, without fee and without a written license +// agreement, for (a) use, reproduction, modification, and distribution of this +// software and its documentation by educational, research, and non-profit +// entities for noncommercial purposes only; and (b) use, reproduction and +// modification of this software by other entities for internal purposes only. +// The above copyright notice, this paragraph and the following three +// paragraphs must appear in all copies and modifications of the software +// and/or documentation. +// +// Permission to incorporate this software into products for commercial +// distribution may be obtained by contacting the University of California +// Office of Technology Licensing +// 2150 Shattuck Avenue #510, +// Berkeley, CA 94720-1620, +// (510) 643-7201. +// +// This software program and documentation are copyrighted by The Regents of +// the University of California. The Regents does not warrant that the +// operation of the program will be uninterrupted or error-free. The end-user +// understands that the program was developed for research purposes and is +// advised not to rely exclusively on the program for any reason. +// +// IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, +// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +// REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. REGENTS GRANTS +// NO EXPRESS OR IMPLIED LICENSE IN ANY PATENT RIGHTS OF REGENTS BUT HAS +// IMPLEMENTED AN INDIVIDUAL CONTRIBUTOR LICENSE AGREEMENT FOR THE OPENSEES +// PROJECT AT THE UNIVERISTY OF CALIFORNIA, BERKELEY TO BENEFIT THE END USER. +// +// REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED +// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED +// HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE +// MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +// +//===----------------------------------------------------------------------===// + +// +// Description: SouzaFrameTransf implements a Corotational +// transformation for a spatial frame element following the formulation +// by Crisfield (1990). +// +// Written: Claudio Perez +// Created: 05/2024 +// +// Adapted from: Remo Magalhaes de Souza (rmsouza@ce.berkeley.edu) +// +// [1] Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +// [2] Crisfield, M.A. (1990) "A consistent co-rotational formulation for +// non-linear, three-dimensional, beam-elements", Computer Methods in Applied +// Mechanics and Engineering, 81(2), pp. 131–150. Available at: +// https://doi.org/10.1016/0045-7825(90)90106-V. +// +#include +#include +#include +#include "SouzaFrameTransf.h" + +#include +#include +#include +#include +#include +#include +#include +#include "Isometry/CrisfieldIsometry.h" + +namespace OpenSees { + +template +SouzaFrameTransf::SouzaFrameTransf(int tag, const Vector3D &vz, + const std::array *offset, + int offset_flags) + : FrameTransform(tag), + vz(vz), + offsets{nullptr}, + L(0), Ln(0), + nodeIInitialDisp(0), nodeJInitialDisp(0), + initialDispChecked(false), + crs{vz} +{ + alphaI.zero(); + alphaJ.zero(); + + // Rigid joint offsets + if (offset != nullptr) { + offsets = new std::array{}; + *offsets = *offset; + } +} + + +template +SouzaFrameTransf::~SouzaFrameTransf() +{ + if (offsets != nullptr) + delete offsets; +} + + +template +double +SouzaFrameTransf::getInitialLength() +{ + return L; +} + + +template +double +SouzaFrameTransf::getDeformedLength() +{ + return Ln; +} + + +template +FrameTransform * +SouzaFrameTransf::getCopy() const +{ + + SouzaFrameTransf *theCopy = + new SouzaFrameTransf(this->getTag(), vz, offsets); + + theCopy->nodes[0] = nodes[0]; + theCopy->nodes[1] = nodes[1]; + theCopy->xAxis = xAxis; + theCopy->L = L; + theCopy->Ln = Ln; + theCopy->R0 = R0; + theCopy->Q_pres[0] = Q_pres[0]; + theCopy->Q_pres[1] = Q_pres[1]; + theCopy->Q_past[0] = Q_past[0]; + theCopy->Q_past[1] = Q_past[1]; + theCopy->ul = ul; + theCopy->ulcommit = ulcommit; + return theCopy; +} + + +template +int +SouzaFrameTransf::revertToStart() +{ + ul.zero(); + Q_pres[0] = Versor::from_matrix(R0); + for (int i=1; iupdate(); + return 0; +} + + +template +int +SouzaFrameTransf::commit() +{ + ulcommit = ul; + Q_past[0] = Q_pres[0]; + Q_past[1] = Q_pres[1]; + return 0; +} + + +template +int +SouzaFrameTransf::revertToLastCommit() +{ + // determine global displacement increments from last iteration + const Vector &dispI = nodes[0]->getTrialDisp(); + const Vector &dispJ = nodes[1]->getTrialDisp(); + + for (int k = 0; k < 3; k++) { + alphaI(k) = dispI(k+3); + alphaJ(k) = dispJ(k+3); + } + + ul = ulcommit; + Q_pres[0] = Q_past[0]; + Q_pres[1] = Q_past[1]; + + this->update(); + + return 0; +} + + +template +int +SouzaFrameTransf::initialize(std::array& new_nodes) +{ + for (int i=0; igetCrds(); + dX -= nodes[ 0]->getCrds(); + + // Add initial displacements at nodes + if (initialDispChecked == false) { + const Vector &nodeIDisp = nodes[0]->getDisp(); + const Vector &nodeJDisp = nodes[1]->getDisp(); + for (int i = 0; i<6; i++) + if (nodeIDisp[i] != 0.0) { + nodeIInitialDisp = new double [6]; + for (int j = 0; j<6; j++) + nodeIInitialDisp[j] = nodeIDisp[j]; + i = 6; + } + + for (int j = 0; j<6; j++) + if (nodeJDisp[j] != 0.0) { + nodeJInitialDisp = new double [6]; + for (int i = 0; i<6; i++) + nodeJInitialDisp[i] = nodeJDisp[i]; + j = 6; + } + initialDispChecked = true; + } + + // + // Length and Orientation + // + Vector3D dx; + + dx = nodes[nn-1]->getCrds() - nodes[0]->getCrds(); + + L = dx.norm(); + + if (L == 0.0) { + opserr << "\nSouzaFrameTransf::computeElemtLengthAndOrien: 0 length\n"; + return -2; + } + + // + // Set rotation matrix + // + int error = FrameTransform::Orient(dx, vz, R0); + if (error) + return error; + + // Compute initial pseudo-vectors for nodal triads + Q_pres[0] = Versor::from_matrix(R0); + Q_pres[1] = Q_pres[0]; + + ul.zero(); + ulpr.zero(); + + for (int i=0; icommit(); + + return 0; +} + +template +VectorND +SouzaFrameTransf::getStateVariation() +{ + return ul - ulpr; +} + + +template +Vector3D +SouzaFrameTransf::getNodePosition(int tag) +{ + Vector3D u; + for (int i=0; i<3; i++) + u[i] = ul[tag*ndf+i]; + return u; +} + + +template +Vector3D +SouzaFrameTransf::getNodeRotationLogarithm(int tag) +{ + return vr[tag]; +} + + +// +// Set RI,RJ,Rbar, Ln, e and ul +// +template +int +SouzaFrameTransf::update() +{ + // determine global displacement increments from last iteration + + const Vector& dispI = nodes[ 0]->getTrialDisp(); + const Vector& dispJ = nodes[nn-1]->getTrialDisp(); + + // + // Update state + // + + // 1.1 Relative translation + Vector3D dx = dX;// dx = dX + dJI; + { + // Relative translation + for (int k = 0; k < 3; k++) + dx[k] += dispJ(k) - dispI(k); + + + // Calculate the deformed length + Ln = dx.norm(); + + if (Ln == 0.0) { + opserr << "\nSouzaFrameTransf: deformed length is 0.0\n"; + return -2; + } + } + + // 1.2 Rotational displacement increments + { + Vector3D dAlphaI, dAlphaJ; + + for (int k = 0; k < 3; k++) { + dAlphaI[k] = dispI(k+3) - alphaI[k]; + alphaI[k] = dispI(k+3); + dAlphaJ[k] = dispJ(k+3) - alphaJ[k]; + alphaJ[k] = dispJ(k+3); + } + + // Update the nodal rotations; Note the Hamilton product is assumed! + if (dAlphaI.norm() != 0) + Q_pres[0] = Versor::from_vector(dAlphaI)*Q_pres[0]; + if (dAlphaJ.norm() != 0) + Q_pres[1] = Versor::from_vector(dAlphaJ)*Q_pres[1]; + } + + // + // 2) Form transformation + // + const Matrix3D RIR0 = MatrixFromVersor(Q_pres[0]), + RJR0 = MatrixFromVersor(Q_pres[1]); + + crs.update(RIR0, RJR0, dx, nodes); + + // + // 3) Local deformations + // + + // Save previous state + ulpr = ul; + + // Rotations + { + const Matrix3D e = crs.getRotation(); + vr[0] = LogC90(e^RIR0); + for (int i=0; i<3; i++) + ul[imx+i] = vr[0][i]; + + vr[1] = LogC90(e^RJR0); + for (int i=0; i<3; i++) + ul[jmx+i] = vr[1][i]; + } + + // Axial + ul(inx) = 0; + ul(jnx) = Ln - L; + // ul(jnx) = (dX + (dx-dX)*0.5).dot(dx-dX)*2.0/(Ln+L); + + // Form the transformation tangent + T = crs.compute_tangent(ul); + return 0; +} + + +template +int +SouzaFrameTransf::push(VectorND&pl, Operation) +{ + // return T^pl; + VectorND pg{}; + for (int a = 0; a pa {pl(a*ndf+0), pl(a*ndf+1), pl(a*ndf+2), + pl(a*ndf+3), pl(a*ndf+4), pl(a*ndf+5)}; + + for (int b = 0; b<2; b++) { + VectorND<6> pab{}; + for (int i = 0; i < 6; i++) + for (int j = 0; j < 6; j++) + pab[j] += T(a*6 + i, b*6+j) * pa[i]; + pg.assemble(b*6, pab, 1.0); + } + } + pl = pg; // TODO: optimize + return 0; +} + + +// do +// K = ag'*Km*ag + Kp +// +template +int +SouzaFrameTransf::push(MatrixND& kl, + const VectorND& pl, + Operation op) +{ + MatrixND<12,12> KT = kl*T; + kl.addMatrixTransposeProduct(0.0, T, KT, 1.0); + + // Add geometric part + this->addTangent(kl, pl, ul); + + return 0; +} + + +// +// Add geometric part of the transformation tangent +// +// kg += T'*kl*T + ks1 + T * diag(m.*tan(thetal))*T' + ... +// m(4)*(ks2r2t3_u3 + ks2r3u2_t2) + ... +// m(2)*ks2r2t1 + m(3)*ks2r3t1 + ... +// m(5)*ks2r2u1 + m(6)*ks2r3u1 + ... +// ks3 + ks3' + ks4 + ks5; +template +int +SouzaFrameTransf::addTangent(MatrixND<12,12>& kg, + const VectorND<12>& pl, + const VectorND<12>& ul) +{ + + crs.addTangent(kg, pl, ul); + + // + // T' * diag (M .* tan(thetal))*T + // + for (int node=0; node<2; node++) { + for (int k = 0; k < 3; k++) { + const double factor = pl[(node ? jmx : imx) + k] + * std::tan(ul[(node ? jmx : imx) + k]); + + + for (int i = 0; i < 12; i++) { + const double Tki = T((node ? jmx : imx) + k,i); + for (int j = 0; j < 12; j++) { + kg(i,j) += Tki * factor * T((node ? jmx : imx) + k, j); + } + } + } + } + + return 0; +} + + +template +int +SouzaFrameTransf::getLocalAxes(Vector3D &e1, Vector3D &e2, Vector3D &e3) const +{ + for (int i = 0; i < 3; i++) { + e1[i] = R0(i,0); + e2[i] = R0(i,1); + e3[i] = R0(i,2); + } + return 0; +} + + +template +double +SouzaFrameTransf::getLengthGrad() +{ + const int di = nodes[0]->getCrdsSensitivity(); + const int dj = nodes[1]->getCrdsSensitivity(); + + Vector3D dxi{0.0}; + Vector3D dxj{0.0}; + + if (di != 0) + dxi(di-1) = 1.0; + if (dj != 0) + dxj(dj-1) = 1.0; + + return 1.0/L * dX.dot(dxj - dxi); +} + +template +const Vector & +SouzaFrameTransf::getBasicDisplTotalGrad(int gradNumber) +{ + opserr << "WARNING CrdTransf::getBasicDisplTotalGrad() - this method " + << " should not be called.\n"; + + static Vector dummy(1); + return dummy; +} + +template +const Vector & +SouzaFrameTransf::getBasicDisplFixedGrad() +{ + opserr << "ERROR CrdTransf::getBasicDisplFixedGrad() - has not been" + << " implemented yet for the chosen transformation\n."; + + static Vector dummy(1); + return dummy; +} + + +template +const Vector & +SouzaFrameTransf::getGlobalResistingForceShapeSensitivity(const Vector &pb, + const Vector &p0, + int gradNumber) +{ + opserr << "ERROR CrdTransf::getGlobalResistingForceSensitivity() - has not been" + << " implemented yet for the chosen transformation." << endln; + + static Vector dummy(1); + return dummy; +} + +template +void +SouzaFrameTransf::Print(OPS_Stream &s, int flag) +{ + + if (flag == OPS_PRINT_CURRENTSTATE) { + s << "\nFrameTransform: " << this->getTag() << " Type: SouzaFrameTransf"; + s << "\tvxz: " << Vector(vz); + } + + if (flag == OPS_PRINT_PRINTMODEL_JSON) { + s << OPS_PRINT_JSON_MATE_INDENT << "{"; + s << "\"name\": " << this->getTag() << ", "; + s << "\"type\": \"SouzaFrameTransf\"" << ", "; + s << "\"vecxz\": [" << vz(0) << ", " << vz(1) << ", " << vz(2) << "]"; + + if (offsets != nullptr) { + s << ", \"offsets\": ["; + for (int i=0; i +#include +#include +#include + +Vector BeamUniformMoment::data(3); + +BeamUniformMoment::BeamUniformMoment(int tag, double x, double y, double z, + int theElementTag) + :ElementalLoad(tag, LOAD_TAG_BeamUniformMoment, theElementTag), + mx(x), my(y), mz(z) +{ + +} + +BeamUniformMoment::BeamUniformMoment() + :ElementalLoad(LOAD_TAG_BeamUniformMoment), + mx(0.0), my(0.0), mz(0.0) +{ + +} + +BeamUniformMoment::~BeamUniformMoment() +{ + +} + +const Vector & +BeamUniformMoment::getData(int &type, double loadFactor) +{ + type = LOAD_TAG_BeamUniformMoment; + data(0) = mx; + data(1) = my; + data(2) = mz; + return data; +} + + +int +BeamUniformMoment::sendSelf(int commitTag, Channel &theChannel) +{ + int dbTag = this->getDbTag(); + + static Vector vectData(5); + vectData(4) = this->getTag(); + vectData(0) = mx; + vectData(1) = my; + vectData(2) = mz; + vectData(3) = eleTag; + + int result = theChannel.sendVector(dbTag, commitTag, vectData); + if (result < 0) { + opserr << "BeamUniformMoment::sendSelf - failed to send data\n"; + return result; + } + + return 0; +} + +int +BeamUniformMoment::recvSelf(int commitTag, Channel &theChannel, + FEM_ObjectBroker &theBroker) +{ + int dbTag = this->getDbTag(); + + static Vector vectData(5); + + int result = theChannel.recvVector(dbTag, commitTag, vectData); + if (result < 0) { + opserr << "BeamUniformMoment::recvSelf - failed to recv data\n"; + return result; + } + + mx = vectData(0);; + my = vectData(1);; + mz = vectData(2);; + eleTag = (int)vectData(3); + this->setTag(vectData(4)); + + return 0; +} + +void +BeamUniformMoment::Print(OPS_Stream &s, int flag) +{ + s << "BeamUniformMoment - Reference load: " << this->getTag() << endln; + s << " Torque (x): " << mx << endln; + s << " About y: " << my << endln; + s << " About z: " << mz << endln; + s << " Element: " << eleTag << endln; +} diff --git a/SRC/runtime/runtime/SectionBuilder/cell/QuadCell.h b/SRC/domain/load/BeamUniformMoment.h similarity index 60% rename from SRC/runtime/runtime/SectionBuilder/cell/QuadCell.h rename to SRC/domain/load/BeamUniformMoment.h index 314005d35c..477d091161 100644 --- a/SRC/runtime/runtime/SectionBuilder/cell/QuadCell.h +++ b/SRC/domain/load/BeamUniformMoment.h @@ -18,58 +18,41 @@ ** ** ** ****************************************************************** */ -// $Revision: 1.2 $ -// $Date: 2003/02/14 23:01:36 $ -// $Source: /usr/local/cvs/OpenSees/SRC/material/section/repres/cell/QuadCell.h,v $ +// $Revision: 1.3 $ +// $Date: 2007-10-17 22:11:35 $ +// $Source: /usr/local/cvs/OpenSees/SRC/domain/load/BeamUniformMoment.h,v $ - -// File: QuadCell.h -// -// Written by Remo M. de Souza -// December 1998 - - -#ifndef QuadCell_h -#define QuadCell_h +#ifndef BeamUniformMoment_h +#define BeamUniformMoment_h -#include -#include +// Written: fmk -class Matrix; -class Vector; +// Purpose: This file contains the class definition for BeamUniformMoment. +#include -class QuadCell: public Cell +class BeamUniformMoment : public ElementalLoad { public: + BeamUniformMoment(int tag, double mx, double my, double mz, int eleTag); + + BeamUniformMoment(); + ~BeamUniformMoment(); - QuadCell(); - QuadCell(const Matrix &vertexCoords); - - ~QuadCell(); - - // edition functions + const Vector &getData(int &type, double loadFactor); - void setVertCoords (const Matrix &vertexCoords); + int sendSelf(int commitTag, Channel &theChannel); + int recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker); + void Print(OPS_Stream &s, int flag =0); - // reinforcing bar inquiring functions - - double getArea (void) const; - double getdValue (void) const; - const Matrix &getVertCoords (void) const; - const Vector &getCentroidPosition (void); - - void Print(OPS_Stream &s, int flag =0) const; - friend OPS_Stream &operator<<(OPS_Stream &s, const QuadCell &quadCell); - protected: - + private: - Matrix vertCoord; - Vector Centroid; -// double area; + double mx; // Twist + double my; // About y + double mz; // About z + static Vector data; }; - #endif diff --git a/SRC/domain/load/CMakeLists.txt b/SRC/domain/load/CMakeLists.txt index 29ede24e18..1c694290ba 100644 --- a/SRC/domain/load/CMakeLists.txt +++ b/SRC/domain/load/CMakeLists.txt @@ -17,6 +17,7 @@ target_sources(OPS_Domain Beam3dUniformLoad.cpp Beam3dPointLoad.cpp Beam3dPartialUniformLoad.cpp + BeamUniformMoment.cpp BrickSelfWeight.cpp SurfaceLoader.cpp SelfWeight.cpp @@ -32,6 +33,7 @@ target_sources(OPS_Domain Beam3dUniformLoad.h Beam3dPointLoad.h Beam3dPartialUniformLoad.h + BeamUniformMoment.h BrickSelfWeight.h SurfaceLoader.h SelfWeight.h diff --git a/SRC/domain/load/Makefile b/SRC/domain/load/Makefile index 4c3a92c857..ab8ae80880 100644 --- a/SRC/domain/load/Makefile +++ b/SRC/domain/load/Makefile @@ -12,6 +12,7 @@ OBJS = Load.o \ BrickSelfWeight.o \ Beam2dTempLoad.o \ Beam2dThermalAction.o \ + BeamUniformMoment.o \ NodalThermalAction.o \ ThermalActionWrapper.o \ Beam3dThermalAction.o \ diff --git a/SRC/domain/node/Node.cpp b/SRC/domain/node/Node.cpp index ccebd571df..2d5854cf2c 100644 --- a/SRC/domain/node/Node.cpp +++ b/SRC/domain/node/Node.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -227,6 +228,7 @@ Node::Node(int theClassTag) trialDisp(0), trialVel(0), trialAccel(0), unbalLoad(0), incrDisp(0), incrDeltaDisp(0), disp(0), vel(0), accel(0), dbTag1(0), dbTag2(0), dbTag3(0), dbTag4(0), + rotation(nullptr), R(0), mass(0), unbalLoadWithInertia(0), alphaM(0.0), theEigenvectors(0), index(-1), reaction(0), displayLocation(0), temperature(0) { @@ -250,6 +252,7 @@ Node::Node(int tag, int theClassTag) trialDisp(0), trialVel(0), trialAccel(0), unbalLoad(0), incrDisp(0), incrDeltaDisp(0), disp(0), vel(0), accel(0), dbTag1(0), dbTag2(0), dbTag3(0), dbTag4(0), + rotation(nullptr), R(0), mass(0), unbalLoadWithInertia(0), alphaM(0.0), theEigenvectors(0), index(-1), reaction(0), displayLocation(0), temperature(0) { @@ -273,6 +276,7 @@ Node::Node(int tag, int ndof, double Crd1, Vector *dLoc) trialDisp(0), trialVel(0), trialAccel(0), unbalLoad(0), incrDisp(0), incrDeltaDisp(0), disp(0), vel(0), accel(0), dbTag1(0), dbTag2(0), dbTag3(0), dbTag4(0), + rotation(nullptr), R(0), mass(0), unbalLoadWithInertia(0), alphaM(0.0), theEigenvectors(0), index(-1), reaction(0), displayLocation(0), temperature(0) { @@ -305,6 +309,7 @@ Node::Node(int tag, int ndof, double Crd1, double Crd2, Vector *dLoc) trialDisp(0), trialVel(0), trialAccel(0), unbalLoad(0), incrDisp(0), incrDeltaDisp(0), disp(0), vel(0), accel(0), dbTag1(0), dbTag2(0), dbTag3(0), dbTag4(0), + rotation(nullptr), R(0), mass(0), unbalLoadWithInertia(0), alphaM(0.0), theEigenvectors(0), reaction(0), displayLocation(0), temperature(0) { @@ -339,6 +344,7 @@ Node::Node(int tag, int ndof, double Crd1, double Crd2, Vector *dLoc) trialDisp(0), trialVel(0), trialAccel(0), unbalLoad(0), incrDisp(0), incrDeltaDisp(0), disp(0), vel(0), accel(0), dbTag1(0), dbTag2(0), dbTag3(0), dbTag4(0), + rotation(nullptr), R(0), mass(0), unbalLoadWithInertia(0), alphaM(0.0), theEigenvectors(0), reaction(0), displayLocation(0), temperature(0) { @@ -374,6 +380,7 @@ Node::Node(const Node &otherNode, bool copyMass) trialDisp(0), trialVel(0), trialAccel(0), unbalLoad(0), incrDisp(0), incrDeltaDisp(0), disp(0), vel(0), accel(0), dbTag1(0), dbTag2(0), dbTag3(0), dbTag4(0), + rotation(nullptr), R(0), mass(0), unbalLoadWithInertia(0), alphaM(0.0), theEigenvectors(0), reaction(0), displayLocation(0), temperature(0) { @@ -482,6 +489,10 @@ Node::~Node() if (trialAccel != 0) delete trialAccel; + if (rotation != nullptr) + delete[] rotation; + + if (incrDisp != 0) delete incrDisp; @@ -693,6 +704,17 @@ Node::getIncrDeltaDisp(void) return *incrDeltaDisp; } +Versor +Node::getTrialRotation() +{ + if (rotation == nullptr) [[unlikely]] { + rotation = new Versor[2]; + rotation[0] = Versor{{0.0, 0.0, 0.0}, 1.0}; + rotation[1] = Versor{{0.0, 0.0, 0.0}, 1.0}; + } + + return rotation[1]; +} int Node::setTrialDisp(double value, int dof) @@ -815,6 +837,10 @@ Node::incrTrialDisp(const Vector &incrDispl) return -2; } + if (rotation != nullptr && this->getNumberDOF() >= 6) + rotation[1] = rotation[1]*Versor::from_vector(&disp[3*numberDOF+3]); + + // create a copy if no trial exists and add committed if (trialDisp == 0) { if (this->createDisp() < 0) { @@ -1087,6 +1113,8 @@ Node::commitState() accel[i+numberDOF] = accel[i]; } + if (rotation != nullptr) + rotation[0] = rotation[1]; // if we get here we are done return 0; } @@ -1117,6 +1145,8 @@ Node::revertToLastCommit() accel[i] = accel[numberDOF+i]; } + if (rotation != nullptr) + rotation[1] = rotation[0]; // if we get here we are done return 0; } @@ -1147,6 +1177,10 @@ Node::revertToStart() (*unbalLoad) *= 0; + if (rotation != nullptr) { + rotation[0] = Versor{{0.0, 0.0, 0.0}, 1.0}; + rotation[1] = rotation[0]; + } // AddingSensitivity: BEGIN ///////////////////////////////// diff --git a/SRC/domain/node/Node.h b/SRC/domain/node/Node.h index 8b7a70211f..2267f7ec6a 100644 --- a/SRC/domain/node/Node.h +++ b/SRC/domain/node/Node.h @@ -46,6 +46,8 @@ class Vector; class Matrix; class Channel; class Renderer; +namespace OpenSees {struct Versor;} +using OpenSees::Versor; class DOF_Group; class NodalThermalAction; //L.Jiang [ SIF ] @@ -86,6 +88,7 @@ class Node : public DomainComponent virtual const Vector &getTrialDisp(void); virtual const Vector &getTrialVel(void); virtual const Vector &getTrialAccel(void); + virtual Versor getTrialRotation(void); // public methods for updating the trial response quantities virtual int setTrialDisp(double value, int dof); @@ -187,6 +190,7 @@ class Node : public DomainComponent Vector *commitDisp, *commitVel, *commitAccel; // committed quantities Vector *trialDisp, *trialVel, *trialAccel; // trial quantities Vector *unbalLoad; // unbalanced load + Versor *rotation; Vector *incrDisp; Vector *incrDeltaDisp; diff --git a/SRC/domain/pattern/drm/H5DRMLoadPattern.cpp b/SRC/domain/pattern/drm/H5DRMLoadPattern.cpp index a2320d2a78..739fc3450c 100644 --- a/SRC/domain/pattern/drm/H5DRMLoadPattern.cpp +++ b/SRC/domain/pattern/drm/H5DRMLoadPattern.cpp @@ -1629,6 +1629,17 @@ void H5DRMLoadPattern::node_matching_BruteForce(double d_tol, const ID & interna while ((node_ptr = node_iter()) != 0) { int tag = node_ptr->getTag(); + + // Skip nodes with more than 6 DOF + int numDOF = node_ptr->getNumberDOF(); + if (numDOF > 6) { + if (DEBUG_NODE_MATCHING) + { + fprintf(fptrdrm, "Node # %05d skipped - has %d DOF (>6)\n", tag, numDOF); + } + continue; + } + const Vector& node_xyz = node_ptr->getCrds(); double dmin = std::numeric_limits::infinity(); int ii_station_min = 0; diff --git a/SRC/element/PFEMElement/QuadMeshGenerator.cpp b/SRC/element/PFEMElement/QuadMeshGenerator.cpp index 969aa6d8e7..43a1a5b5a1 100644 --- a/SRC/element/PFEMElement/QuadMeshGenerator.cpp +++ b/SRC/element/PFEMElement/QuadMeshGenerator.cpp @@ -127,7 +127,7 @@ QuadMeshGenerator::mesh(double size) } // create points - if (m<=1 || n<=1) return 0; + if (m<1 || n<1) return 0; Matrix grid(m+1, n+1); for (int i=0; igetDT(); + + // // make C zero + for (int i = 0; i < PML3D_NUM_DOF*PML3D_NUM_DOF; i++) { + // C[i] = 0.0; + // K[i] = 0.0; + // M[i] = 0.0; + // G[i] = 0.0; + } } // ======================================================================= @@ -205,33 +219,26 @@ void PML3D::setDomain(Domain* theDomain) // ======================================================================= int PML3D::update(void) { - // check if the dt has changed - if (fabs(Domainptr->getDT() - dt) > 1e-10) { - update_dt = 1; - dt = Domainptr->getDT(); - } else { - update_dt = 0; - } - - if (updateflag == 1) { - // get u, v, a from nodes and calculate the ubar vector - int loc = 0; - double c1 = dt; - double c2 = dt * dt * 0.5; - double c3 = dt*dt*dt*((1.0/6.0)-eta); - double c4 = dt*dt*dt*eta; - for (int i = 0; i < PML3D_NUM_NODES; i++) { - const Vector& uNode = nodePointers[i]->getDisp(); - const Vector& vNode = nodePointers[i]->getVel(); - const Vector& aNode = nodePointers[i]->getAccel(); - const Vector& atpdt = nodePointers[i]->getTrialAccel(); - for (int j = 0; j < 9; j++) { - ubar(loc) = ubart(loc) + uNode(j)*c1 + vNode(j)*c2 + aNode(j)*c3 + atpdt(j)*c4; - loc++; - } + dt = Domainptr->getDT(); + // opserr << "dt = " << dt << "\n"; + // get u, v, a from nodes and calculate the ubar vector + int loc = 0; + double c1 = dt; + double c2 = dt * dt * 0.5; + double c3 = dt*dt*dt*((1.0/6.0)-eta); + double c4 = dt*dt*dt*eta; + for (int i = 0; i < PML3D_NUM_NODES; i++) { + const Vector& uNode = nodePointers[i]->getDisp(); + const Vector& vNode = nodePointers[i]->getVel(); + const Vector& aNode = nodePointers[i]->getAccel(); + const Vector& atpdt = nodePointers[i]->getTrialAccel(); + for (int j = 0; j < 9; j++) { + ubar(loc) = ubart(loc) + uNode(j)*c1 + vNode(j)*c2 + aNode(j)*c3 + atpdt(j)*c4; + loc++; } } - updateflag = 1; + + return 0; } @@ -241,16 +248,10 @@ int PML3D::update(void) const Matrix& PML3D::getTangentStiff() { // check if the dt is changed to update the tangent stiffness matrix - if (update_dt == 1) { - double cg = eta*dt/beta; - //keff = k + cg*g( k and g are symmetric matrices) - for (int i = 0; i < PML3D_NUM_DOF; i++) { - for (int j = i; j < PML3D_NUM_DOF; j++) { // Loop over the upper triangular part of the matrices. - double sum = K[i*PML3D_NUM_DOF + j] + cg * G[i*PML3D_NUM_DOF + j]; - Keff[i*PML3D_NUM_DOF + j] = sum; - Keff[j*PML3D_NUM_DOF + i] = sum; // Since K and G are symmetric, set the corresponding lower triangular element. - } - } + double cg = eta*dt/beta; + //keff = k + cg*g( k and g are symmetric matrices) + for (int i = 0; i < PML3D_NUM_DOF*PML3D_NUM_DOF; i++) { + Keff[i] = K[i] + cg*G[i]; } tangent.setData(Keff, PML3D_NUM_DOF, PML3D_NUM_DOF); return tangent; @@ -354,14 +355,12 @@ PML3D::getResistingForceIncInertia() theVector(loc++) = vel[j]; } } - - resid.addMatrixVector(1.0, this->getDamp(), theVector, 1.0); // R += G*ubar - mass.setData(G, PML3D_NUM_DOF, PML3D_NUM_DOF); - resid.addMatrixVector(1.0, mass, ubar, 1.0); + tangent.setData(G, PML3D_NUM_DOF, PML3D_NUM_DOF); + resid.addMatrixVector(1.0, tangent, ubar, 1.0); return resid; @@ -441,12 +440,10 @@ int PML3D::revertToStart() int success = 0; // set ubar and ubart to zero - // for (int i = 0; i < PML3D_NUM_DOF; i++) { - // ubar[i] = 0.0; - // ubart[i] = 0.0; - // } - ubar.Zero(); - ubart.Zero(); + for (int i = 0; i < PML3D_NUM_DOF; i++) { + ubar(i) = 0.0; + ubart(i) = 0.0; + } return success; } diff --git a/SRC/element/PML/PML3D.h b/SRC/element/PML/PML3D.h index 1d3faab729..70114d3f93 100644 --- a/SRC/element/PML/PML3D.h +++ b/SRC/element/PML/PML3D.h @@ -52,12 +52,13 @@ extern "C" void pml3d_(double* mMatrix, double* cMatrix, double* kMatrix, double* gMatrix, + double* hMatrix, int* NDOFEL, double* PROPS, - int* NPROPS, double* COORDS, int* MCRD, - int* NNODE); + int* NNODE, + int* LFLAGS); #else @@ -67,12 +68,13 @@ extern "C" void pml3d_(double* mMatrix, double* cMatrix, double* kMatrix, double* gMatrix, + double* hMatrix, int* NDOFEL, double* PROPS, - int* NPROPS, double* COORDS, int* MCRD, - int* NNODE); + int* NNODE, + int* LFLAGS); #endif diff --git a/SRC/element/PML/PML3DVISCOUS.cpp b/SRC/element/PML/PML3DVISCOUS.cpp new file mode 100644 index 0000000000..0a4fd9ba27 --- /dev/null +++ b/SRC/element/PML/PML3DVISCOUS.cpp @@ -0,0 +1,1380 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +// Written by: Amin Pakzad, Pedro Arduino (parduino@uw.edu) +// +// Eight node PML3DVISCOUS element .. a c++ wrapper to fortran routine +// provided by Wenyang Zhang (zwyll@ucla.edu), University of California, Los Angeles +// +// University of Washington, UC. Los Angeles, U.C. Berkeley, 12, 2020 + + +#include "PML3DVISCOUS.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +void OPS_PML3DVISCOUS_Box(double* boxParams, double* eleCenter, double* Xref, double* Normal) { + // calculate the Xref and Normal for the Box meshType + // boxParams: XC, YC, ZC, L, W, H + // XC, YC, ZC: center of the box at the surface + // L, W, H: length, width, height of the box + Xref[0] = 0.0; + Xref[1] = 0.0; + Xref[2] = 0.0; + Normal[0] = 0.0; + Normal[1] = 0.0; + Normal[2] = 0.0; + double xref, yref, zref, nx, ny, nz; + xref = 0.0; yref = 0.0; zref = 0.0; + nx = 0.0; ny = 0.0; nz = 0.0; + + // calculate the Normal + double widthx = boxParams[3]/2.; + double widthy = boxParams[4]/2.; + double depth = boxParams[5]; + double Xmesh = boxParams[0]; + double Ymesh = boxParams[1]; + double Zmesh = boxParams[2]; + + double x1 = eleCenter[0]; + double x2 = eleCenter[1]; + double x3 = eleCenter[2]; + + int EleType_arg = 0; + + if (x2 < Ymesh - widthy) { + if (x1 < Xmesh - widthx) { + if (x3 < Zmesh - depth) { + EleType_arg = 15; + nx = -1.0; + ny = -1.0; + nz = -1.0; + xref = Xmesh - widthx; + yref = Ymesh - widthy; + zref = Zmesh - depth; + } + else { + EleType_arg = 6; + nx = -1.0; + ny = -1.0; + nz = 0.0; + xref = Xmesh - widthx; + yref = Ymesh - widthy; + zref = Zmesh; + } + } + else if (x1 < Xmesh + widthx) { + if (x3 < Zmesh - depth) { + EleType_arg = 11; + nx = 0.0; + ny = -1.0; + nz = -1.0; + xref = Xmesh; + yref = Ymesh - widthy; + zref = Zmesh - depth; + } + else { + EleType_arg = 2; + nx = 0.0; + ny = -1.0; + nz = 0.0; + xref = Xmesh; + yref = Ymesh - widthy; + zref = Zmesh; + } + } + else { + if (x3 < Zmesh - depth) { + EleType_arg = 16; + nx = 1.0; + ny = -1.0; + nz = -1.0; + xref = Xmesh + widthx; + yref = Ymesh - widthy; + zref = Zmesh - depth; + } + else { + EleType_arg = 7; + nx = 1.0; + ny = -1.0; + nz = 0.0; + xref = Xmesh + widthx; + yref = Ymesh - widthy; + zref = Zmesh; + } + } + } else if (x2 < Ymesh + widthy) { + if (x1 < Xmesh - widthx) { + if (x3 < Zmesh - depth) { + EleType_arg = 14; + nx = -1.0; + ny = 0.0; + nz = -1.0; + xref = Xmesh - widthx; + yref = Ymesh; + zref = Zmesh - depth; + } + else { + EleType_arg = 5; + nx = -1.0; + ny = 0.0; + nz = 0.0; + xref = Xmesh - widthx; + yref = Ymesh; + zref = Zmesh; + } + } + else if (x1 < Xmesh + widthx) { + if (x3 < Zmesh - depth) { + EleType_arg = 10; + nx = 0.0; + ny = 0.0; + nz = -1.0; + xref = Xmesh; + yref = Ymesh; + zref = Zmesh - depth; + } + else { + EleType_arg = 1; + nx = 0.0; + ny = 0.0; + nz = 0.0; + xref = Xmesh; + yref = Ymesh; + zref = Zmesh; + } + } + else { + if (x3 < Zmesh - depth) { + EleType_arg = 12; + nx = 1.0; + ny = 0.0; + nz = -1.0; + xref = Xmesh + widthx; + yref = Ymesh; + zref = Zmesh - depth; + } + else { + EleType_arg = 3; + nx = 1.0; + ny = 0.0; + nz = 0.0; + xref = Xmesh + widthx; + yref = Ymesh; + zref = Zmesh; + } + } + } else { + if (x1 < Xmesh - widthx) { + if (x3 < Zmesh - depth) { + EleType_arg = 18; + nx = -1.0; + ny = 1.0; + nz = -1.0; + xref = Xmesh - widthx; + yref = Ymesh + widthy; + zref = Zmesh - depth; + } + else { + EleType_arg = 9; + nx = -1.0; + ny = 1.0; + nz = 0.0; + xref = Xmesh - widthx; + yref = Ymesh + widthy; + zref = Zmesh; + } + } + else if (x1 < Xmesh + widthx) { + if (x3 < Zmesh - depth) { + EleType_arg = 13; + nx = 0.0; + ny = 1.0; + nz = -1.0; + xref = Xmesh; + yref = Ymesh + widthy; + zref = Zmesh - depth; + } + else { + EleType_arg = 4; + nx = 0.0; + ny = 1.0; + nz = 0.0; + xref = Xmesh; + yref = Ymesh + widthy; + zref = Zmesh; + } + } + else { + if (x3 < Zmesh - depth) { + EleType_arg = 17; + nx = 1.0; + ny = 1.0; + nz = -1.0; + xref = Xmesh + widthx; + yref = Ymesh + widthy; + zref = Zmesh - depth; + } + else { + EleType_arg = 8; + nx = 1.0; + ny = 1.0; + nz = 0.0; + xref = Xmesh + widthx; + yref = Ymesh + widthy; + zref = Zmesh; + } + } + } + + // int tag = 1; + // opserr << "Element Tag: " << tag << "\n"; + // opserr << "Element Type(" << tag << "): " << EleType_arg << "\n"; + // // opserr << "Element Center(" << tag << "): " << elementCenter[0] << " " << elementCenter[1] << " " << elementCenter[2] << "\n"; + // opserr << "Element Reference(" << tag << "): " << xref << " " << yref << " " << zref << "\n"; + // opserr << "Element Normal(" << tag << "): " << nx << " " << ny << " " << nz << "\n"; + + // return the calculated Xref and Normal + Xref[0] = xref; + Xref[1] = yref; + Xref[2] = zref; + Normal[0] = nx; + Normal[1] = ny; + Normal[2] = nz; +} + + +// ======================================================================= +// PML3DVISCOUS element tcl command +// ======================================================================= +void* OPS_PML3DVISCOUS() +{ + // check if the total number of arguments passed is correct + if (OPS_GetNumRemainingInputArgs() < (11)) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: element PML3DVISCOUS eleTag? Node1? Node2? Node3? Node4? Node5? Node6? Node7? Node 8? matTag? $PMLThickness\n"; + return 0; + } + + // reading element tag and node numbers + int idata[9]; + int num = 9; + if (OPS_GetIntInput(&num, idata) < 0) { + opserr << "WARNING: invalid integer data : could be the tag or the node numbers \n"; + return 0; + } + // THIS SHOULD BE DONE IN setDomain() + // calculate the number center of the element by averaging the node coordinates + double elementCenter[3] = {0.0, 0.0, 0.0}; + /* + // OPS_GetNodeCrd(int* nodeTag, int* sizeData, double* data); + for (int i = 1; i < 9; i++) { + int nodeTag = idata[i]; + double nodeCoord[3] = {0.0, 0.0, 0.0}; + num = 3; + // REWRITE TO DO THIS IN setDomain of the element, not in the OPS_command + if (OPS_GetNodeCrd(&nodeTag, &num, nodeCoord) < 0) { + opserr << "WARNING: invalid node tag: " << nodeTag << endln; + return 0; + } + for (int j = 0; j < 3; j++) { + elementCenter[j] += nodeCoord[j]; + } + } + for (int j = 0; j < 3; j++) { + elementCenter[j] /= 8; + } + */ + + // get the material tag + int matTag; + num = 1; + if (OPS_GetIntInput(&num, &matTag) < 0) { + opserr << "WARNING: invalid integer data: could be the material tag\n"; + return 0; + } + + NDMaterial* mat = OPS_getNDMaterial(matTag); + if (mat == 0) { + opserr << "WARNING material not found\n"; + opserr << "material tag: " << matTag; + opserr << "\nPML3DVISCOUS element: " << idata[0] << endln; + } + // check if the material is "ElasticIsotropicMaterial" + if (strcmp(mat->getClassType(), "ElasticIsotropicMaterial") != 0) { + opserr << "Error: PML3DVISCOUS element only supports ElasticIsotropicMaterial\n"; + opserr << "\tMaterial provided is of type: " << mat->getClassType() << endln; + return 0; + } + + double E = 0.0, nu = 0.0, rho = 0.0; + + const char* argv_E[] = {"E"}; + const char* argv_nu[] = {"nu"}; + + Parameter paramE(1); + Parameter paramNu(2); + + // This is the intended way to access material properties + if (mat->setParameter(argv_E, 1, paramE) >= 0) { + E = paramE.getValue(); + } else { + opserr << "Warning: Material doesn't support E parameter\n"; + } + + if (mat->setParameter(argv_nu, 1, paramNu) >= 0) { + nu = paramNu.getValue(); + } else { + opserr << "Warning: Material doesn't support nu parameter\n"; + } + + // Always available in NDMaterial base class + rho = mat->getRho(); + + // opserr << "PML3DVISCOUS element: E=" << E << ", nu=" << nu << ", rho=" << rho << endln; + + + + // get the PML thickness + double PMLThickness; + num = 1; + if (OPS_GetDoubleInput(&num, &PMLThickness) < 0) { + opserr << "WARNING: invalid double data: could be the PMLThickness\n"; + return 0; + } + + + + // reading the meshType string and it related parameters + num = 1; + if (OPS_GetNumRemainingInputArgs() < 1) { + opserr << "Error: need meshType\n"; + opserr << "meshType could be: \"General\", \"Box\", \"Sphere\", \"Cylinder\"\n"; + return 0; + } + double Xref[3]={0.0, 0.0, 0.0}; // double Normal[] + double Normal[3]={0.0, 0.0, 0.0}; // double Normal[] + + const char* meshType = OPS_GetString(); + if (strcmp(meshType, "General") == 0) { + // reading the meshType string and it related parameters + // this meshType needs to read the following parameters + // Xref, Yref, Zref, N1, N2, N3 + num = 6; + if (OPS_GetNumRemainingInputArgs() < 6) { + opserr << "Error: need meshType parameters\n"; + opserr << "meshType parameters: Xref, Yref, Zref, N1, N2, N3\n"; + return 0; + } + num = 3; + if (OPS_GetDoubleInput(&num, Xref) < 0) { + opserr << "WARNING: invalid double data: could be Xref, Yref, Zref\n"; + return 0; + } + + num = 3; + if (OPS_GetDoubleInput(&num, Normal) < 0) { + opserr << "WARNING: invalid double data: could be N1, N2, N3\n"; + return 0; + } + } + else if (strcmp(meshType, "Box") == 0 || strcmp(meshType, "box") == 0) { + // reading the meshType string and it related parameters + // this meshType needs to read the following parameters + // XC, YC, ZC, L, W, H + // XC, YC, ZC: center of the box at the surface + // L, W, H: length, width, height of the box + num = 6; + if (OPS_GetNumRemainingInputArgs() < 6) { + opserr << "Error: need meshType parameters\n"; + opserr << "meshType parameters: XC, YC, ZC, L, W, H\n"; + return 0; + } + double boxParams[6]; + num = 6; + if (OPS_GetDoubleInput(&num, boxParams) < 0) { + opserr << "WARNING: invalid double data: could be XC, YC, ZC, L, W, H\n"; + return 0; + } + // call the helper function to calculate the Xref and Normal + OPS_PML3DVISCOUS_Box(boxParams, elementCenter, Xref, Normal); + } + else if (strcmp(meshType, "Sphere") == 0 || strcmp(meshType, "sphere") == 0) { + // reading the meshType string and it related parameters + // this meshType needs to read the following parameters + // XC, YC, ZC, R + // XC, YC, ZC: center of the sphere at the surface + // R: radius of the sphere + num = 4; + if (OPS_GetNumRemainingInputArgs() < 4) { + opserr << "Error: need meshType parameters\n"; + opserr << "meshType parameters: XC, YC, ZC, R\n"; + return 0; + } + double sphereParams[4]; + num = 4; + if (OPS_GetDoubleInput(&num, sphereParams) < 0) { + opserr << "WARNING: invalid double data: could be XC, YC, ZC, R\n"; + return 0; + } + // call the helper function to calculate the Xref and Normal + // not implemented yet + opserr << "Error: Sphere meshType not implemented yet\n"; + return 0; + } + else if (strcmp(meshType, "Cylinder") == 0 || strcmp(meshType, "cylinder") == 0) { + // reading the meshType string and it related parameters + // this meshType needs to read the following parameters + // XC, YC, ZC, R, H, dir + // XC, YC, ZC: center of the cylinder at the surface + // R: radius of the cylinder + // H: height of the cylinder + // dir: direction of the cylinder + num = 6; + if (OPS_GetNumRemainingInputArgs() < 6) { + opserr << "Error: need meshType parameters\n"; + opserr << "meshType parameters: XC, YC, ZC, R, H, dir\n"; + return 0; + } + double cylinderParams[6]; + num = 6; + if (OPS_GetDoubleInput(&num, cylinderParams) < 0) { + opserr << "WARNING: invalid double data: could be XC, YC, ZC, R, H, dir\n"; + return 0; + } + // call the helper function to calculate the Xref and Normal + // not implemented yet + opserr << "Error: Cylinder meshType not implemented yet\n"; + return 0; + } + else { + opserr << "Error: meshType not recognized\n"; + opserr << "meshType could be: \"General\", \"Box\", \"Sphere\", \"Cylinder\"\n"; + return 0; + } + // cp_ref = SQRT(E *(1.d0-xnu)/rho/(1.d0+xnu)/(1.d0-2.d0*xnu)) + double Cp = sqrt(E * (1.0 - nu) / rho / (1.0 + nu) / (1.0 - 2.0 * nu)); + double m_coeff = 2.0; + double R = 1.0e-8; + double PML_b = PMLThickness / 1.0; + double alpha_0 = 0.0; + double beta_0 = 0.0; + bool ExplicitAlphaBeta = false; + double gamma = 0.5; + double beta = 0.25; + double eta = 1.0/12.0; + double keisi = 1.0/48.0; + + // now iterate overe the remaining arguments to read optional parameters + while (OPS_GetNumRemainingInputArgs() > 0) { + const char* option = OPS_GetString(); + if (strcmp(option, "-Newmark") == 0 || strcmp(option, "-newmark") == 0) { + // reading Newmark parameters + double Newmark[4]; + num = 4; + if (OPS_GetDoubleInput(&num, Newmark) < 0) { + opserr << "WARNING: invalid double data: could be Newmark parameters\n"; + opserr << "Newmark parameters: gamma, beta, dt, alpha_f\n"; + return 0; + } + gamma = Newmark[0]; + beta = Newmark[1]; + eta = Newmark[2]; + keisi = Newmark[3]; + } + else if (strcmp(option, "-Cp") == 0 || strcmp(option, "-cp") == 0) { + // reading the PML parameters + num = 1; + if (OPS_GetDoubleInput(&num, &Cp) < 0) { + opserr << "WARNING: invalid double data: could be Cp\n"; + return 0; + } + } + else if (strcmp(option, "-m") == 0 || strcmp(option, "-M") == 0) { + // reading the PML parameters + num = 1; + if (OPS_GetDoubleInput(&num, &m_coeff) < 0) { + opserr << "WARNING: invalid double data: could be m\n"; + return 0; + } + } + else if (strcmp(option, "-R") == 0 || strcmp(option, "-r") == 0) { + // reading the PML parameters + num = 1; + if (OPS_GetDoubleInput(&num, &R) < 0) { + opserr << "WARNING: invalid double data: could be R\n"; + return 0; + } + } + else if (strcmp(option, "-alphabeta") == 0) { + // reading the PML parameters + double alphabeta[2]; + num = 2; + if (OPS_GetDoubleInput(&num, alphabeta) < 0) { + opserr << "WARNING: invalid double data: could be alphabeta\n"; + return 0; + } + alpha_0 = alphabeta[0]; + beta_0 = alphabeta[1]; + ExplicitAlphaBeta = true; + } + else { + opserr << "WARNING: unknown option: " << option << endln; + return 0; + } + } + + + if (!ExplicitAlphaBeta) { + + alpha_0 = ((m_coeff + 1) * PML_b) / (2.0 * PML_b)*log10(1.0 / R); + beta_0 = ((m_coeff + 1) * Cp) / (2.0 * PML_b)*log10(1.0 / R); + } else { + opserr << "Warning: PML Element(" << idata[0] << ") is using user defined alpha and beta\n"; + } + + // opserr << "PML3DVISCOUS element, tag: " << idata[0] << endln; + // opserr << "Node 1: " << idata[1] << endln; + // opserr << "Node 2: " << idata[2] << endln; + // opserr << "Node 3: " << idata[3] << endln; + // opserr << "Node 4: " << idata[4] << endln; + // opserr << "Node 5: " << idata[5] << endln; + // opserr << "Node 6: " << idata[6] << endln; + // opserr << "Node 7: " << idata[7] << endln; + // opserr << "Node 8: " << idata[8] << endln; + // opserr << "Element center: " << elementCenter[0] << ", " << elementCenter[1] << ", " << elementCenter[2] << endln; + // opserr << "PML Thickness: " << PMLThickness << endln; + // opserr << "Material tag: " << matTag << endln; + // opserr << "Material type: " << mat->getClassType() << endln; + // opserr << "Material information: " << endln; + // opserr << "\t E: " << E << endln; + // opserr << "\t nu: " << nu << endln; + // opserr << "\t rho: " << rho << endln; + // opserr << "Mesh Type: " << meshType << endln; + // opserr << "Xref: " << Xref[0] << ", " << Xref[1] << ", " << Xref[2] << endln; + // opserr << "Normal: " << Normal[0] << ", " << Normal[1] << ", " << Normal[2] << endln; + // opserr << "Cp: " << Cp << endln; + // opserr << "m: " << m_coeff << endln; + // opserr << "R: " << R << endln; + // opserr << "alpha_0: " << alpha_0 << endln; + // opserr << "beta_0: " << beta_0 << endln; + // opserr << "ExplicitAlphaBeta: " << ExplicitAlphaBeta << endln; + + + return new PML3DVISCOUS(idata[0], &idata[1], + mat, PMLThickness, + Xref, Normal, + alpha_0, beta_0, ExplicitAlphaBeta, + Cp, m_coeff, R, + gamma, beta, eta, keisi); +} + + +// ======================================================================= +// static data +// ======================================================================= +double PML3DVISCOUS::gamma = 0.; +double PML3DVISCOUS::beta = 0.; +double PML3DVISCOUS::eta = 0.; +double PML3DVISCOUS::keisi = 0.; +double PML3DVISCOUS::dt = 0.; +int PML3DVISCOUS::eleCount = 0; +int PML3DVISCOUS::ComputedEleTag = -1; + +double PML3DVISCOUS::M[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF] = {0}; +double PML3DVISCOUS::C[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF] = {0}; +double PML3DVISCOUS::K[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF] = {0}; +double PML3DVISCOUS::G[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF] = {0}; +double PML3DVISCOUS::H[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF] = {0}; +double PML3DVISCOUS::Keff[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF] = {0}; + + +// Matrix PML3DVISCOUS::tangent(PML3DVISCOUS_NUM_DOF, PML3DVISCOUS_NUM_DOF); +// Matrix PML3DVISCOUS::mass(PML3DVISCOUS_NUM_DOF, PML3DVISCOUS_NUM_DOF); +// Matrix PML3DVISCOUS::damping(PML3DVISCOUS_NUM_DOF, PML3DVISCOUS_NUM_DOF); +Matrix PML3DVISCOUS::tangent(K, PML3DVISCOUS_NUM_DOF, PML3DVISCOUS_NUM_DOF); +Matrix PML3DVISCOUS::mass(M, PML3DVISCOUS_NUM_DOF, PML3DVISCOUS_NUM_DOF); +Matrix PML3DVISCOUS::damping(C, PML3DVISCOUS_NUM_DOF, PML3DVISCOUS_NUM_DOF); +Matrix PML3DVISCOUS::Gmat(G, PML3DVISCOUS_NUM_DOF, PML3DVISCOUS_NUM_DOF); +Matrix PML3DVISCOUS::Hmat(H, PML3DVISCOUS_NUM_DOF, PML3DVISCOUS_NUM_DOF); +Matrix PML3DVISCOUS::keffmat(Keff, PML3DVISCOUS_NUM_DOF, PML3DVISCOUS_NUM_DOF); +Vector PML3DVISCOUS::resid(PML3DVISCOUS_NUM_DOF); +// int PML3DVISCOUS::numberOfElements = 0; + + +// ======================================================================= +// null constructor +// ======================================================================= +PML3DVISCOUS::PML3DVISCOUS() + :Element(0, ELE_TAG_PML3DVISCOUS), + connectedExternalNodes(PML3DVISCOUS_NUM_NODES), + ubar(PML3DVISCOUS_NUM_DOF), + ubart(PML3DVISCOUS_NUM_DOF), + ubarbar(PML3DVISCOUS_NUM_DOF), + ubarbart(PML3DVISCOUS_NUM_DOF) +{ + for (int i = 0; i < PML3DVISCOUS_NUM_NODES; i++) { + nodePointers[i] = 0; + } + dt = 0; + ubar.Zero(); + ubart.Zero(); + ubarbar.Zero(); + ubarbart.Zero(); + updateflag = 0; + update_dt = 0; + gamma = 0; + beta = 0; + eta = 0; + keisi = 0; + tangent.Zero(); + mass.Zero(); + damping.Zero(); + Gmat.Zero(); + Hmat.Zero(); + keffmat.Zero(); + theMaterial = 0; + PML_L = 0; + cp_ref = 0; + m_coeff = 0; + R_coeff = 0; + alpha0 = 0; + beta0 = 0; + ExplicitAlphaBeta = false; + E = 0.0; + nu = 0.0; + rho = 0.0; + + +} + +// ======================================================================= +// Full constructor +// ======================================================================= +PML3DVISCOUS::PML3DVISCOUS(int tag, int* nodeTags, + NDMaterial* theMat, + double PMLThickness, + double* Xref, double* Normal, + double alpha_0, double beta_0, bool explicitAB, + double Cp, double m_coeff, double R, + double gammaN, double betaN, double etaN, double keisiN + ):Element(tag, ELE_TAG_PML3DVISCOUS), + connectedExternalNodes(PML3DVISCOUS_NUM_NODES), + ubar(PML3DVISCOUS_NUM_DOF), + ubart(PML3DVISCOUS_NUM_DOF), + ubarbar(PML3DVISCOUS_NUM_DOF), + ubarbart(PML3DVISCOUS_NUM_DOF), + theMaterial(theMat), PML_L(PMLThickness), + cp_ref(Cp), m_coeff(m_coeff), R_coeff(R), + alpha0(alpha_0), beta0(beta_0), ExplicitAlphaBeta(explicitAB) +{ + eleCount++; + if (eleCount == 1) { + opserr << "Perfectly Matched Layer 3D (PMLVISCOUS) element - Written: W. Zhang, E. Taciroglu, A. Pakzad, P. Arduino, UCLA, U.Washington\n "; + tangent.Zero(); + mass.Zero(); + damping.Zero(); + Gmat.Zero(); + Hmat.Zero(); + keffmat.Zero(); + } + // initialize node pointers + for (int i = 0; i < PML3DVISCOUS_NUM_NODES; i++) { + connectedExternalNodes(i) = nodeTags[i]; + nodePointers[i] = 0; + } + + // initialize Newmark parameters + gamma = gammaN; + beta = betaN; + eta = etaN; + keisi = keisiN; + + // initialize the ubar and ubart vectors to zero + ubart.Zero(); + ubar.Zero(); + ubarbar.Zero(); + ubarbart.Zero(); + updateflag = 0; + update_dt = 0; + + + xref = Xref[0]; + yref = Xref[1]; + zref = Xref[2]; + + nx = Normal[0]; + ny = Normal[1]; + nz = Normal[2]; + + Parameter paramE(1); + Parameter paramNu(2); + const char* argv_E[] = {"E"}; + const char* argv_nu[] = {"nu"}; + if (strcmp(theMaterial->getClassType(), "ElasticIsotropicMaterial") == 0) { + int res = 0; + res = theMaterial->setParameter(argv_nu, 1, paramNu); + res = theMaterial->setParameter(argv_E, 1, paramE); + if (res >= 0) { + nu = paramNu.getValue(); + E = paramE.getValue(); + } else { + opserr << "Error: PML3DVISCOUS element only supports ElasticIsotropicMaterial\n"; + opserr << "\tMaterial provided is of type: " << theMaterial->getClassType() << endln; + return; + } + } + rho = theMaterial->getRho(); + // opserr << "PML3DVISCOUS element(Domain): E=" << E << ", nu=" << nu << ", rho=" << theMaterial->getRho() << endln; + + // print out the information + // opserr << "PML3DVISCOUS element, tag: " << this->getTag() << endln; + // opserr << "Node 1: " << connectedExternalNodes(0) << endln; + // opserr << "Node 2: " << connectedExternalNodes(1) << endln; + // opserr << "Node 3: " << connectedExternalNodes(2) << endln; + // opserr << "Node 4: " << connectedExternalNodes(3) << endln; + // opserr << "Node 5: " << connectedExternalNodes(4) << endln; + // opserr << "Node 6: " << connectedExternalNodes(5) << endln; + // opserr << "Node 7: " << connectedExternalNodes(6) << endln; + // opserr << "Node 8: " << connectedExternalNodes(7) << endln; + // opserr << "PML Thickness: " << PML_L << endln; + // opserr << "Material tag: " << theMaterial->getTag() << endln; + // opserr << "Material type: " << theMaterial->getClassType() << endln; + // opserr << "Material information: " << endln; + // opserr << "\t E: " << theMaterial->getElasticModulus() << endln; + // opserr << "\t nu: " << theMaterial->getPoissonsRatio() << endln; + // opserr << "\t rho: " << theMaterial->getRho() << endln; + // opserr << "Xref: " << xref << ", " << yref << ", " << zref << endln; + // opserr << "Normal: " << nx << ", " << ny << ", " << nz << endln; + // opserr << "Cp: " << cp_ref << endln; + // opserr << "m: " << m_coeff << endln; + // opserr << "R: " << R_coeff << endln; + // opserr << "alpha_0: " << alpha0 << endln; + // opserr << "beta_0: " << beta0 << endln; + // if (ExplicitAlphaBeta) { + // opserr << "ExplicitAlphaBeta: " << "True" << endln; + // } else { + // opserr << "ExplicitAlphaBeta: " << "False" << endln; + // } + // opserr << "Newmark parameters: " << endln; + // opserr << "\t gamma: " << gamma << endln; + // opserr << "\t beta: " << beta << endln; + // opserr << "\t eta: " << eta << endln; + // opserr << "\t keisi: " << keisi << endln; + // opserr << "Rayleigh Damping parameters: " << endln; + // opserr << "\t alphaM: " << alphaM << endln; + // opserr << "\t betaK: " << betaK << endln; + // opserr << "\t betaK0: " << betaK0 << endln; + // opserr << "\t betaKc: " << betaKc << endln; + +} + +// ======================================================================= +// destructor +// ======================================================================= +PML3DVISCOUS::~PML3DVISCOUS() +{ + +} + +// ======================================================================= +// Set Domain +// ======================================================================= +void PML3DVISCOUS::setDomain(Domain* theDomain) +{ + + Domainptr = theDomain; + + // node pointers + for (int i = 0; i < PML3DVISCOUS_NUM_NODES; i++) + nodePointers[i] = theDomain->getNode(connectedExternalNodes(i)); + + this->DomainComponent::setDomain(theDomain); + for (int i = 0; i < PML3DVISCOUS_NUM_NODES; i++) { + const Vector& loc = nodePointers[i]->getCrds(); + coords[i * 3] = loc(0); + coords[i * 3 + 1] = loc(1); + coords[i * 3 + 2] = loc(2); + } +} +// ======================================================================= +// Calculate the matricies +// ======================================================================= +void PML3DVISCOUS::calculateMatrices() +{ + // create the coordinate vectors + int NDOFEL = PML3DVISCOUS_NUM_DOF; + int NPROPS = 13; + int MCRD = 3; + int NNODE = 8; + int LFLAGS = 12; + for (int i = 0; i < PML3DVISCOUS_NUM_DOF*PML3DVISCOUS_NUM_DOF; i++) { + C[i] = 0.0; + K[i] = 0.0; + M[i] = 0.0; + G[i] = 0.0; + H[i] = 0.0; + } + + double betarayleigh = (betaK0 > betaK) ? betaK0 : betaK; + betarayleigh = (betaKc > betarayleigh) ? betaKc : betarayleigh; + double props[16]; + props[0] = E; + props[1] = nu; + props[2] = rho; + props[3] = 6.0; + props[4] = PML_L; + props[5] = xref; + props[6] = yref; + props[7] = zref; + props[8] = nx; + props[9] = ny; + props[10] = nz; + props[11] = alpha0; + props[12] = beta0; + props[13] = alphaM; + props[14] = betarayleigh; + props[15] = m_coeff; + + pml3d_(M, C, K, G, H, &NDOFEL, props, coords, &MCRD, &NNODE, &LFLAGS); + ComputedEleTag = this->getTag(); +} + + + +// ======================================================================= +// update +// ======================================================================= +int PML3DVISCOUS::update(void) +{ + dt = Domainptr->getDT(); + // opserr << "dt = " << dt << "\n"; + // get u, v, a from nodes and calculate the ubar vector + int loc = 0; + double c1 = dt; + double c2 = dt * dt * 0.5; + double c3 = dt*dt*dt*((1.0/6.0)-eta); + double c4 = dt*dt*dt*eta; + for (int i = 0; i < PML3DVISCOUS_NUM_NODES; i++) { + const Vector& uNode = nodePointers[i]->getDisp(); + const Vector& vNode = nodePointers[i]->getVel(); + const Vector& aNode = nodePointers[i]->getAccel(); + const Vector& atpdt = nodePointers[i]->getTrialAccel(); + for (int j = 0; j < 9; j++) { + ubar(loc) = ubart(loc) + uNode(j)*c1 + vNode(j)*c2 + aNode(j)*c3 + atpdt(j)*c4; + loc++; + } + } + + loc = 0; + c1 = dt; + c2 = dt * dt * 0.5; + c3 = dt * dt * dt /6.0; + c4 = dt * dt * dt * dt * (1.0/24.0 - keisi); + int c5 = dt * dt * dt * dt * keisi; + for (int i = 0; i < PML3DVISCOUS_NUM_NODES; i++) { + const Vector& uNode = nodePointers[i]->getDisp(); + const Vector& vNode = nodePointers[i]->getVel(); + const Vector& aNode = nodePointers[i]->getAccel(); + const Vector& atpdt = nodePointers[i]->getTrialAccel(); + for (int j = 0; j < 9; j++) { + ubarbar(loc) = ubarbart(loc) + ubart(loc)*c1 + uNode(j)*c2 + vNode(j)*c3 + aNode(j)*c4 + atpdt(j)*c5; + loc++; + } + } + + return 0; +} + +// ======================================================================= +// return stiffness matrix +// ======================================================================= +const Matrix& PML3DVISCOUS::getTangentStiff() +{ + if (ComputedEleTag != this->getTag()) { + this->calculateMatrices(); + } + + // check if the dt is changed to update the tangent stiffness matrix + double cg = eta*dt/beta; + double ch = dt * dt * keisi/beta; + //keff = k + cg*g( k and g are symmetric matrices) + for (int i = 0; i < PML3DVISCOUS_NUM_DOF*PML3DVISCOUS_NUM_DOF; i++) { + Keff[i] = K[i] + cg*G[i] + ch*H[i]; + } + return keffmat; +} + +// ======================================================================= +// return initial stiffness matrix +// ======================================================================= +const Matrix& PML3DVISCOUS::getInitialStiff() +{ + return this->getTangentStiff(); +} + +// ======================================================================= +// return mass matrix +// ======================================================================= +const Matrix& PML3DVISCOUS::getMass() +{ + if (ComputedEleTag != this->getTag()) { + this->calculateMatrices(); + } + return mass; +} + +// ======================================================================= +// return damping matrix +// ======================================================================= +const Matrix& PML3DVISCOUS::getDamp() +{ + if (ComputedEleTag != this->getTag()) { + this->calculateMatrices(); + } + return damping; +} + +// ======================================================================= +// Ressisting force +// ======================================================================= +//get residual +const Vector& PML3DVISCOUS::getResistingForce() +{ + if (ComputedEleTag != this->getTag()) { + this->calculateMatrices(); + } + int numNodalDOF = 9; + static Vector theVector(PML3DVISCOUS_NUM_DOF); + + + // + // perform: R = K * u + // + + int loc = 0; + for (int i = 0; i < PML3DVISCOUS_NUM_NODES; i++) { + const Vector& uNode = nodePointers[i]->getTrialDisp(); + for (int j = 0; j < numNodalDOF; j++) + theVector(loc++) = uNode(j); + } + resid.addMatrixVector(0.0, tangent, theVector, 1.0); + return resid; +} + + +// ======================================================================= +// +// ======================================================================= +//get residual with inertia terms +const Vector& +PML3DVISCOUS::getResistingForceIncInertia() +{ + if (ComputedEleTag != this->getTag()) { + this->calculateMatrices(); + } + // R += K*u + static Vector theVector(PML3DVISCOUS_NUM_DOF); + + int loc = 0; + for (int i = 0; i < PML3DVISCOUS_NUM_NODES; i++) { + const Vector& uNode = nodePointers[i]->getTrialDisp(); + for (int j = 0; j < 9; j++) + theVector(loc++) = uNode(j); + } + resid.addMatrixVector(0.0, tangent, theVector, 1.0); + + + + // R += M*a + loc = 0; + Node** theNodes = this->getNodePtrs(); + for (int i = 0; i < PML3DVISCOUS_NUM_NODES; i++) { + const Vector& acc = theNodes[i]->getTrialAccel(); + for (int j = 0; j < 9; j++) { + theVector(loc++) = acc(j); + } + } + resid.addMatrixVector(1.0, mass, theVector, 1.0); + + // R += C*v + loc = 0; + for (int i = 0; i < PML3DVISCOUS_NUM_NODES; i++) { + const Vector& vel = theNodes[i]->getTrialVel(); + for (int j = 0; j < 9; j++) { + theVector(loc++) = vel[j]; + } + } + resid.addMatrixVector(1.0, damping, theVector, 1.0); + + + // R += G*ubar + resid.addMatrixVector(1.0, Gmat, ubar, 1.0); + + // R += H*ubarbar + resid.addMatrixVector(1.0, Hmat, ubarbar, 1.0); + return resid; +} + +// ======================================================================= +// get the number of external nodes +// ======================================================================= +int PML3DVISCOUS::getNumExternalNodes() const +{ + return PML3DVISCOUS_NUM_NODES; +} + +// ======================================================================= +// return connected external nodes +// ======================================================================= +const ID& PML3DVISCOUS::getExternalNodes() +{ + return connectedExternalNodes; +} + +// ======================================================================= +// return node pointers +// ======================================================================= +Node** PML3DVISCOUS::getNodePtrs(void) +{ + return nodePointers; +} + +// ======================================================================= +// return number of dofs +// ======================================================================= +int PML3DVISCOUS::getNumDOF() +{ + return PML3DVISCOUS_NUM_DOF; +} + +// ======================================================================= +// commit state +// ======================================================================= +int PML3DVISCOUS::commitState() +{ + int success = 0; + if ((success = this->Element::commitState()) != 0) { + opserr << "PML3DVISCOUS::commitState () - failed in base class"; + } + + // set ubart to ubar + for (int i = 0; i < PML3DVISCOUS_NUM_DOF; i++) { + ubart(i) = ubar(i); + } + + updateflag = 0; + return success; +} + +// ======================================================================= +// revert to last commit +// ======================================================================= +int PML3DVISCOUS::revertToLastCommit() +{ + int success = 0; + + // set ubar to ubart + for (int i = 0; i < PML3DVISCOUS_NUM_DOF; i++) { + ubar(i) = ubart(i); + ubarbar(i) = ubarbart(i); + } + + return success; +} + +// ======================================================================= +// revert to start +// ======================================================================= +int PML3DVISCOUS::revertToStart() +{ + int success = 0; + + // set ubar and ubart to zero + for (int i = 0; i < PML3DVISCOUS_NUM_DOF; i++) { + ubar(i) = 0.0; + ubart(i) = 0.0; + ubarbar(i) = 0.0; + ubarbart(i) = 0.0; + } + + return success; +} + +// ======================================================================= +// add load +// ======================================================================= +int PML3DVISCOUS::addLoad(ElementalLoad* theLoad, double loadFactor) +{ + return -1; +} + +// ======================================================================= +// add zero load +// ======================================================================= +void PML3DVISCOUS::zeroLoad() +{ + return; +} + +// ======================================================================= +// senself +// ======================================================================= +int PML3DVISCOUS::sendSelf(int commitTag, + Channel& theChannel) +{ + return 0; + // int res = 0; + + // // note: we don't check for dataTag == 0 for Element + // // objects as that is taken care of in a commit by the Domain + // // object - don't want to have to do the check if sending data + // int dataTag = this->getDbTag(); + + // // PML3DVISCOUS packs its data into a Vector and sends this to theChannel + // // along with its dbTag and the commitTag passed in the arguments + // static Vector data(PML3DVISCOUS_NUM_PROPS + 4); + // data(0) = this->getTag(); + + // for (int ii = 1; ii <= PML3DVISCOUS_NUM_PROPS; ii++) { + // data(ii) = props[ii - 1]; + // } + // data(PML3DVISCOUS_NUM_PROPS+1) = eta; + // data(PML3DVISCOUS_NUM_PROPS+2) = beta; + // data(PML3DVISCOUS_NUM_PROPS+3) = gamma; + + // res += theChannel.sendVector(dataTag, commitTag, data); + // if (res < 0) { + // opserr << "WARNING PML3DVISCOUS::sendSelf() - " << this->getTag() << " failed to send Vector\n"; + // return res; + // } + + + // // PML3DVISCOUS then sends the tags of its four nodes + // res += theChannel.sendID(dataTag, commitTag, connectedExternalNodes); + // if (res < 0) { + // opserr << "WARNING PML3DVISCOUS::sendSelf() - " << this->getTag() << " failed to send ID\n"; + // return res; + // } + + // return res; +} + +// ======================================================================= +// recvself +// ======================================================================= +int PML3DVISCOUS::recvSelf(int commitTag, + Channel& theChannel, + FEM_ObjectBroker& theBroker) +{ + return 0; + // int res = 0; + + // int dataTag = this->getDbTag(); + + // // PML3DVISCOUS creates a Vector, receives the Vector and then sets the + // // internal data with the data in the Vector + // static Vector data(PML3DVISCOUS_NUM_PROPS + 4); + // res += theChannel.recvVector(dataTag, commitTag, data); + // if (res < 0) { + // opserr << "WARNING PML3DVISCOUS::recvSelf() - failed to receive Vector\n"; + // return res; + // } + + // this->setTag((int)data(0)); + + + // for (int ii = 1; ii <= PML3DVISCOUS_NUM_PROPS; ii++) { + // props[ii - 1] = data(ii); + // } + + // eta = data(PML3DVISCOUS_NUM_PROPS+1); + // beta = data(PML3DVISCOUS_NUM_PROPS+2); + // gamma = data(PML3DVISCOUS_NUM_PROPS+3); + + // // PML3DVISCOUS now receives the tags of its four external nodes + // res += theChannel.recvID(dataTag, commitTag, connectedExternalNodes); + // if (res < 0) { + // opserr << "WARNING PML3DVISCOUS::recvSelf() - " << this->getTag() << " failed to receive ID\n"; + // return res; + // } + + // return res; +} + + +// ======================================================================= +// display +// ======================================================================= +int PML3DVISCOUS::displaySelf(Renderer& theViewer, int displayMode, float fact, const char** modes, int numMode) +{ + // Get the end point display coords + static Vector v1(3); + static Vector v2(3); + static Vector v3(3); + static Vector v4(3); + static Vector v5(3); + static Vector v6(3); + static Vector v7(3); + static Vector v8(3); + nodePointers[0]->getDisplayCrds(v1, fact, displayMode); + nodePointers[1]->getDisplayCrds(v2, fact, displayMode); + nodePointers[2]->getDisplayCrds(v3, fact, displayMode); + nodePointers[3]->getDisplayCrds(v4, fact, displayMode); + nodePointers[4]->getDisplayCrds(v5, fact, displayMode); + nodePointers[5]->getDisplayCrds(v6, fact, displayMode); + nodePointers[6]->getDisplayCrds(v7, fact, displayMode); + nodePointers[7]->getDisplayCrds(v8, fact, displayMode); + + // place values in coords matrix + static Matrix Coords(8, 3); + for (int i = 0; i < 3; i++) { + Coords(0, i) = v1(i); + Coords(1, i) = v2(i); + Coords(2, i) = v3(i); + Coords(3, i) = v4(i); + Coords(4, i) = v5(i); + Coords(5, i) = v6(i); + Coords(6, i) = v7(i); + Coords(7, i) = v8(i); + } + + // fill RGB vector + static Vector values(8); + for (int i = 0; i < 8; i++) + values(i) = 1.0; + + // draw the cube + return theViewer.drawCube(Coords, values, this->getTag()); +} + +// ======================================================================= +// setresponse +// ======================================================================= +Response* PML3DVISCOUS::setResponse(const char** argv, int argc, OPS_Stream& output) +{ + Response* theResponse = 0; + + // char outputData[32]; + + // output.tag("ElementOutput"); + // output.attr("eleType", "PML3DVISCOUS"); + // output.attr("eleTag", this->getTag()); + // for (int i = 1; i <= 8; i++) { + // sprintf(outputData, "node%d", i); + // output.attr(outputData, nodePointers[i - 1]->getTag()); + // } + + // if (strcmp(argv[0], "force") == 0 || strcmp(argv[0], "forces") == 0) { + + // for (int i = 1; i <= 8; i++) { + // sprintf(outputData, "P1_%d", i); + // output.tag("ResponseType", outputData); + // sprintf(outputData, "P2_%d", i); + // output.tag("ResponseType", outputData); + // sprintf(outputData, "P3_%d", i); + // output.tag("ResponseType", outputData); + // } + + // theResponse = new ElementResponse(this, 1, resid); + // } + // output.endTag(); // ElementOutput + return theResponse; +} + +// ======================================================================= +// getresponse +// ======================================================================= +int PML3DVISCOUS::getResponse(int responseID, Information& eleInfo) +{ + // static Vector stresses(48); + + // if (responseID == 1) + // return eleInfo.setVector(this->getResistingForce()); + + return -1; +} + +// ======================================================================= +// set parameter +// ======================================================================= +int PML3DVISCOUS::setParameter(const char** argv, int argc, Parameter& param) +{ + int res = -1; + return res; +} + +// ======================================================================= +// update parameter +// ======================================================================= +int PML3DVISCOUS::updateParameter(int parameterID, Information& info) +{ + int res = -1; + return res; +} + +// ======================================================================= +// print +// ======================================================================= +void PML3DVISCOUS::Print(OPS_Stream &s, int flag) { + + if (flag == OPS_PRINT_CURRENTSTATE) { + s << "Element: " << this->getTag() << endln; + s << "type: PML3DVISCOUS \n"; + s << "Nodes: " << connectedExternalNodes; + s << "eta: " << eta << " beta: " << beta << " gamma: " << gamma << endln; + s << endln; + s << "Resisting Force (no inertia): " << this->getResistingForce(); + } + + if (flag == OPS_PRINT_PRINTMODEL_JSON) { + s << "\t\t\t{"; + s << "\"name\": " << this->getTag() << ", "; + s << "\"type\": \"PML3DVISCOUS\", "; + s << "\"nodes\": [" << connectedExternalNodes(0) << ", "; + for (int i = 1; i < 7; i++) + s << connectedExternalNodes(i) << ", "; + s << connectedExternalNodes(7) << "], "; + } + return; +} diff --git a/SRC/element/PML/PML3DVISCOUS.h b/SRC/element/PML/PML3DVISCOUS.h new file mode 100644 index 0000000000..42755d49df --- /dev/null +++ b/SRC/element/PML/PML3DVISCOUS.h @@ -0,0 +1,175 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + + +// Written by: Amin Pakzad, Pedro Arduino (parduino@uw.edu) +// +// Eight node PML3D element .. a c++ wrapper to fortran routine +// provided by Wenyang Zhang (zwyll@ucla.edu), University of California, Los Angeles +// +// University of Washington, UC. Los Angeles, U.C. Berkeley, 12, 2020 + + +#ifndef PML3DVISCOUS_H +#define PML3DVISCOUS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PML3DVISCOUS_NUM_DOF 72 +#define PML3DVISCOUS_NUM_PROPS 12 +#define PML3DVISCOUS_NUM_NODES 8 + +#ifdef _WIN32 + +#define pml3d_ PML_3D + +extern "C" void pml3d_(double* mMatrix, + double* cMatrix, + double* kMatrix, + double* gMatrix, + double* hMatrix, + int* NDOFEL, + double* PROPS, + double* COORDS, + int* MCRD, + int* NNODE, + int* LFLAGS); + +#else + +#define pml3d_ pml_3d_ + +extern "C" void pml3d_(double* mMatrix, + double* cMatrix, + double* kMatrix, + double* gMatrix, + double* hMatrix, + int* NDOFEL, + double* PROPS, + double* COORDS, + int* MCRD, + int* NNODE, + int* LFLAGS); + +#endif + +class PML3DVISCOUS : public Element { + +public: + + PML3DVISCOUS(); //null constructor + // PML3DVISCOUS(int tag, int* nodeTags, double* newmarks, double* dData); // full constructor + PML3DVISCOUS(int tag, int* nodeTags, + NDMaterial* theMat, double PMLThickness, + double* Xref, double* Normal, + double alpha_0, double beta_0, bool explicitAB, + double Cp, double m_coeff, double R, + double gammaN, double betaN, double etaN, double keisiN); // full constructor + + virtual ~PML3DVISCOUS(); //destructor + const char* getClassType(void) const { return "PML3DVISCOUS"; }; //return class type + void setDomain(Domain* theDomain); // set domain + int getNumExternalNodes() const; // get number of external nodes + const ID& getExternalNodes(); // get external nodes + Node** getNodePtrs(void); // get external nodes + int getNumDOF(); // get number of DOF + int commitState(); // commit state + int revertToLastCommit(); // revert to last commit + int revertToStart(); // revert to start + int update(void); // update + void Print(OPS_Stream& s, int flag); // print out element data + const Matrix& getTangentStiff(); // get stiffness matrix + const Matrix& getInitialStiff(); // get initial stiffness matrix + const Matrix& getMass(); // get mass matrix + const Matrix& getDamp(); // get damping matrix + void zeroLoad(); // set residual to 0 + int addLoad(ElementalLoad* theLoad, double loadFactor); // add element loads + const Vector& getResistingForce(); // get residual + const Vector& getResistingForceIncInertia(); // get residual including damping forces + int sendSelf(int commitTag, Channel& theChannel); // send self + int recvSelf(int commitTag, Channel& theChannel, FEM_ObjectBroker & theBroker); // receive self + Response* setResponse(const char** argv, int argc, OPS_Stream& s); // set response + int getResponse(int responseID, Information& eleInformation); // get response + int setParameter(const char** argv, int argc, Parameter& param); + int updateParameter(int parameterID, Information& info); // update parameter + int displaySelf(Renderer&, int mode, float fact, const char** displayModes = 0, int numModes = 0); + +private: + void calculateMatrices(); // calculate matrices method + Domain* Domainptr; // pointer to the domain + // double props[PML3DVISCOUS_NUM_PROPS]; // material properties + ID connectedExternalNodes; //eight node numbers + Node* nodePointers[PML3DVISCOUS_NUM_NODES]; //pointers to eight nodes + static double K[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF]; // stiffness matrix + static double C[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF]; // damping matrix + static double M[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF]; // mass matrix + static double G[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF]; // G matrix + static double H[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF]; // H matrix + static double Keff[PML3DVISCOUS_NUM_DOF * PML3DVISCOUS_NUM_DOF]; // effective stiffness matrix + static double gamma; // Newmark parameters: gamma + static double beta; // Newmark parameters: beta + static double eta; // Newmark parameters: eta + static double keisi; // Newmark parameters: keisi + static Matrix tangent; // tangent matrix + static Vector resid; // residual vector + static Matrix mass; // mass matrix + static Matrix damping; // damping matrix + static Matrix Gmat; // G matrix + static Matrix Hmat; // H matrix + static Matrix keffmat; // effective stiffness matrix + Vector ubart; // ubar at time t + Vector ubarbart; // ubarbar at time t + Vector ubar; // ubar at time t+dt + Vector ubarbar; // ubarbar at time t+dt + static double dt; // time step + int updateflag; // update flag + int update_dt; // flag for updating dt + static int eleCount; // element count + static int ComputedEleTag; // computed element tag + double coords[24]; + // int innertag; // inner tag + // static int numberOfElements; // number of elements + double alpha0; // alpha0 pml parameter + double beta0; // beta0 pml parameter + double xref, yref, zref; // reference point + double nx, ny, nz; // normal vector + const char* meshtype; // type of mesh + double PML_L; // PML minimum thickness + double m_coeff; // m parameter for PML + double R_coeff; // PML damping ratio + double cp_ref; // reference wave speed + bool ExplicitAlphaBeta; // flag for explicit alpha beta + + NDMaterial* theMaterial; // pointer to the material + double E, nu, rho; // material properties: E, nu, rho + +}; + +#endif + diff --git a/SRC/element/PML/pml_3d.f b/SRC/element/PML/pml_3d.f index 31475ad05f..af71152435 100644 --- a/SRC/element/PML/pml_3d.f +++ b/SRC/element/PML/pml_3d.f @@ -1,134 +1,47 @@ -c------------------------------------------------------------------------------ -c Complete UEL file for Perfectly-Matched-Layer (PML) (3D) -c------------------------------------------------------------------------------ -c Note: 1) Please do not distribute the material model routines, and if -c anyone asks, please refer them to Prof. Ertugrul Taciroglu -c (etacir@ucla.edu) -c 2) Please properly acknowledge our related publications when you -c publish your results -c Ref: Zhang W, Esmaeilzadeh Seylabi E, Taciroglu E. An ABAQUS toolbox for -c soil-structure interaction analysis. Computers and Geotechnics. 114 -c (2019): 103143. -c------------------------------------------------------------------------------ -c Authors: Wenyang Zhang (zwyll@ucla.edu) -c University of California, Los Angeles -c------------------------------------------------------------------------------ -c Function inputs given by the user: -c -c E = PROPS(1) --- Young's modulus -c xnu = PROPS(2) --- Poisson's Ratio -c rho = PROPS(3) --- Density -c EleType_pos = floor(PROPS(4)) --- Element type, See line -c PML_L = PROPS(5) --- Thickness of the PML -c afp = PROPS(6) --- Coefficient m, typically m = 2 -c PML_Rcoef = PROPS(7) --- Coefficient R, typically R = 1e-8 -c RD_half_width_x = PROPS(8) --- Halfwidth of the regular domain in x-direction -c RD_half_width_y = PROPS(9) --- Halfwidth of the regular domain in y-direction -c RD_depth = PROPS(10) --- Depth of the regular domain -c Damp_alpha = PROPS(11) --- Rayleigh damping coefficient alpha -c Damp_beta = PROPS(12) --- Rayleigh damping coefficient beta -!=========================== ABAQUS format user element subroutine =================== - -c SUBROUTINE UEL(RHS,AMATRX,SVARS,ENERGY,NDOFEL,NRHS,NSVARS, -c 1 PROPS,NPROPS,COORDS,MCRD,NNODE,U,DU,V,A,JTYPE,TIME,DTIME, -c 2 KSTEP,KINC,JELEM,PARAMS,NDLOAD,JDLTYP,ADLMAG,PREDEF,NPREDF, -c 3 LFLAGS,MLVARX,DDLMAG,MDLOAD,PNEWDT,JPROPS,NJPROP,PERIOD) -c ! -c INCLUDE 'ABA_PARAM.INC' -c ! -c ! -c DIMENSION MTRX(NDF,NDF),KTRX(NDF,NDF),C(NDF,NDF), NDF, (*), -c 1 SVARS(*),ENERGY(8),COORDS(MCRD,NNODE),U(NDOFEL), -c 2 DU(MLVARX,*),V(NDOFEL),A(NDOFEL),TIME(2),PARAMS(*), -c 3 JDLTYP(MDLOAD,*),ADLMAG(MDLOAD,*),DDLMAG(MDLOAD,*), -c 4 PREDEF(2,NPREDF,NNODE),LFLAGS(*),JPROPS(*) - - SUBROUTINE PML_3D(MMTRX,CMTRX,KMTRX,GMTRX, NDF, - 1 PROPS,NPROPS,COORDS,MCRD,NNODE) - - - REAL *8 MMTRX,CMTRX,KMTRX,GMTRX,PROPS,COORDS,PARAMS +! Modify material properties +! Modify cp_ref for PML - INTEGER *4 NDF,NRHS,NPROPS,MCRD,NNODE - - DIMENSION MMTRX(NDF,NDF),CMTRX(NDF,NDF),KMTRX(NDF,NDF),PROPS(*), - 1 COORDS(MCRD,NNODE),GMTRX(NDF,NDF) +! +! ABAQUS format UEL subroutine +! +! This file is compatible with ABAQUS/Standard +! +! The example implements a standard fully integrated 3D linear elastic continuum element +! +! The file also contains the following subrouines: +! abq_UEL_3D_integrationpoints - defines integration ponits for 3D continuum elements +! abq_UEL_3D_shapefunctions - defines shape functions for 3D continuum elements +! abq_UEL_invert3D - computes the inverse and determinant of a 3x3 matrix +! abq_facenodes_3D - returns list of nodes on the face of a 3D element +! +!=========================== ABAQUS format user element subroutine =================== + SUBROUTINE PML_3D(MMATRX,CMATRX,KMATRX,GMATRX,HMATRX, + 1 NDOFEL,PROPS,COORDS,MCRD,NNODE,LFLAGS) ! - ! Variables that must be computed in this routine - ! RHS(i) Right hand side vector. Dimensions are RHS(MLVARX,1) - ! AMATRX(i,j) Stiffness matrix d RHS(i)/ d DU(j) - ! SVARS(1:NSVARS) Element state variables. Must be updated in this routine - ! ENERGY(1:8) - ! Energy(1) Kinetic Energy - ! Energy(2) Elastic Strain Energy - ! Energy(3) Creep Dissipation - ! Energy(4) Plastic Dissipation - ! Energy(5) Viscous Dissipation - ! Energy(6) Artificial strain energy - ! Energy(7) Electrostatic energy - ! Energy(8) Incremental work done by loads applied to the element - ! PNEWDT Allows user to control ABAQUS time increments. - ! If PNEWDT<1 then time step is abandoned and computation is restarted with - ! a time increment equal to PNEWDT*DTIME - ! If PNEWDT>1 ABAQUS may increase the time increment by a factor PNEWDT - ! - ! Variables provided for information - ! NDF Total # DOF for the element - ! NRHS Dimension variable - ! NSVARS Total # element state variables - ! PROPS(1:NPROPS) User-specified properties of the element - ! NPROPS No. properties - ! JPROPS(1:NJPROPS) Integer valued user specified properties for the element - ! NJPROPS No. integer valued properties - ! COORDS(i,N) ith coordinate of Nth node on element - ! MCRD Maximum of (# coords,minimum of (3,#DOF)) on any node - ! U Vector of DOF at the end of the increment - ! DU Vector of DOF increments - ! V Vector of velocities (defined only for implicit dynamics) - ! A Vector of accelerations (defined only for implicit dynamics) - ! TIME(1:2) TIME(1) Current value of step time - ! TIME(2) Total time - ! DTIME Time increment - ! KSTEP Current step number - ! KINC Increment number - ! JELEM User assigned element number in ABAQUS (internally assigned) - ! NDLOAD Number of user-defined distributed loads defined for this element - ! JDLTYP(1:NDLOAD) Integers n defining distributed load types defined as Un or (if negative) UnNU in input file - ! ADLMAG(1:NDLOAD) Distributed load magnitudes - ! DDLMAG(1:NDLOAD) Increment in distributed load magnitudes - ! PREDEF(1:2,1:NPREDF,1:NNODE) Predefined fields. - ! PREDEF(1,...) Value of predefined field - ! PREDEF(2,...) Increment in predefined field - ! PREDEF(1:2,1,k) Value of temperature/temperature increment at kth node - ! PREDEF(1:2,2:NPREDF,k) Value of user defined field/field increment at kth node - ! NPREDF Number of predefined fields - ! LFLAGS Control variable - ! LFLAGS(1) Defines procedure type - ! LFLAGS(2) 0 => small displacement analysis 1 => Large displacement (NLGEOM option) - ! LFLAGS(3) 1 => Subroutine must return both RHS and AMATRX - ! 2 => Subroutine must return stiffness AMATRX = -dF/du - ! 3 => Subroutine must return daming matrix AMATRX = -dF/dudot - ! 4 => Subroutine must return mass matrix AMATRX = -dF/duddot - ! 5 => Define the RHS only - ! 6 => Define the mass matrix for the initial acceleration calculation - ! 100 => Define perturbation quantities for output - ! LFLAGS(4) 0 => General step 1 => linear perturbation step - ! LFLAGS(5) 0 => current approximation to solution based on Newton correction; 1 => based on extrapolation - ! MLVARX Dimension variable for RHS - ! PERIOD Time period of the current step - ! + ! INCLUDE 'ABA_PARAM.INC' + ! ! + REAL *8 PROPS,COORDS,MMATRX, CMATRX, KMATRX, GMATRX, HMATRX + INTEGER *4 NDOFEL,MCRD,NNODE,LFLAGS + + DIMENSION MMATRX(NDOFEL,NDOFEL), + 1 CMATRX(NDOFEL,NDOFEL), + 2 KMATRX(NDOFEL,NDOFEL), + 3 GMATRX(NDOFEL,NDOFEL), + 4 HMATRX(NDOFEL,NDOFEL), + 5 PROPS(*),COORDS(MCRD,NNODE),LFLAGS(*) + ! Local Variables real*8 ZERO,ONE,HALF PARAMETER ( ZERO = 0.D0, HALF = 0.5D0, ONE = 1.D0 ) - real*8 coef_alpha + real*8 coef_alpha, coef_beta PARAMETER (coef_alpha = 1.d0/12.d0) + PARAMETER (coef_beta = 1.d0/48.d0) - integer :: i,j,n_points,kint, nfacenodes, ipoin - integer :: face_node_list(8) ! List of nodes on an element face + integer :: i,j,n_points,kint ! double precision :: xi(3,64) ! Volumetric Integration points double precision :: w(64) ! Integration weights @@ -136,29 +49,21 @@ SUBROUTINE PML_3D(MMTRX,CMTRX,KMTRX,GMTRX, NDF, double precision :: dNdxi(20,3) ! 3D Shape function derivatives double precision :: dxdxi(3,3) ! Derivative of position wrt normalized coords double precision :: dNdx(20,3) ! Derivative of shape functions wrt spatial coords - ! - ! Variables below are for computing integrals over element faces - double precision :: face_coords(3,8) ! Coords of nodes on an element face - double precision :: xi2(2,9) ! Area integration points - double precision :: N2(9) ! 2D shape functions - double precision :: dNdxi2(9,2) ! 2D shape function derivatives - double precision :: norm(3) ! Normal to an element face - double precision :: dxdxi2(3,2) ! Derivative of spatial coord wrt normalized areal coord - ! - + + double precision :: strain(6) ! Strain vector contains [e11, e22, e33, 2e12, 2e13, 2e23] + double precision :: stress(6) ! Stress vector contains [s11, s22, s33, s12, s13, s23] + double precision :: D(6,6) ! stress = D*(strain) (NOTE FACTOR OF 2 in shear strain) double precision :: B(6,60) ! strain = B*(dof_total) double precision :: dxidx(3,3), determinant ! Jacobian inverse and determinant - double precision :: E, xnu, D44, D11, D12 ! Material properties + double precision :: E, xnu ! Material properties double precision :: Phi(3,60) ! Matrix consists of shape functions [N1 N2 ... N20] - double precision :: MMATRX(NDF,NDF) ! Element mass matrix - double precision :: KMATRX(NDF,NDF) ! Element stiffness matrix - double precision :: CMATRX(NDF,NDF) ! Element damping matrix - double precision :: GMATRX(NDF,NDF) ! Element G matrix + double precision :: rho ! Density of the material - double precision :: PML_L,afp,PML_Rcoef ! Parameters of PML - double precision :: RD_half_width_x, RD_half_width_y ! Parameters of PML - double precision :: RD_depth ! Parameters of PML + double precision :: PML_L,afp ! Parameters of PML + double precision :: alpha_0, beta_0 ! Parameters of PML + double precision :: x1_0, x2_0, x3_0 ! Parameters of PML + double precision :: n1, n2, n3 ! Parameters of PML integer :: EleType_pos ! Parameters of PML double precision :: x1,x2,x3,PML_alpha_beta(2,3) ! Coordinates x, y and z, alphas and betas @@ -171,75 +76,74 @@ SUBROUTINE PML_3D(MMTRX,CMTRX,KMTRX,GMTRX, NDF, double precision :: Phi_x(8), Phi_y(8), Phi_z(8) ! Derivative of shape functions for displacement fields [N1,i N2,i ... N8,i]^T double precision :: lambda, mu ! Lame' constants double precision :: M_RD(24,24) ! Mass matrix for regular domain + double precision :: C_RD(24,24) ! Damping matrix for regular domain double precision :: M_a(24,24),M_b(24,24),M_c(24,24),M_d(24,24) ! Mass matrices double precision :: N_a(48,48),N_b(48,48),N_c(48,48),N_d(48,48) ! N matrices for PML double precision :: A_eu(24,48), A_wu(24,48), A_pu(24,48) ! A_iu matrices for PML, where i = e, w, p double precision :: A_el(24,48), A_wl(24,48), A_pl(24,48) ! A_il matrices for PML, where i = e, w, p double precision :: K_PML(72,72), M_PML(72,72), C_PML(72,72) ! Stiffnee, mass and damping matrices for PML double precision :: G_PML(72,72) ! G matrices for PML + double precision :: H_PML(72,72) ! H matrices for PML double precision :: d_bar_n(72), d_bar_n1(72) ! d_bar at previous and current step + double precision :: d_bar_dot_n(72), d_bar_dot_n1(72) ! d_bar_dot at previous and current step + double precision :: U_n(72), V_n(72), A_n(72) ! U, V, A at previous step - integer :: NodeDOF ! Number of DOF per node + integer :: NodeDOF double precision :: Damp_alpha, Damp_beta ! Damping coefficients for Rayleigh Damping + - NodeDOF = NDF/NNODE - ! - ! Example ABAQUS UEL implementing 3D linear elastic elements - ! El props are: + NodeDOF = NDOFEL/NNODE + + - ! PROPS(1) Young's modulus - ! PROPS(2) Poisson's ratio if (NNODE == 4) n_points = 1 ! Linear tet if (NNODE == 10) n_points = 4 ! Quadratic tet if (NNODE == 8) n_points = 27 ! Linear Hex if (NNODE == 20) n_points = 27 ! Quadratic hex - + ! Local Variables call abq_UEL_3D_integrationpoints(n_points, NNODE, xi, w) - MMATRX(1:NDF,1:NDF) = 0.d0 - KMATRX(1:NDF,1:NDF) = 0.d0 - CMATRX(1:NDF,1:NDF) = 0.d0 - GMATRX(1:NDF,1:NDF) = 0.d0 + + MMATRX(1:NDOFEL,1:NDOFEL) = 0.d0 + KMATRX(1:NDOFEL,1:NDOFEL) = 0.d0 + CMATRX(1:NDOFEL,1:NDOFEL) = 0.d0 + GMATRX(1:NDOFEL,1:NDOFEL) = 0.d0 + HMATRX(1:NDOFEL,1:NDOFEL) = 0.d0 + E = PROPS(1) xnu = PROPS(2) rho = PROPS(3) EleType_pos = floor(PROPS(4)) PML_L = PROPS(5) - afp = PROPS(6) - PML_Rcoef = PROPS(7) - RD_half_width_x = PROPS(8) - RD_half_width_y = PROPS(9) - RD_depth = PROPS(10) - Damp_alpha = PROPS(11) - Damp_beta = PROPS(12) - - -c write(6,*) ' E = ',E,' xnu = ',xnu,' rho = ', rho -c write(6,*) ' Etype = ',EleType_pos,' PML_L = ',PML_L -c write(6,*) ' afp = ',afp,' PML_Rcoef = ',PML_Rcoef -c write(6,*) ' RD_halfwidth_x = ',RD_half_width_x -c write(6,*) ' RD_halfwidth_y = ',RD_half_width_y -c write(6,*) ' RD_Depth = ',RD_depth -c do i=1,NNODE -c write(6,*) COORDS(1,i),' ',COORDS(2,i),' ',COORDS(3,i) -c end do - -c write(6,*) + x1_0 = PROPS(6) + x2_0 = PROPS(7) + x3_0 = PROPS(8) + n1 = PROPS(9) + n2 = PROPS(10) + n3 = PROPS(11) + alpha_0 = PROPS(12) + beta_0 = PROPS(13) + Damp_alpha = PROPS(14) + Damp_beta = PROPS(15) + afp = PROPS(16) + + IF (afp .LT. 3.d0) THEN n_points = 27 else n_points = 64 endif - + lambda = xnu*E/( (1.d0+xnu)*(1.d0-2.D0*xnu) ) mu = 0.5D0*E/(1.d0+xnu) + M_RD = 0.d0 M_a = 0.d0 M_b = 0.d0 @@ -260,19 +164,24 @@ SUBROUTINE PML_3D(MMTRX,CMTRX,KMTRX,GMTRX, NDF, A_pl = 0.d0 K_RD = 0.d0 + C_RD = 0.d0 K_PML = 0.d0 C_PML = 0.d0 M_PML = 0.d0 G_PML = 0.d0 + H_PML = 0.d0 d_bar_n = 0.d0 d_bar_n1 = 0.d0 + + d_bar_dot_n = 0.d0 + d_bar_dot_n1 = 0.d0 U_n = 0.d0 V_n = 0.d0 A_n = 0.d0 - + ! -- Loop over integration points do kint = 1, n_points call abq_UEL_3D_shapefunctions(xi(1:3,kint),NNODE,N,dNdxi) @@ -290,402 +199,471 @@ SUBROUTINE PML_3D(MMTRX,CMTRX,KMTRX,GMTRX, NDF, B(6,2:3*NNODE-1:3) = dNdx(1:NNODE,3) B(6,3:3*NNODE:3) = dNdx(1:NNODE,2) - Phi = 0.d0 - Phi(1,1:3*NNODE-2:3) = N(1:NNODE) - Phi(2,2:3*NNODE-1:3) = N(1:NNODE) - Phi(3,3:3*NNODE:3) = N(1:NNODE) - - Phi_x = 0.d0 - Phi_y = 0.d0 - Phi_z = 0.d0 - Phi_x(1:NNODE) = dNdx(1:NNODE,1) - Phi_y(1:NNODE) = dNdx(1:NNODE,2) - Phi_z(1:NNODE) = dNdx(1:NNODE,3) - + ! strain = matmul(B(1:6,1:3*NNODE),U(1:3*NNODE)) - x1 = 0.d0 - x2 = 0.d0 - x3 = 0.d0 - - do i = 1,NNODE - x1 = x1 + N(i)*coords(1,i) - x2 = x2 + N(i)*coords(2,i) - x3 = x3 + N(i)*coords(3,i) - end do - - call PML_alpha_beta_function(PROPS,x1,x2,x3,PML_alpha_beta) - - coef_a = PML_alpha_beta(1,1)*PML_alpha_beta(1,2) - 1 *PML_alpha_beta(1,3) + stress = matmul(D,strain) - coef_b = PML_alpha_beta(1,1)*PML_alpha_beta(1,2) - 1 *PML_alpha_beta(2,3) + - 2 PML_alpha_beta(1,1)*PML_alpha_beta(1,3) - 3 *PML_alpha_beta(2,2) + - 4 PML_alpha_beta(1,2)*PML_alpha_beta(1,3) - 5 *PML_alpha_beta(2,1) - - coef_c = PML_alpha_beta(1,1)*PML_alpha_beta(2,2) - 1 *PML_alpha_beta(2,3) + - 2 PML_alpha_beta(1,2)*PML_alpha_beta(2,3) - 3 *PML_alpha_beta(2,1) + - 4 PML_alpha_beta(1,3)*PML_alpha_beta(2,2) - 5 *PML_alpha_beta(2,1) - - coef_d = PML_alpha_beta(2,1)*PML_alpha_beta(2,2) - 1 *PML_alpha_beta(2,3) - - coef_Le = 0.d0 - coef_Lp = 0.d0 - coef_Lw = 0.d0 + + ! ALPHA = PARAMS(1) + ! BETA = PARAMS(2) + ! GAMMA = PARAMS(3) + + ! DADU = ONE/(BETA*DTIME**2.d0) + ! DVDU = GAMMA/(BETA*DTIME) + + Phi = 0.d0 + Phi(1,1:3*NNODE-2:3) = N(1:NNODE) + Phi(2,2:3*NNODE-1:3) = N(1:NNODE) + Phi(3,3:3*NNODE:3) = N(1:NNODE) + + Phi_x = 0.d0 + Phi_y = 0.d0 + Phi_z = 0.d0 + Phi_x(1:NNODE) = dNdx(1:NNODE,1) + Phi_y(1:NNODE) = dNdx(1:NNODE,2) + Phi_z(1:NNODE) = dNdx(1:NNODE,3) + + + x1 = 0.d0 + x2 = 0.d0 + x3 = 0.d0 + + do i = 1,NNODE + x1 = x1 + N(i)*coords(1,i) + x2 = x2 + N(i)*coords(2,i) + x3 = x3 + N(i)*coords(3,i) + end do + + + + ! call PML_alpha_beta_function(PROPS,x1,x2,x3,PML_alpha_beta) + ! PML_alpha_beta(1,1) = 1.d0 + alpha_0*((x1 -x1_0) * n1 /PML_L)**afp + ! PML_alpha_beta(1,2) = 1.d0 + alpha_0*((x2 -x2_0) * n2 /PML_L)**afp + ! PML_alpha_beta(1,3) = 1.d0 + alpha_0*((x3 -x3_0) * n3 /PML_L)**afp + PML_alpha_beta(1,1) = alpha_0*((x1 -x1_0) * n1 /PML_L)**afp + PML_alpha_beta(1,2) = alpha_0*((x2 -x2_0) * n2 /PML_L)**afp + PML_alpha_beta(1,3) = alpha_0*((x3 -x3_0) * n3 /PML_L)**afp + PML_alpha_beta(1,1) = 1.d0 + PML_alpha_beta(1,1) + PML_alpha_beta(1,2) = 1.d0 + PML_alpha_beta(1,2) + PML_alpha_beta(1,3) = 1.d0 + PML_alpha_beta(1,3) + + PML_alpha_beta(2,1) = beta_0*((x1 -x1_0) * n1 /PML_L)**afp + PML_alpha_beta(2,2) = beta_0*((x2 -x2_0) * n2 /PML_L)**afp + PML_alpha_beta(2,3) = beta_0*((x3 -x3_0) * n3 /PML_L)**afp + + coef_a = PML_alpha_beta(1,1)*PML_alpha_beta(1,2) + 1 *PML_alpha_beta(1,3) - do i = 1,3 + + + coef_b = PML_alpha_beta(1,1)*PML_alpha_beta(1,2) + 1 *PML_alpha_beta(2,3) + + 2 PML_alpha_beta(1,1)*PML_alpha_beta(1,3) + 3 *PML_alpha_beta(2,2) + + 4 PML_alpha_beta(1,2)*PML_alpha_beta(1,3) + 5 *PML_alpha_beta(2,1) + + coef_c = PML_alpha_beta(1,1)*PML_alpha_beta(2,2) + 1 *PML_alpha_beta(2,3) + + 2 PML_alpha_beta(1,2)*PML_alpha_beta(2,3) + 3 *PML_alpha_beta(2,1) + + 4 PML_alpha_beta(1,3)*PML_alpha_beta(2,2) + 5 *PML_alpha_beta(2,1) + + coef_d = PML_alpha_beta(2,1)*PML_alpha_beta(2,2) + 1 *PML_alpha_beta(2,3) + + coef_Le = 0.d0 + coef_Lp = 0.d0 + coef_Lw = 0.d0 + + do i = 1,3 do j = 1,3 - coef_Le(i,j) = PML_alpha_beta(1,i)*PML_alpha_beta(1,j) - coef_Lp(i,j) = PML_alpha_beta(1,i)*PML_alpha_beta(2,j) + - 1 PML_alpha_beta(2,i)*PML_alpha_beta(1,j) - coef_Lw(i,j) = PML_alpha_beta(2,i)*PML_alpha_beta(2,j) + coef_Le(i,j) = PML_alpha_beta(1,i)*PML_alpha_beta(1,j) + coef_Lp(i,j) = PML_alpha_beta(1,i)*PML_alpha_beta(2,j) + + 1 PML_alpha_beta(2,i)*PML_alpha_beta(1,j) + coef_Lw(i,j) = PML_alpha_beta(2,i)*PML_alpha_beta(2,j) end do - end do - - - do i = 1,NNODE + end do + + + do i = 1,NNODE do j = 1,NNODE - Kxx(i,j) = (lambda + 2.d0*mu) * Phi_x(i)*Phi_x(j) + - 1 mu*(Phi_y(i)*Phi_y(j)+Phi_z(i)*Phi_z(j)) - Kyy(i,j) = (lambda + 2.d0*mu) * Phi_y(i)*Phi_y(j) + - 1 mu*(Phi_x(i)*Phi_x(j)+Phi_z(i)*Phi_z(j)) - Kzz(i,j) = (lambda + 2.d0*mu) * Phi_z(i)*Phi_z(j) + - 1 mu*(Phi_x(i)*Phi_x(j)+Phi_y(i)*Phi_y(j)) - - Kxy(i,j) = lambda * Phi_x(i)*Phi_y(j) + - 1 mu * Phi_y(i)*Phi_x(j) - - Kxz(i,j) = lambda * Phi_x(i)*Phi_z(j) + - 1 mu * Phi_z(i)*Phi_x(j) - - Kyz(i,j) = lambda * Phi_y(i)*Phi_z(j) + - 1 mu * Phi_z(i)*Phi_y(j) - - M_RD(i,j) = M_RD(i,j) + rho*N(i)*N(j)*w(kint)*determinant - M_a(i,j) = M_a(i,j) + - 1 coef_a*rho*N(i)*N(j)*w(kint)*determinant - M_b(i,j) = M_b(i,j) + - 1 coef_b*rho*N(i)*N(j)*w(kint)*determinant + Kxx(i,j) = (lambda + 2.d0*mu) * Phi_x(i)*Phi_x(j) + + 1 mu*(Phi_y(i)*Phi_y(j)+Phi_z(i)*Phi_z(j)) + Kyy(i,j) = (lambda + 2.d0*mu) * Phi_y(i)*Phi_y(j) + + 1 mu*(Phi_x(i)*Phi_x(j)+Phi_z(i)*Phi_z(j)) + Kzz(i,j) = (lambda + 2.d0*mu) * Phi_z(i)*Phi_z(j) + + 1 mu*(Phi_x(i)*Phi_x(j)+Phi_y(i)*Phi_y(j)) + + Kxy(i,j) = lambda * Phi_x(i)*Phi_y(j) + + 1 mu * Phi_y(i)*Phi_x(j) + + Kxz(i,j) = lambda * Phi_x(i)*Phi_z(j) + + 1 mu * Phi_z(i)*Phi_x(j) + + Kyz(i,j) = lambda * Phi_y(i)*Phi_z(j) + + 1 mu * Phi_z(i)*Phi_y(j) + + M_RD(i,j) = M_RD(i,j) + rho*N(i)*N(j)*w(kint)*determinant + M_a(i,j) = M_a(i,j) + + 1 coef_a*rho*N(i)*N(j)*w(kint)*determinant + + + + + M_b(i,j) = M_b(i,j) + + 1 coef_b*rho*N(i)*N(j)*w(kint)*determinant M_c(i,j) = M_c(i,j) + - 1 coef_c*rho*N(i)*N(j)*w(kint)*determinant + 1 coef_c*rho*N(i)*N(j)*w(kint)*determinant M_d(i,j) = M_d(i,j) + - 1 coef_d*rho*N(i)*N(j)*w(kint)*determinant - + 1 coef_d*rho*N(i)*N(j)*w(kint)*determinant + A_eu(i,j) = A_eu(i,j) + - 1 Phi_x(i)*N(j)*coef_Le(2,3)*w(kint)*determinant + 1 Phi_x(i)*N(j)*coef_Le(2,3)*w(kint)*determinant A_eu(i,j+NNODE*3) = A_eu(i,j+NNODE*3) + - 1 Phi_y(i)*N(j)*coef_Le(1,3)*w(kint)*determinant + 1 Phi_y(i)*N(j)*coef_Le(1,3)*w(kint)*determinant A_eu(i,j+NNODE*4) = A_eu(i,j+NNODE*4) + - 1 Phi_z(i)*N(j)*coef_Le(1,2)*w(kint)*determinant - + 1 Phi_z(i)*N(j)*coef_Le(1,2)*w(kint)*determinant + A_eu(i+NNODE,j+NNODE) = A_eu(i+NNODE,j+NNODE) + - 1 Phi_y(i)*N(j)*coef_Le(1,3)*w(kint)*determinant + 1 Phi_y(i)*N(j)*coef_Le(1,3)*w(kint)*determinant A_eu(i+NNODE,j+NNODE*3) = A_eu(i+NNODE,j+NNODE*3) + - 1 Phi_x(i)*N(j)*coef_Le(2,3)*w(kint)*determinant + 1 Phi_x(i)*N(j)*coef_Le(2,3)*w(kint)*determinant A_eu(i+NNODE,j+NNODE*5) = A_eu(i+NNODE,j+NNODE*5) + - 1 Phi_z(i)*N(j)*coef_Le(1,2)*w(kint)*determinant - + 1 Phi_z(i)*N(j)*coef_Le(1,2)*w(kint)*determinant + A_eu(i+NNODE*2,j+NNODE*2) = A_eu(i+NNODE*2,j+NNODE*2) + - 1 Phi_z(i)*N(j)*coef_Le(1,2)*w(kint)*determinant + 1 Phi_z(i)*N(j)*coef_Le(1,2)*w(kint)*determinant A_eu(i+NNODE*2,j+NNODE*4) = A_eu(i+NNODE*2,j+NNODE*4) + - 1 Phi_x(i)*N(j)*coef_Le(2,3)*w(kint)*determinant + 1 Phi_x(i)*N(j)*coef_Le(2,3)*w(kint)*determinant A_eu(i+NNODE*2,j+NNODE*5) = A_eu(i+NNODE*2,j+NNODE*5) + - 1 Phi_y(i)*N(j)*coef_Le(1,3)*w(kint)*determinant - + 1 Phi_y(i)*N(j)*coef_Le(1,3)*w(kint)*determinant + A_wu(i,j) = A_wu(i,j) + - 1 Phi_x(i)*N(j)*coef_Lw(2,3)*w(kint)*determinant + 1 Phi_x(i)*N(j)*coef_Lw(2,3)*w(kint)*determinant A_wu(i,j+NNODE*3) = A_wu(i,j+NNODE*3) + - 1 Phi_y(i)*N(j)*coef_Lw(1,3)*w(kint)*determinant + 1 Phi_y(i)*N(j)*coef_Lw(1,3)*w(kint)*determinant A_wu(i,j+NNODE*4) = A_wu(i,j+NNODE*4) + - 1 Phi_z(i)*N(j)*coef_Lw(1,2)*w(kint)*determinant - + 1 Phi_z(i)*N(j)*coef_Lw(1,2)*w(kint)*determinant + A_wu(i+NNODE,j+NNODE) = A_wu(i+NNODE,j+NNODE) + - 1 Phi_y(i)*N(j)*coef_Lw(1,3)*w(kint)*determinant + 1 Phi_y(i)*N(j)*coef_Lw(1,3)*w(kint)*determinant A_wu(i+NNODE,j+NNODE*3) = A_wu(i+NNODE,j+NNODE*3) + - 1 Phi_x(i)*N(j)*coef_Lw(2,3)*w(kint)*determinant + 1 Phi_x(i)*N(j)*coef_Lw(2,3)*w(kint)*determinant A_wu(i+NNODE,j+NNODE*5) = A_wu(i+NNODE,j+NNODE*5) + - 1 Phi_z(i)*N(j)*coef_Lw(1,2)*w(kint)*determinant - + 1 Phi_z(i)*N(j)*coef_Lw(1,2)*w(kint)*determinant + A_wu(i+NNODE*2,j+NNODE*2) = A_wu(i+NNODE*2,j+NNODE*2) + - 1 Phi_z(i)*N(j)*coef_Lw(1,2)*w(kint)*determinant + 1 Phi_z(i)*N(j)*coef_Lw(1,2)*w(kint)*determinant A_wu(i+NNODE*2,j+NNODE*4) = A_wu(i+NNODE*2,j+NNODE*4) + - 1 Phi_x(i)*N(j)*coef_Lw(2,3)*w(kint)*determinant + 1 Phi_x(i)*N(j)*coef_Lw(2,3)*w(kint)*determinant A_wu(i+NNODE*2,j+NNODE*5) = A_wu(i+NNODE*2,j+NNODE*5) + - 1 Phi_y(i)*N(j)*coef_Lw(1,3)*w(kint)*determinant - + 1 Phi_y(i)*N(j)*coef_Lw(1,3)*w(kint)*determinant + A_pu(i,j) = A_pu(i,j) + - 1 Phi_x(i)*N(j)*coef_Lp(2,3)*w(kint)*determinant + 1 Phi_x(i)*N(j)*coef_Lp(2,3)*w(kint)*determinant A_pu(i,j+NNODE*3) = A_pu(i,j+NNODE*3) + - 1 Phi_y(i)*N(j)*coef_Lp(1,3)*w(kint)*determinant + 1 Phi_y(i)*N(j)*coef_Lp(1,3)*w(kint)*determinant A_pu(i,j+NNODE*4) = A_pu(i,j+NNODE*4) + - 1 Phi_z(i)*N(j)*coef_Lp(1,2)*w(kint)*determinant - + 1 Phi_z(i)*N(j)*coef_Lp(1,2)*w(kint)*determinant + A_pu(i+NNODE,j+NNODE) = A_pu(i+NNODE,j+NNODE) + - 1 Phi_y(i)*N(j)*coef_Lp(1,3)*w(kint)*determinant + 1 Phi_y(i)*N(j)*coef_Lp(1,3)*w(kint)*determinant A_pu(i+NNODE,j+NNODE*3) = A_pu(i+NNODE,j+NNODE*3) + - 1 Phi_x(i)*N(j)*coef_Lp(2,3)*w(kint)*determinant + 1 Phi_x(i)*N(j)*coef_Lp(2,3)*w(kint)*determinant A_pu(i+NNODE,j+NNODE*5) = A_pu(i+NNODE,j+NNODE*5) + - 1 Phi_z(i)*N(j)*coef_Lp(1,2)*w(kint)*determinant - + 1 Phi_z(i)*N(j)*coef_Lp(1,2)*w(kint)*determinant + A_pu(i+NNODE*2,j+NNODE*2) = A_pu(i+NNODE*2,j+NNODE*2) + - 1 Phi_z(i)*N(j)*coef_Lp(1,2)*w(kint)*determinant + 1 Phi_z(i)*N(j)*coef_Lp(1,2)*w(kint)*determinant A_pu(i+NNODE*2,j+NNODE*4) = A_pu(i+NNODE*2,j+NNODE*4) + - 1 Phi_x(i)*N(j)*coef_Lp(2,3)*w(kint)*determinant + 1 Phi_x(i)*N(j)*coef_Lp(2,3)*w(kint)*determinant A_pu(i+NNODE*2,j+NNODE*5) = A_pu(i+NNODE*2,j+NNODE*5) + - 1 Phi_y(i)*N(j)*coef_Lp(1,3)*w(kint)*determinant - - end do - end do + 1 Phi_y(i)*N(j)*coef_Lp(1,3)*w(kint)*determinant + + end do + end do + + + Kyx(1:NNODE,1:NNODE) = transpose(Kxy(1:NNODE,1:NNODE)) + Kzx(1:NNODE,1:NNODE) = transpose(Kxz(1:NNODE,1:NNODE)) + Kzy(1:NNODE,1:NNODE) = transpose(Kyz(1:NNODE,1:NNODE)) + + K_RD(1:NNODE,1:NNODE) = K_RD(1:NNODE,1:NNODE) + + 1 Kxx(1:NNODE,1:NNODE)*w(kint)*determinant + K_RD(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = + 1 K_RD(NNODE+1:2*NNODE,NNODE+1:2*NNODE) + + 2 Kyy(1:NNODE,1:NNODE)*w(kint)*determinant + K_RD(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) = + 1 K_RD(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) + + 2 Kzz(1:NNODE,1:NNODE)*w(kint)*determinant + + K_RD(1:NNODE,NNODE+1:2*NNODE) = + 1 K_RD(1:NNODE,NNODE+1:2*NNODE) + + 2 Kxy(1:NNODE,1:NNODE)*w(kint)*determinant + K_RD(1:NNODE,2*NNODE+1:3*NNODE) = + 1 K_RD(1:NNODE,2*NNODE+1:3*NNODE) + + 2 Kxz(1:NNODE,1:NNODE)*w(kint)*determinant + K_RD(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) = + 1 K_RD(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) + + 2 Kyz(1:NNODE,1:NNODE)*w(kint)*determinant + + K_RD(NNODE+1:2*NNODE,1:NNODE) = + 1 K_RD(NNODE+1:2*NNODE,1:NNODE) + + 2 Kyx(1:NNODE,1:NNODE)*w(kint)*determinant + K_RD(2*NNODE+1:3*NNODE,1:NNODE) = + 1 K_RD(2*NNODE+1:3*NNODE,1:NNODE) + + 2 Kzx(1:NNODE,1:NNODE)*w(kint)*determinant + K_RD(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) = + 1 K_RD(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) + + 2 Kzy(1:NNODE,1:NNODE)*w(kint)*determinant + + + end do - Kyx(1:NNODE,1:NNODE) = transpose(Kxy(1:NNODE,1:NNODE)) - Kzx(1:NNODE,1:NNODE) = transpose(Kxz(1:NNODE,1:NNODE)) - Kzy(1:NNODE,1:NNODE) = transpose(Kyz(1:NNODE,1:NNODE)) - - K_RD(1:NNODE,1:NNODE) = K_RD(1:NNODE,1:NNODE) + - 1 Kxx(1:NNODE,1:NNODE)*w(kint)*determinant - K_RD(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = - 1 K_RD(NNODE+1:2*NNODE,NNODE+1:2*NNODE) + - 2 Kyy(1:NNODE,1:NNODE)*w(kint)*determinant - K_RD(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) = - 1 K_RD(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) + - 2 Kzz(1:NNODE,1:NNODE)*w(kint)*determinant - - K_RD(1:NNODE,NNODE+1:2*NNODE) = - 1 K_RD(1:NNODE,NNODE+1:2*NNODE) + - 2 Kxy(1:NNODE,1:NNODE)*w(kint)*determinant - K_RD(1:NNODE,2*NNODE+1:3*NNODE) = - 1 K_RD(1:NNODE,2*NNODE+1:3*NNODE) + - 2 Kxz(1:NNODE,1:NNODE)*w(kint)*determinant - K_RD(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) = - 1 K_RD(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) + - 2 Kyz(1:NNODE,1:NNODE)*w(kint)*determinant - - K_RD(NNODE+1:2*NNODE,1:NNODE) = - 1 K_RD(NNODE+1:2*NNODE,1:NNODE) + - 2 Kyx(1:NNODE,1:NNODE)*w(kint)*determinant - K_RD(2*NNODE+1:3*NNODE,1:NNODE) = - 1 K_RD(2*NNODE+1:3*NNODE,1:NNODE) + - 2 Kzx(1:NNODE,1:NNODE)*w(kint)*determinant - K_RD(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) = - 1 K_RD(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) + - 2 Kzy(1:NNODE,1:NNODE)*w(kint)*determinant - + + M_RD(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = M_RD(1:NNODE,1:NNODE) + M_RD(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) + 1 = M_RD(1:NNODE,1:NNODE) - end do - - M_RD(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = M_RD(1:NNODE,1:NNODE) - M_RD(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) - 1 = M_RD(1:NNODE,1:NNODE) - - M_a(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = M_a(1:NNODE,1:NNODE) - M_a(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) - 1 = M_a(1:NNODE,1:NNODE) - - M_b(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = M_b(1:NNODE,1:NNODE) - M_b(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) - 1 = M_b(1:NNODE,1:NNODE) - - M_c(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = M_c(1:NNODE,1:NNODE) - M_c(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) - 1 = M_c(1:NNODE,1:NNODE) - - M_d(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = M_d(1:NNODE,1:NNODE) - M_d(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) - 1 = M_d(1:NNODE,1:NNODE) + C_RD(1:3*NNODE,1:3*NNODE) = Damp_alpha*M_RD(1:3*NNODE,1:3*NNODE) + 1 + Damp_beta*K_RD(1:3*NNODE,1:3*NNODE) + + M_a(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = M_a(1:NNODE,1:NNODE) + M_a(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) + 1 = M_a(1:NNODE,1:NNODE) + + M_b(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = M_b(1:NNODE,1:NNODE) + M_b(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) + 1 = M_b(1:NNODE,1:NNODE) + M_c(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = M_c(1:NNODE,1:NNODE) + M_c(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) + 1 = M_c(1:NNODE,1:NNODE) - N_a(1:NNODE,1:NNODE) = - 1 M_a(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_a(1:NNODE,NNODE+1:2*NNODE) = + M_d(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = M_d(1:NNODE,1:NNODE) + M_d(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) + 1 = M_d(1:NNODE,1:NNODE) + + + N_a(1:NNODE,1:NNODE) = + 1 M_a(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) + N_a(1:NNODE,NNODE+1:2*NNODE) = 1 -M_a(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_a(1:NNODE,2*NNODE+1:3*NNODE) = + N_a(1:NNODE,2*NNODE+1:3*NNODE) = 1 -M_a(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_a(NNODE+1:2*NNODE,1:NNODE) = + N_a(NNODE+1:2*NNODE,1:NNODE) = 1 -M_a(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_a(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = - 1 M_a(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_a(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) = + N_a(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = + 1 M_a(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) + N_a(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) = 1 -M_a(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_a(2*NNODE+1:3*NNODE,1:NNODE) = + N_a(2*NNODE+1:3*NNODE,1:NNODE) = 1 -M_a(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_a(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) = + N_a(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) = 1 -M_a(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_a(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) = + N_a(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) = 1 M_a(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_a(3*NNODE+1:4*NNODE,3*NNODE+1:4*NNODE) = + N_a(3*NNODE+1:4*NNODE,3*NNODE+1:4*NNODE) = 1 M_a(1:NNODE,1:NNODE)/rho/mu - N_a(4*NNODE+1:5*NNODE,4*NNODE+1:5*NNODE) = + N_a(4*NNODE+1:5*NNODE,4*NNODE+1:5*NNODE) = 1 M_a(1:NNODE,1:NNODE)/rho/mu - N_a(5*NNODE+1:6*NNODE,5*NNODE+1:6*NNODE) = + N_a(5*NNODE+1:6*NNODE,5*NNODE+1:6*NNODE) = 1 M_a(1:NNODE,1:NNODE)/rho/mu - - N_b(1:NNODE,1:NNODE) = + N_b(1:NNODE,1:NNODE) = 1 M_b(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_b(1:NNODE,NNODE+1:2*NNODE) = + N_b(1:NNODE,NNODE+1:2*NNODE) = 1 -M_b(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_b(1:NNODE,2*NNODE+1:3*NNODE) = + N_b(1:NNODE,2*NNODE+1:3*NNODE) = 1 -M_b(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_b(NNODE+1:2*NNODE,1:NNODE) = + N_b(NNODE+1:2*NNODE,1:NNODE) = 1 -M_b(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_b(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = + N_b(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = 1 M_b(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_b(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) = + N_b(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) = 1 -M_b(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_b(2*NNODE+1:3*NNODE,1:NNODE) = + N_b(2*NNODE+1:3*NNODE,1:NNODE) = 1 -M_b(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_b(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) = + N_b(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) = 1 -M_b(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_b(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) = + N_b(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) = 1 M_b(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_b(3*NNODE+1:4*NNODE,3*NNODE+1:4*NNODE) = + N_b(3*NNODE+1:4*NNODE,3*NNODE+1:4*NNODE) = 1 M_b(1:NNODE,1:NNODE)/rho/mu - N_b(4*NNODE+1:5*NNODE,4*NNODE+1:5*NNODE) = + N_b(4*NNODE+1:5*NNODE,4*NNODE+1:5*NNODE) = 1 M_b(1:NNODE,1:NNODE)/rho/mu - N_b(5*NNODE+1:6*NNODE,5*NNODE+1:6*NNODE) = + N_b(5*NNODE+1:6*NNODE,5*NNODE+1:6*NNODE) = 1 M_b(1:NNODE,1:NNODE)/rho/mu - N_c(1:NNODE,1:NNODE) = + N_c(1:NNODE,1:NNODE) = 1 M_c(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_c(1:NNODE,NNODE+1:2*NNODE) = + N_c(1:NNODE,NNODE+1:2*NNODE) = 1 -M_c(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_c(1:NNODE,2*NNODE+1:3*NNODE) = + N_c(1:NNODE,2*NNODE+1:3*NNODE) = 1 -M_c(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_c(NNODE+1:2*NNODE,1:NNODE) = + N_c(NNODE+1:2*NNODE,1:NNODE) = 1 -M_c(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_c(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = + N_c(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = 1 M_c(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_c(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) = + N_c(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) = 1 -M_c(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_c(2*NNODE+1:3*NNODE,1:NNODE) = + N_c(2*NNODE+1:3*NNODE,1:NNODE) = 1 -M_c(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_c(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) = + N_c(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) = 1 -M_c(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_c(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) = + N_c(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) = 1 M_c(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_c(3*NNODE+1:4*NNODE,3*NNODE+1:4*NNODE) = + N_c(3*NNODE+1:4*NNODE,3*NNODE+1:4*NNODE) = 1 M_c(1:NNODE,1:NNODE)/rho/mu - N_c(4*NNODE+1:5*NNODE,4*NNODE+1:5*NNODE) = + N_c(4*NNODE+1:5*NNODE,4*NNODE+1:5*NNODE) = 1 M_c(1:NNODE,1:NNODE)/rho/mu - N_c(5*NNODE+1:6*NNODE,5*NNODE+1:6*NNODE) = + N_c(5*NNODE+1:6*NNODE,5*NNODE+1:6*NNODE) = 1 M_c(1:NNODE,1:NNODE)/rho/mu - N_d(1:NNODE,1:NNODE) = + N_d(1:NNODE,1:NNODE) = 1 M_d(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_d(1:NNODE,NNODE+1:2*NNODE) = + N_d(1:NNODE,NNODE+1:2*NNODE) = 1 -M_d(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_d(1:NNODE,2*NNODE+1:3*NNODE) = + N_d(1:NNODE,2*NNODE+1:3*NNODE) = 1 -M_d(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_d(NNODE+1:2*NNODE,1:NNODE) = + N_d(NNODE+1:2*NNODE,1:NNODE) = 1 -M_d(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_d(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = + N_d(NNODE+1:2*NNODE,NNODE+1:2*NNODE) = 1 M_d(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_d(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) = + N_d(NNODE+1:2*NNODE,2*NNODE+1:3*NNODE) = 1 -M_d(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_d(2*NNODE+1:3*NNODE,1:NNODE) = + N_d(2*NNODE+1:3*NNODE,1:NNODE) = 1 -M_d(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_d(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) = + N_d(2*NNODE+1:3*NNODE,NNODE+1:2*NNODE) = 1 -M_d(1:NNODE,1:NNODE)/rho*(lambda)/mu/2.d0/(3.d0*lambda+2.d0*mu) - N_d(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) = + N_d(2*NNODE+1:3*NNODE,2*NNODE+1:3*NNODE) = 1 M_d(1:NNODE,1:NNODE)/rho*(lambda+mu)/mu/(3.d0*lambda+2.d0*mu) - N_d(3*NNODE+1:4*NNODE,3*NNODE+1:4*NNODE) = + N_d(3*NNODE+1:4*NNODE,3*NNODE+1:4*NNODE) = 1 M_d(1:NNODE,1:NNODE)/rho/mu - N_d(4*NNODE+1:5*NNODE,4*NNODE+1:5*NNODE) = + N_d(4*NNODE+1:5*NNODE,4*NNODE+1:5*NNODE) = 1 M_d(1:NNODE,1:NNODE)/rho/mu - N_d(5*NNODE+1:6*NNODE,5*NNODE+1:6*NNODE) = + N_d(5*NNODE+1:6*NNODE,5*NNODE+1:6*NNODE) = 1 M_d(1:NNODE,1:NNODE)/rho/mu - - IF (EleType_pos .EQ. 1) THEN - M_PML(1:NNODE*3,1:NNODE*3) = M_RD(1:NNODE*3,1:NNODE*3) + + IF (EleType_pos .EQ. 1 .OR. LFLAGS(1).EQ.1 .OR. + & LFLAGS(1).EQ.2) THEN + + M_PML(1:NNODE*3,1:NNODE*3) = M_RD(1:NNODE*3,1:NNODE*3) + + K_PML(1:NNODE*3,1:NNODE*3) = K_RD(1:NNODE*3,1:NNODE*3) + write(*,*) 'this 2 if statement is working' + + + + else + IF (EleType_pos .EQ. 1) THEN + + M_PML(1:NNODE*3,1:NNODE*3) = M_RD(1:NNODE*3,1:NNODE*3) + 1 M_a(1:NNODE*3,1:NNODE*3) - M_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = + M_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = 1 -N_a(1:NNODE*6,1:NNODE*6) - C_PML(1:NNODE*3,1:NNODE*3) = M_b(1:NNODE*3,1:NNODE*3) - C_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = A_eu(1:NNODE*3,1:NNODE*6) - C_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = - 1 transpose(A_eu(1:NNODE*3,1:NNODE*6)) - C_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = + C_PML(1:NNODE*3,1:NNODE*3) = C_RD(1:NNODE*3,1:NNODE*3) + + 1 M_b(1:NNODE*3,1:NNODE*3) + C_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = A_eu(1:NNODE*3,1:NNODE*6) + C_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = + 1 transpose(A_eu(1:NNODE*3,1:NNODE*6)) + C_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = 1 -N_b(1:NNODE*6,1:NNODE*6) - K_PML(1:NNODE*3,1:NNODE*3) = K_RD(1:NNODE*3,1:NNODE*3) + + K_PML(1:NNODE*3,1:NNODE*3) = K_RD(1:NNODE*3,1:NNODE*3) + 1 M_c(1:NNODE*3,1:NNODE*3) - K_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = A_pu(1:NNODE*3,1:NNODE*6) - K_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = + K_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = A_pu(1:NNODE*3,1:NNODE*6) + K_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = 1 transpose(A_pu(1:NNODE*3,1:NNODE*6)) - K_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = + K_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = 1 -N_c(1:NNODE*6,1:NNODE*6) - G_PML(1:NNODE*3,1:NNODE*3) = M_d(1:NNODE*3,1:NNODE*3) - G_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = A_wu(1:NNODE*3,1:NNODE*6) - G_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = + G_PML(1:NNODE*3,1:NNODE*3) = M_d(1:NNODE*3,1:NNODE*3) + G_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = A_wu(1:NNODE*3,1:NNODE*6) + G_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = 1 transpose(A_wu(1:NNODE*3,1:NNODE*6)) - G_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = - 1 -N_d(1:NNODE*6,1:NNODE*6) + G_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = + 1 -N_d(1:NNODE*6,1:NNODE*6) + ! write(*,*) 'this 1 if statement is working' - else - M_PML(1:NNODE*3,1:NNODE*3) = M_a(1:NNODE*3,1:NNODE*3) - M_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = + else + ! write(*,*) 'this if statement is working' + M_PML(1:NNODE*3,1:NNODE*3) = + 1 M_a(1:NNODE*3,1:NNODE*3) + M_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = + 1 A_eu(1:NNODE*3,1:NNODE*6)*Damp_beta + M_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = 1 -N_a(1:NNODE*6,1:NNODE*6) - C_PML(1:NNODE*3,1:NNODE*3) = M_b(1:NNODE*3,1:NNODE*3) - C_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = A_eu(1:NNODE*3,1:NNODE*6) - C_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = + C_PML(1:NNODE*3,1:NNODE*3) = + 1 M_b(1:NNODE*3,1:NNODE*3) + + 2 M_a(1:NNODE*3,1:NNODE*3)*Damp_alpha + + C_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = + 1 A_pu(1:NNODE*3,1:NNODE*6)*Damp_beta + + 2 A_eu(1:NNODE*3,1:NNODE*6) + C_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = 1 transpose(A_eu(1:NNODE*3,1:NNODE*6)) - C_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = + C_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = 1 -N_b(1:NNODE*6,1:NNODE*6) - K_PML(1:NNODE*3,1:NNODE*3) = M_c(1:NNODE*3,1:NNODE*3) - K_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = A_pu(1:NNODE*3,1:NNODE*6) - K_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = - 1 transpose(A_pu(1:NNODE*3,1:NNODE*6)) - K_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = + K_PML(1:NNODE*3,1:NNODE*3) = + 1 M_c(1:NNODE*3,1:NNODE*3) + M_b(1:NNODE*3,1:NNODE*3)*Damp_alpha + K_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = + 1 A_pu(1:NNODE*3,1:NNODE*6)+A_wu(1:NNODE*3,1:NNODE*6)*Damp_beta + K_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = + 1 transpose(A_pu(1:NNODE*3,1:NNODE*6)) + K_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = 1 -N_c(1:NNODE*6,1:NNODE*6) - G_PML(1:NNODE*3,1:NNODE*3) = M_d(1:NNODE*3,1:NNODE*3) - G_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = A_wu(1:NNODE*3,1:NNODE*6) - G_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = - 1 transpose(A_wu(1:NNODE*3,1:NNODE*6)) + G_PML(1:NNODE*3,1:NNODE*3) = + 1 M_d(1:NNODE*3,1:NNODE*3) + M_c(1:NNODE*3,1:NNODE*3)*Damp_alpha + G_PML(1:NNODE*3,NNODE*3+1:NNODE*9) = A_wu(1:NNODE*3,1:NNODE*6) + G_PML(NNODE*3+1:NNODE*9,1:NNODE*3) = + 1 transpose(A_wu(1:NNODE*3,1:NNODE*6)) G_PML(NNODE*3+1:NNODE*9,NNODE*3+1:NNODE*9) = 1 -N_d(1:NNODE*6,1:NNODE*6) + + H_PML(1:NNODE*3,1:NNODE*3) = + 1 M_d(1:NNODE*3,1:NNODE*3)*Damp_alpha + + + endif + + + endif - endif do i = 1,8 do j = 1,8 - MMTRX((i-1)*9+1:i*9,(j-1)*9+1:j*9) = + MMATRX((i-1)*9+1:i*9,(j-1)*9+1:j*9) = 1 M_PML(i:NDOFEL-8+i:8,j:NDOFEL-8+j:8) - CMTRX((i-1)*9+1:i*9,(j-1)*9+1:j*9) = + CMATRX((i-1)*9+1:i*9,(j-1)*9+1:j*9) = 1 C_PML(i:NDOFEL-8+i:8,j:NDOFEL-8+j:8) - KMTRX((i-1)*9+1:i*9,(j-1)*9+1:j*9) = + KMATRX((i-1)*9+1:i*9,(j-1)*9+1:j*9) = 1 K_PML(i:NDOFEL-8+i:8,j:NDOFEL-8+j:8) - GMTRX((i-1)*9+1:i*9,(j-1)*9+1:j*9) = + GMATRX((i-1)*9+1:i*9,(j-1)*9+1:j*9) = 1 G_PML(i:NDOFEL-8+i:8,j:NDOFEL-8+j:8) + HMATRX((i-1)*9+1:i*9,(j-1)*9+1:j*9) = + 1 H_PML(i:NDOFEL-8+i:8,j:NDOFEL-8+j:8) end do end do - ! ! set MMTRX equal to M_PML - ! MMTRX(1:NNODE*9,1:NNODE*9) = M_PML(1:NNODE*9,1:NNODE*9) - ! CMTRX(1:NNODE*9,1:NNODE*9) = C_PML(1:NNODE*9,1:NNODE*9) - ! KMTRX(1:NNODE*9,1:NNODE*9) = K_PML(1:NNODE*9,1:NNODE*9) - ! GMTRX(1:NNODE*9,1:NNODE*9) = G_PML(1:NNODE*9,1:NNODE*9) - return END SUBROUTINE PML_3D + + + subroutine abq_UEL_3D_integrationpoints(n_points, n_nodes, xi, w) @@ -1053,663 +1031,313 @@ subroutine abq_UEL_invert3d(A,A_inverse,determinant) end subroutine abq_UEL_invert3d - subroutine abq_facenodes_3D(nelnodes,face,list,nfacenodes) - - implicit none - - integer, intent (in) :: nelnodes - integer, intent (in) :: face - integer, intent (out) :: list(*) - integer, intent (out) :: nfacenodes - - ! - ! Subroutine to return list of nodes on an element face for standard 3D solid elements - ! - - if (nelnodes == 4) then - nfacenodes = 3 - if (face == 1) list(1:3) = [1,2,3] - if (face == 2) list(1:3) = [1,4,2] - if (face == 3) list(1:3) = [2,4,3] - if (face == 4) list(1:3) = [3,4,1] - else if (nelnodes ==6) then - nfacenodes = 3 - if (face==1) list(1:3) = [1,2,3] - if (face==2) list(1:3) = [6,5,4] - if (face==3) list(1:4) = [1,2,5,4] - if (face==4) list(1:4) = [2,3,6,5] - if (face==5) list(1:4) = [4,6,3,1] - if (face>2) nfacenodes = 4 - else if (nelnodes == 10) then - nfacenodes = 6 - if (face == 1) list(1:6) = [1,2,3,5,6,7] - if (face == 2) list(1:6) = [1,4,2,8,9,5] - if (face == 3) list(1:6) = [2,4,3,9,10,6] - if (face == 4) list(1:6) = [3,4,1,10,8,7] - else if (nelnodes == 8) then - nfacenodes = 4 - if (face==1) list(1:4) = [1,2,3,4] - if (face==2) list(1:4) = [5,8,7,6] - if (face==3) list(1:4) = [1,5,6,2] - if (face==4) list(1:4) = [2,6,7,3] - if (face==5) list(1:4) = [3,7,8,4] - if (face==6) list(1:4) = [4,8,5,1] - else if (nelnodes ==15) then - nfacenodes = 6 - if (face==1) list(1:6) = [1,2,3,7,8,9] - if (face==2) list(1:6) = [6,5,4,11,10,12] - if (face==3) list(1:8) = [1,2,5,4,7,14,10,13] - if (face==4) list(1:8) = [2,3,6,5,8,15,11,14] - if (face==5) list(1:8) = [4,6,3,1,12,15,9,13] - if (face>2) nfacenodes = 8 - else if (nelnodes == 20) then - nfacenodes = 8 - if (face == 1) list(1:8) = [1,2,3,4,9,10,11,12] - if (face == 2) list(1:8) = [5,8,7,6,16,15,14,13] - if (face == 3) list(1:8) = [1,5,6,2,17,13,18,9] - if (face == 4) list(1:8) = [2,6,7,3,18,14,19,10] - if (face == 5) list(1:8) = [3,7,8,4,19,15,6,11] - if (face == 6) list(1:8) = [4,8,5,1,20,16,17,12] - endif - - end subroutine abq_facenodes_3D - - subroutine abq_UEL_2D_integrationpoints(n_points, n_nodes, xi, w) - - implicit none - integer, intent(in) :: n_points - integer, intent(in) :: n_nodes - - double precision, intent(out) :: xi(2,*) - double precision, intent(out) :: w(*) - - integer :: i,j,k,n - - double precision :: cn,w1,w2,w11,w12,w22 - - ! Defines integration points and weights for 2D continuum elements - - if ( n_points==1 ) then - if ( n_nodes==4 .or. n_nodes==9 ) then ! --- 4 or 9 noded quad - xi(1, 1) = 0.D0 - xi(2, 1) = 0.D0 - w(1) = 4.D0 - else if ( n_nodes==3 .or. n_nodes==6 ) then ! --- 3 or 6 noded triangle - xi(1, 1) = 1.D0/3.D0 - xi(2, 1) = 1.D0/3.D0 - w(1) = 1.D0/2.D0 - end if - else if ( n_points==3 ) then - xi(1, 1) = 0.5D0 - xi(2, 1) = 0.5D0 - w(1) = 1.D0/6.D0 - xi(1, 2) = 0.D0 - xi(2, 2) = 0.5D0 - w(2) = w(1) - xi(1, 3) = 0.5D0 - xi(2, 3) = 0.D0 - w(3) = w(1) - else if ( n_points==4 ) then - if ( n_nodes==4 .or. n_nodes==8 .or. n_nodes==9 ) then - ! 2X2 GAUSS INTEGRATION POINTS FOR QUADRILATERAL - ! 43 - ! 12 - cn = 0.5773502691896260D0 - xi(1, 1) = -cn - xi(1, 2) = cn - xi(1, 3) = cn - xi(1, 4) = -cn - xi(2, 1) = -cn - xi(2, 2) = -cn - xi(2, 3) = cn - xi(2, 4) = cn - w(1) = 1.D0 - w(2) = 1.D0 - w(3) = 1.D0 - w(4) = 1.D0 - else if ( n_nodes==3 .or. n_nodes==6 ) then - ! xi integration points for triangle - xi(1, 1) = 1.D0/3.D0 - xi(2, 1) = xi(1, 1) - w(1) = -27.D0/96.D0 - xi(1, 2) = 0.6D0 - xi(2, 2) = 0.2D0 - w(2) = 25.D0/96.D0 - xi(1, 3) = 0.2D0 - xi(2, 3) = 0.6D0 - w(3) = w(2) - xi(1, 4) = 0.2D0 - xi(2, 4) = 0.2D0 - w(4) = w(2) - end if - - else if ( n_points==7 ) then - ! Quintic integration for triangle - xi(1,1) = 1.d0/3.d0 - xi(2,1) = xi(1,1) - w(1) = 0.1125d0 - xi(1,2) = 0.0597158717d0 - xi(2,2) = 0.4701420641d0 - w(2) = 0.0661970763d0 - xi(1,3) = xi(2,2) - xi(2,3) = xi(1,2) - w(3) = w(2) - xi(1,4) = xi(2,2) - xi(2,4) = xi(2,2) - w(4) = w(2) - xi(1,5) = 0.7974269853d0 - xi(2,5) = 0.1012865073d0 - w(5) = 0.0629695902d0 - xi(1,6) = xi(2,5) - xi(2,6) = xi(1,5) - w(6) = w(5) - xi(1,7) = xi(2,5) - xi(2,7) = xi(2,5) - w(7) = w(5) - else if ( n_points==9 ) then - ! 3X3 GAUSS INTEGRATION POINTS - ! 789 - ! 456 - ! 123 - cn = 0.7745966692414830D0 - xi(1, 1) = -cn - xi(1, 2) = 0.D0 - xi(1, 3) = cn - xi(1, 4) = -cn - xi(1, 5) = 0.D0 - xi(1, 6) = cn - xi(1, 7) = -cn - xi(1, 8) = 0.D0 - xi(1, 9) = cn - xi(2, 1) = -cn - xi(2, 2) = -cn - xi(2, 3) = -cn - xi(2, 4) = 0.D0 - xi(2, 5) = 0.D0 - xi(2, 6) = 0.D0 - xi(2, 7) = cn - xi(2, 8) = cn - xi(2, 9) = cn - w1 = 0.5555555555555560D0 - w2 = 0.8888888888888890D0 - w11 = w1*w1 - w12 = w1*w2 - w22 = w2*w2 - w(1) = w11 - w(2) = w12 - w(3) = w11 - w(4) = w12 - w(5) = w22 - w(6) = w12 - w(7) = w11 - w(8) = w12 - w(9) = w11 - end if - - return - - end subroutine abq_UEL_2D_integrationpoints +! subroutine PML_alpha_beta_function(PROPS,x1,x2,x3,PML_alpha_beta) +! implicit none - subroutine abq_UEL_2D_shapefunctions(xi,n_nodes,f,df) - - implicit none - integer, intent(in) :: n_nodes - - double precision, intent(in) :: xi(2) - double precision, intent(out) :: f(*) - double precision, intent(out) :: df(9,2) - double precision g1, g2, g3, dg1, dg2, dg3 - double precision h1, h2, h3, dh1, dh2, dh3 - double precision z,dzdp, dzdq - - if ( n_nodes==3 ) then ! SHAPE FUNCTIONS FOR 3 NODED TRIANGLE - f(1) = xi(1) - f(2) = xi(2) - f(3) = 1.D0 - xi(1) - xi(2) - df(1, 1) = 1.D0 - df(1, 2) = 0.D0 - df(2, 1) = 0.D0 - df(2, 2) = 1.D0 - df(3, 1) = -1.D0 - df(3, 2) = -1.D0 - else if ( n_nodes==4 ) then - ! SHAPE FUNCTIONS FOR 4 NODED QUADRILATERAL - ! 43 - ! 12 - g1 = 0.5D0*(1.D0 - xi(1)) - g2 = 0.5D0*(1.D0 + xi(1)) - h1 = 0.5D0*(1.D0 - xi(2)) - h2 = 0.5D0*(1.D0 + xi(2)) - f(1) = g1*h1 - f(2) = g2*h1 - f(3) = g2*h2 - f(4) = g1*h2 - dg1 = -0.5D0 - dg2 = 0.5D0 - dh1 = -0.5D0 - dh2 = 0.5D0 - df(1, 1) = dg1*h1 - df(2, 1) = dg2*h1 - df(3, 1) = dg2*h2 - df(4, 1) = dg1*h2 - df(1, 2) = g1*dh1 - df(2, 2) = g2*dh1 - df(3, 2) = g2*dh2 - df(4, 2) = g1*dh2 - - else if ( n_nodes==6 ) then - - ! SHAPE FUNCTIONS FOR 6 NODED TRIANGLE - ! 3 - - ! 6 5 - - ! 1 4 2 - - ! P = L1 - ! Q = L2 - ! Z = 1 - P - Q = L3 - - z = 1.D0 - xi(1) - xi(2) - f(1) = (2.D0*xi(1) - 1.D0)*xi(1) - f(2) = (2.D0*xi(2) - 1.D0)*xi(2) - f(3) = (2.D0*z - 1.D0)*z - f(4) = 4.D0*xi(1)*xi(2) - f(5) = 4.D0*xi(2)*z - f(6) = 4.D0*xi(1)*z - dzdp = -1.D0 - dzdq = -1.D0 - df(1, 1) = 4.D0*xi(1) - 1.D0 - df(2, 1) = 0.D0 - df(3, 1) = 4.D0*z*dzdp - dzdp - df(4, 1) = 4.D0*xi(2) - df(5, 1) = 4.D0*xi(2)*dzdp - df(6, 1) = 4.D0*z + 4.D0*xi(1)*dzdp - df(1, 2) = 0.D0 - df(2, 2) = 4.D0*xi(2) - 1.D0 - df(3, 2) = 4.D0*z*dzdq - dzdq - df(4, 2) = 4.D0*xi(1) - df(5, 2) = 4.D0*z + 4.D0*xi(2)*dzdq - df(6, 2) = 4.D0*xi(1)*dzdq - - else if ( n_nodes==8 ) then - ! SHAPE FUNCTIONS FOR 8 NODED SERENDIPITY ELEMENT - f(1) = -0.25*(1.-xi(1))*(1.-xi(2))*(1.+xi(1)+xi(2)) - f(2) = 0.25*(1.+xi(1))*(1.-xi(2))*(xi(1)-xi(2)-1.) - f(3) = 0.25*(1.+xi(1))*(1.+xi(2))*(xi(1)+xi(2)-1.) - f(4) = 0.25*(1.-xi(1))*(1.+xi(2))*(xi(2)-xi(1)-1.) - f(5) = 0.5*(1.-xi(1)*xi(1))*(1.-xi(2)) - f(6) = 0.5*(1.+xi(1))*(1.-xi(2)*xi(2)) - f(7) = 0.5*(1.-xi(1)*xi(1))*(1.+xi(2)) - f(8) = 0.5*(1.-xi(1))*(1.-xi(2)*xi(2)) - df(1,1) = 0.25*(1.-xi(2))*(2.*xi(1)+xi(2)) - df(1,2) = 0.25*(1.-xi(1))*(xi(1)+2.*xi(2)) - df(2,1) = 0.25*(1.-xi(2))*(2.*xi(1)-xi(2)) - df(2,2) = 0.25*(1.+xi(1))*(2.*xi(2)-xi(1)) - df(3,1) = 0.25*(1.+xi(2))*(2.*xi(1)+xi(2)) - df(3,2) = 0.25*(1.+xi(1))*(2.*xi(2)+xi(1)) - df(4,1) = 0.25*(1.+xi(2))*(2.*xi(1)-xi(2)) - df(4,2) = 0.25*(1.-xi(1))*(2.*xi(2)-xi(1)) - df(5,1) = -xi(1)*(1.-xi(2)) - df(5,2) = -0.5*(1.-xi(1)*xi(1)) - df(6,1) = 0.5*(1.-xi(2)*xi(2)) - df(6,2) = -(1.+xi(1))*xi(2) - df(7,1) = -xi(1)*(1.+xi(2)) - df(7,2) = 0.5*(1.-xi(1)*xi(1)) - df(8,1) = -0.5*(1.-xi(2)*xi(2)) - df(8,2) = -(1.-xi(1))*xi(2) - else if ( n_nodes==9 ) then - ! SHAPE FUNCTIONS FOR 9 NODED LAGRANGIAN ELEMENT - ! 789 - ! 456 - ! 123 - g1 = -.5D0*xi(1)*(1.D0 - xi(1)) - g2 = (1.D0 - xi(1))*(1.D0 + xi(1)) - g3 = .5D0*xi(1)*(1.D0 + xi(1)) - h1 = -.5D0*xi(2)*(1.D0 - xi(2)) - h2 = (1.D0 - xi(2))*(1.D0 + xi(2)) - h3 = .5D0*xi(2)*(1.D0 + xi(2)) - dg1 = xi(1) - 0.5d0 - dg2 = -2.d0*xi(1) - dg3 = xi(1) + 0.5d0 - dh1 = xi(2)-0.5d0 - dh2 = -2.d0*xi(2) - dh3 = xi(2) + 0.5d0 - f(1) = g1*h1 - f(2) = g2*h1 - f(3) = g3*h1 - f(4) = g1*h2 - f(5) = g2*h2 - f(6) = g3*h2 - f(7) = g1*h3 - f(8) = g2*h3 - f(9) = g3*h3 - df(1,1) = dg1*h1 - df(1,2) = g1*dh1 - df(2,1) = dg2*h1 - df(2,2) = g2*dh1 - df(3,1) = dg3*h1 - df(3,2) = g3*dh1 - df(4,1) = dg1*h2 - df(4,2) = g1*dh2 - df(5,1) = dg2*h2 - df(5,2) = g2*dh2 - df(6,1) = dg3*h2 - df(6,2) = g3*dh2 - df(7,1) = dg1*h3 - df(7,2) = g1*dh3 - df(8,1) = dg2*h3 - df(8,2) = g2*dh3 - df(9,1) = dg3*h3 - df(9,2) = g3*dh3 - end if - - end subroutine abq_UEL_2D_shapefunctions - - - subroutine PML_alpha_beta_function(PROPS,x1,x2,x3,PML_alpha_beta) - - implicit none - - double precision, intent(in) :: PROPS(*) - double precision, intent(in) :: x1, x2, x3 +! double precision, intent(in) :: PROPS(*) +! double precision, intent(in) :: x1, x2, x3 - double precision, intent(out) :: PML_alpha_beta(2,3) - - integer EleType_arg - - double precision E, xnu, rho, PML_L, afp, PML_Rcoef - double precision x1_0, x2_0, x3_0, n1, n2, n3, cp_ref, PML_b - double precision alpha_0, beta_0 - double precision RD_half_width_x, RD_half_width_y, RD_depth - - E = PROPS(1) - xnu = PROPS(2) - rho = PROPS(3) - EleType_arg = floor(PROPS(4)) - PML_L = PROPS(5) - afp = PROPS(6) - PML_Rcoef = PROPS(7) - RD_half_width_x = PROPS(8) - RD_half_width_y = PROPS(9) - RD_depth = PROPS(10) +! double precision, intent(out) :: PML_alpha_beta(2,3) + +! integer EleType_arg + +! double precision E, xnu, rho, PML_L, afp, PML_Rcoef +! double precision x1_0, x2_0, x3_0, n1, n2, n3, cp_ref, PML_b +! double precision alpha_0, beta_0 +! double precision RD_half_width_x, RD_half_width_y, RD_depth + +! E = PROPS(1) +! xnu = PROPS(2) +! rho = PROPS(3) +! EleType_arg = floor(PROPS(4)) +! PML_L = PROPS(5) +! afp = PROPS(6) +! PML_Rcoef = PROPS(7) +! RD_half_width_x = PROPS(8) +! RD_half_width_y = PROPS(9) +! RD_depth = PROPS(10) - cp_ref = SQRT(E *(1.d0-xnu)/rho/(1.d0+xnu)/(1.d0-2.d0*xnu)) +! cp_ref = SQRT(E *(1.d0-xnu)/rho/(1.d0+xnu)/(1.d0-2.d0*xnu)) - - IF(x2 < -RD_half_width_y) then - IF(x1 < -RD_half_width_x) then - IF(x3 < -RD_depth) then +! IF(x2 < -RD_half_width_y) then +! IF(x1 < -RD_half_width_x) then +! IF(x3 < -RD_depth) then - EleType_arg = 15 +! EleType_arg = 15 - else +! else - EleType_arg = 6 +! EleType_arg = 6 - endif +! endif - ELSEIF(x1 < RD_half_width_x) then - IF(x3 < -RD_depth) then +! ELSEIF(x1 < RD_half_width_x) then +! IF(x3 < -RD_depth) then - EleType_arg = 11 +! EleType_arg = 11 - else +! else - EleType_arg = 2 +! EleType_arg = 2 - endif +! endif - Else - IF(x3 < -RD_depth) then +! Else +! IF(x3 < -RD_depth) then - EleType_arg = 16 +! EleType_arg = 16 - else +! else - EleType_arg = 7 +! EleType_arg = 7 - endif - endif +! endif +! endif - ELSEIF(x2 < RD_half_width_y) then - IF(x1 < -RD_half_width_x) then - IF(x3 < -RD_depth) then +! ELSEIF(x2 < RD_half_width_y) then +! IF(x1 < -RD_half_width_x) then +! IF(x3 < -RD_depth) then - EleType_arg = 14 +! EleType_arg = 14 - else +! else - EleType_arg = 5 +! EleType_arg = 5 - endif +! endif - ELSEIF(x1 < RD_half_width_x) then - IF(x3 < -RD_depth) then +! ELSEIF(x1 < RD_half_width_x) then +! IF(x3 < -RD_depth) then - EleType_arg = 10 +! EleType_arg = 10 - else +! else - EleType_arg = 1 +! EleType_arg = 1 - endif +! endif - Else - IF(x3 < -RD_depth) then +! Else +! IF(x3 < -RD_depth) then - EleType_arg = 12 +! EleType_arg = 12 - else +! else - EleType_arg = 3 +! EleType_arg = 3 - endif - endif +! endif +! endif - Else - IF(x1 < -RD_half_width_x) then - IF(x3 < -RD_depth) then +! Else +! IF(x1 < -RD_half_width_x) then +! IF(x3 < -RD_depth) then - EleType_arg = 18 +! EleType_arg = 18 - else +! else - EleType_arg = 9 +! EleType_arg = 9 - endif +! endif - ELSEIF(x1 < RD_half_width_x) then - IF(x3 < -RD_depth) then +! ELSEIF(x1 < RD_half_width_x) then +! IF(x3 < -RD_depth) then - EleType_arg = 13 +! EleType_arg = 13 - else +! else - EleType_arg = 4 +! EleType_arg = 4 - endif +! endif - Else - IF(x3 < -RD_depth) then +! Else +! IF(x3 < -RD_depth) then - EleType_arg = 17 +! EleType_arg = 17 - else +! else - EleType_arg = 8 +! EleType_arg = 8 - endif - endif +! endif +! endif - endif +! endif +! ! write(6,*) "EleType_arg ",EleType_arg +! select case (EleType_arg) +! case(1) !Regular domain (do nothing) +! n1 = 0.d0 +! n2 = 0.d0 +! n3 = 0.d0 +! x1_0 = 0 +! x2_0 = 0 +! x3_0 = 0 + +! case(2) ! Top view, bottom surface PML +! n1 = 0.d0 +! n2 = -1.d0 +! n3 = 0.d0 +! x1_0 = 0 +! x2_0 = -1.d0* RD_half_width_y +! x3_0 = 0 + +! case(3) ! Top view, right surface PML +! n1 = 1.d0 +! n2 = 0.d0 +! n3 = 0.d0 +! x1_0 = 1.d0* RD_half_width_x +! x2_0 = 0 +! x3_0 = 0 + +! case(4) ! Top view, top surface PML +! n1 = 0.d0 +! n2 = 1.d0 +! n3 = 0.d0 +! x1_0 = 0 +! x2_0 = 1.d0* RD_half_width_y +! x3_0 = 0 + +! case(5) ! Top view, left surface PML +! n1 = -1.d0 +! n2 = 0.d0 +! n3 = 0.d0 +! x1_0 = -1.d0* RD_half_width_x +! x2_0 = 0 +! x3_0 = 0 + +! case(6) ! Top view, left-bottom column PML +! n1 = -1.d0 +! n2 = -1.d0 +! n3 = 0.d0 +! x1_0 = -1.d0* RD_half_width_x +! x2_0 = -1.d0* RD_half_width_y +! x3_0 = 0 + +! case(7) ! Top view, right-bottom column PML +! n1 = 1.d0 +! n2 = -1.d0 +! n3 = 0.d0 +! x1_0 = 1.d0* RD_half_width_x +! x2_0 = -1.d0* RD_half_width_y +! x3_0 = 0 + +! case(8) ! Top view, right-top column PML +! n1 = 1.d0 +! n2 = 1.d0 +! n3 = 0.d0 +! x1_0 = 1.d0* RD_half_width_x +! x2_0 = 1.d0* RD_half_width_y +! x3_0 = 0 + +! case(9) ! Top view, left-top column PML +! n1 = -1.d0 +! n2 = 1.d0 +! n3 = 0.d0 +! x1_0 = -1.d0* RD_half_width_x +! x2_0 = 1.d0* RD_half_width_y +! x3_0 = 0 + +! case(10) ! Top view, bottom surface, surface PML +! n1 = 0.d0 +! n2 = 0.d0 +! n3 = -1.d0 +! x1_0 = 0 +! x2_0 = 0 +! x3_0 = -1.d0* RD_depth + +! case(11) ! Top view, bottom surface, bottom column PML +! n1 = 0.d0 +! n2 = -1.d0 +! n3 = -1.d0 +! x1_0 = 0 +! x2_0 = -1.d0* RD_half_width_y +! x3_0 = -1.d0* RD_depth + +! case(12) ! Top view, bottom surface, right column PML +! n1 = 1.d0 +! n2 = 0.d0 +! n3 = -1.d0 +! x1_0 = 1.d0* RD_half_width_x +! x2_0 = 0 +! x3_0 = -1.d0* RD_depth + +! case(13) ! Top view, bottom surface, top column PML +! n1 = 0.d0 +! n2 = 1.d0 +! n3 = -1.d0 +! x1_0 = 0 +! x2_0 = 1.d0* RD_half_width_y +! x3_0 = -1.d0* RD_depth + +! case(14) ! Top view, bottom surface, left column PML +! n1 = -1.d0 +! n2 = 0.d0 +! n3 = -1.d0 +! x1_0 = -1.d0* RD_half_width_x +! x2_0 = 0 +! x3_0 = -1.d0* RD_depth + +! case(15) ! Top view, bottom surface, left-bottom corner PML +! n1 = -1.d0 +! n2 = -1.d0 +! n3 = -1.d0 +! x1_0 = -1.d0* RD_half_width_x +! x2_0 = -1.d0* RD_half_width_y +! x3_0 = -1.d0* RD_depth + +! case(16) ! Top view, bottom surface, right-bottom corner PML +! n1 = 1.d0 +! n2 = -1.d0 +! n3 = -1.d0 +! x1_0 = 1.d0* RD_half_width_x +! x2_0 = -1.d0* RD_half_width_y +! x3_0 = -1.d0* RD_depth + +! case(17) ! Top view, bottom surface, right-top corner PML +! n1 = 1.d0 +! n2 = 1.d0 +! n3 = -1.d0 +! x1_0 = 1.d0* RD_half_width_x +! x2_0 = 1.d0* RD_half_width_y +! x3_0 = -1.d0* RD_depth + +! case(18) ! Top view, bottom surface, left-top corner PML +! n1 = -1.d0 +! n2 = 1.d0 +! n3 = -1.d0 +! x1_0 = -1.d0* RD_half_width_x +! x2_0 = 1.d0* RD_half_width_y +! x3_0 = -1.d0* RD_depth + +! end select + +! PML_b = PML_L / 1.d0 !characteristic length (average element size in the PML domain) + +! alpha_0 = ((afp+1)*PML_b) / (2.d0*PML_L )*LOG10(1.d0 / PML_Rcoef) +! beta_0 = ((afp+1)*cp_ref) / (2.d0*PML_L )*LOG10(1.d0 / PML_Rcoef) - select case (EleType_arg) - case(1) !Regular domain (do nothing) - n1 = 0.d0 - n2 = 0.d0 - n3 = 0.d0 - x1_0 = 0 - x2_0 = 0 - x3_0 = 0 - - case(2) ! Top view, bottom surface PML - n1 = 0.d0 - n2 = -1.d0 - n3 = 0.d0 - x1_0 = 0 - x2_0 = -1.d0* RD_half_width_y - x3_0 = 0 - - case(3) ! Top view, right surface PML - n1 = 1.d0 - n2 = 0.d0 - n3 = 0.d0 - x1_0 = 1.d0* RD_half_width_x - x2_0 = 0 - x3_0 = 0 - - case(4) ! Top view, top surface PML - n1 = 0.d0 - n2 = 1.d0 - n3 = 0.d0 - x1_0 = 0 - x2_0 = 1.d0* RD_half_width_y - x3_0 = 0 - - case(5) ! Top view, left surface PML - n1 = -1.d0 - n2 = 0.d0 - n3 = 0.d0 - x1_0 = -1.d0* RD_half_width_x - x2_0 = 0 - x3_0 = 0 - - case(6) ! Top view, left-bottom column PML - n1 = -1.d0 - n2 = -1.d0 - n3 = 0.d0 - x1_0 = -1.d0* RD_half_width_x - x2_0 = -1.d0* RD_half_width_y - x3_0 = 0 - - case(7) ! Top view, right-bottom column PML - n1 = 1.d0 - n2 = -1.d0 - n3 = 0.d0 - x1_0 = 1.d0* RD_half_width_x - x2_0 = -1.d0* RD_half_width_y - x3_0 = 0 - - case(8) ! Top view, right-top column PML - n1 = 1.d0 - n2 = 1.d0 - n3 = 0.d0 - x1_0 = 1.d0* RD_half_width_x - x2_0 = 1.d0* RD_half_width_y - x3_0 = 0 - - case(9) ! Top view, left-top column PML - n1 = -1.d0 - n2 = 1.d0 - n3 = 0.d0 - x1_0 = -1.d0* RD_half_width_x - x2_0 = 1.d0* RD_half_width_y - x3_0 = 0 - - case(10) ! Top view, bottom surface, surface PML - n1 = 0.d0 - n2 = 0.d0 - n3 = -1.d0 - x1_0 = 0 - x2_0 = 0 - x3_0 = -1.d0* RD_depth - - case(11) ! Top view, bottom surface, bottom column PML - n1 = 0.d0 - n2 = -1.d0 - n3 = -1.d0 - x1_0 = 0 - x2_0 = -1.d0* RD_half_width_y - x3_0 = -1.d0* RD_depth - - case(12) ! Top view, bottom surface, right column PML - n1 = 1.d0 - n2 = 0.d0 - n3 = -1.d0 - x1_0 = 1.d0* RD_half_width_x - x2_0 = 0 - x3_0 = -1.d0* RD_depth - - case(13) ! Top view, bottom surface, top column PML - n1 = 0.d0 - n2 = 1.d0 - n3 = -1.d0 - x1_0 = 0 - x2_0 = 1.d0* RD_half_width_y - x3_0 = -1.d0* RD_depth - - case(14) ! Top view, bottom surface, left column PML - n1 = -1.d0 - n2 = 0.d0 - n3 = -1.d0 - x1_0 = -1.d0* RD_half_width_x - x2_0 = 0 - x3_0 = -1.d0* RD_depth - - case(15) ! Top view, bottom surface, left-bottom corner PML - n1 = -1.d0 - n2 = -1.d0 - n3 = -1.d0 - x1_0 = -1.d0* RD_half_width_x - x2_0 = -1.d0* RD_half_width_y - x3_0 = -1.d0* RD_depth - - case(16) ! Top view, bottom surface, right-bottom corner PML - n1 = 1.d0 - n2 = -1.d0 - n3 = -1.d0 - x1_0 = 1.d0* RD_half_width_x - x2_0 = -1.d0* RD_half_width_y - x3_0 = -1.d0* RD_depth - - case(17) ! Top view, bottom surface, right-top corner PML - n1 = 1.d0 - n2 = 1.d0 - n3 = -1.d0 - x1_0 = 1.d0* RD_half_width_x - x2_0 = 1.d0* RD_half_width_y - x3_0 = -1.d0* RD_depth - - case(18) ! Top view, bottom surface, left-top corner PML - n1 = -1.d0 - n2 = 1.d0 - n3 = -1.d0 - x1_0 = -1.d0* RD_half_width_x - x2_0 = 1.d0* RD_half_width_y - x3_0 = -1.d0* RD_depth - - end select - - PML_b = PML_L / 1.d0 !characteristic length (average element size in the PML domain) - - alpha_0 = ((afp+1)*PML_b) / (2.d0*PML_L )*LOG(1.d0 / PML_Rcoef) - beta_0 = ((afp+1)*cp_ref) / (2.d0*PML_L )*LOG(1.d0 / PML_Rcoef) - - PML_alpha_beta(1,1) = 1.d0 + alpha_0*((x1 -x1_0) * n1 /PML_L)**afp - PML_alpha_beta(1,2) = 1.d0 + alpha_0*((x2 -x2_0) * n2 /PML_L)**afp - PML_alpha_beta(1,3) = 1.d0 + alpha_0*((x3 -x3_0) * n3 /PML_L)**afp - - PML_alpha_beta(2,1) = beta_0*((x1 -x1_0) * n1 /PML_L)**afp - PML_alpha_beta(2,2) = beta_0*((x2 -x2_0) * n2 /PML_L)**afp - PML_alpha_beta(2,3) = beta_0*((x3 -x3_0) * n3 /PML_L)**afp - - IF (EleType_arg .EQ.1) THEN - PML_alpha_beta(1:2,1:3) = 0.d0 - end if - - end subroutine PML_alpha_beta_function +! ! alpha_0 = 5.d0 +! ! beta_0 = 800.d0 + +! write(6,*) , "alpha_____0", alpha_0 +! write(6,*) , "beta______0", beta_0 + +! PML_alpha_beta(1,1) = 1.d0 + alpha_0*((x1 -x1_0) * n1 /PML_L)**afp +! PML_alpha_beta(1,2) = 1.d0 + alpha_0*((x2 -x2_0) * n2 /PML_L)**afp +! PML_alpha_beta(1,3) = 1.d0 + alpha_0*((x3 -x3_0) * n3 /PML_L)**afp + +! PML_alpha_beta(2,1) = beta_0*((x1 -x1_0) * n1 /PML_L)**afp +! PML_alpha_beta(2,2) = beta_0*((x2 -x2_0) * n2 /PML_L)**afp +! PML_alpha_beta(2,3) = beta_0*((x3 -x3_0) * n3 /PML_L)**afp + +! IF (EleType_arg .EQ.1) THEN +! PML_alpha_beta(1:2,1:3) = 0.d0 +! end if + +! end subroutine PML_alpha_beta_function diff --git a/SRC/element/TclElementCommands.cpp b/SRC/element/TclElementCommands.cpp index abca26b27f..01c9d21b07 100644 --- a/SRC/element/TclElementCommands.cpp +++ b/SRC/element/TclElementCommands.cpp @@ -140,6 +140,7 @@ extern void *OPS_PML2D_3(void); extern void *OPS_PML2D_5(void); extern void *OPS_PML2D_12(void); extern void *OPS_PML2DVISCOUS(void); +extern void *OPS_PML3DVISCOUS(void); extern void *OPS_CorotTruss2(void); extern void *OPS_ZeroLengthImpact3D(void); extern void *OPS_HDR(void); @@ -240,7 +241,7 @@ TclModelBuilder_addJoint2D(ClientData, Tcl_Interp *, int, TCL_Char **, Domain*); extern int TclModelBuilder_addJoint3D(ClientData, Tcl_Interp *, int, TCL_Char **, Domain*, TclModelBuilder *); - + extern int TclModelBuilder_addEnhancedQuad(ClientData, Tcl_Interp *, int, TCL_Char **, Domain*, TclModelBuilder *); @@ -587,8 +588,8 @@ TclModelBuilderElementCommand(ClientData clientData, Tcl_Interp *interp, ID info; if (OPS_GetNDM() == 2) theEle = (Element *)OPS_PML2DVISCOUS(); - // else - // theEle = (Element *)OPS_PML3DVISCOUS(); + if (OPS_GetNDM() == 3) + theEle = (Element *)OPS_PML3DVISCOUS(); if (theEle != 0) theElement = theEle; else { @@ -600,8 +601,8 @@ TclModelBuilderElementCommand(ClientData clientData, Tcl_Interp *interp, ID info; if (OPS_GetNDM() == 2) theEle = (Element *)OPS_PML2D(); - else - theEle = (Element *)OPS_PML3D(); + if (OPS_GetNDM() == 3) + theEle = (Element *)OPS_PML3DVISCOUS(); if (theEle != 0) theElement = theEle; else { @@ -753,7 +754,7 @@ TclModelBuilderElementCommand(ClientData clientData, Tcl_Interp *interp, else { opserr << "TclElementCommand -- unable to create element of type : " << argv[1] << endln; return TCL_ERROR; - } + } } else if ((strcmp(argv[1],"BeamContact3dp") == 0) || (strcmp(argv[1],"BeamContact3Dp") == 0)) { @@ -939,8 +940,8 @@ TclModelBuilderElementCommand(ClientData clientData, Tcl_Interp *interp, if (theEle != 0) theElement = (Element *)theEle; else { - opserr << "TclElementCommand -- unable to create element of type : " << argv[1] << endln; - return TCL_ERROR; + opserr << "TclElementCommand -- unable to create element of type : " << argv[1] << endln; + return TCL_ERROR; } } @@ -1028,11 +1029,11 @@ TclModelBuilderElementCommand(ClientData clientData, Tcl_Interp *interp, void* theEle = OPS_ShellNLDKGTThermal(); if (theEle != 0) theElement = (Element*)theEle; - else { - opserr << "TclElementCommand -- unable to create element of type : " << argv[1] << endln; - return TCL_ERROR; - } - //end of adding thermo-mechanical shell elements by L.Jiang [SIF] + else { + opserr << "TclElementCommand -- unable to create element of type : " << argv[1] << endln; + return TCL_ERROR; + } + //end of adding thermo-mechanical shell elements by L.Jiang [SIF] } else if ((strcmp(argv[1],"shellNL") == 0) || (strcmp(argv[1],"ShellNL") == 0) || (strcmp(argv[1],"shellMITC9") == 0) || (strcmp(argv[1],"ShellMITC9") == 0)) { @@ -1424,7 +1425,7 @@ TclModelBuilderElementCommand(ClientData clientData, Tcl_Interp *interp, return TCL_ERROR; } } - + else if (strcmp(argv[1], "ASDAbsorbingBoundary2D") == 0) { void *theEle = OPS_ASDAbsorbingBoundary2D(); if (theEle != 0) { @@ -1971,7 +1972,7 @@ TclModelBuilderElementCommand(ClientData clientData, Tcl_Interp *interp, int result = TclModelBuilder_addJoint3D(clientData, interp, argc, argv, theTclDomain, theTclBuilder); return result; - } + } else if ((strcmp(argv[1],"LehighJoint2D") == 0) || (strcmp(argv[1],"LehighJoint2d") == 0)) { diff --git a/SRC/element/UP-ucsd/BBarBrickUP.cpp b/SRC/element/UP-ucsd/BBarBrickUP.cpp index 60a8bcb4cd..f8d12755a3 100644 --- a/SRC/element/UP-ucsd/BBarBrickUP.cpp +++ b/SRC/element/UP-ucsd/BBarBrickUP.cpp @@ -1584,8 +1584,45 @@ BBarBrickUP::setResponse(const char **argv, int argc, OPS_Stream &output) output.endTag(); // GaussPoint } theResponse = new ElementResponse(this, 5, Vector(48)); + } else if (strcmp(argv[0],"stress3D6") ==0) { + output.tag("GaussPoint"); + output.attr("number",1); + output.tag("NdMaterialOutput"); + output.attr("classType", materialPointers[0]->getClassTag()); + output.attr("tag", materialPointers[0]->getTag()); + + output.tag("ResponseType","sigma11"); + output.tag("ResponseType","sigma22"); + output.tag("ResponseType","sigma33"); + output.tag("ResponseType","sigma12"); + output.tag("ResponseType","sigma23"); + output.tag("ResponseType","sigma13"); + + output.endTag(); // NdMaterialOutput + output.endTag(); // GaussPoint + theResponse = new ElementResponse(this, 6, Vector(6)); + } else if (strcmp(argv[0],"strain3D6")==0) { + output.tag("GaussPoint"); + output.attr("number",1); + output.tag("NdMaterialOutput"); + output.attr("classType", materialPointers[0]->getClassTag()); + output.attr("tag", materialPointers[0]->getTag()); + + output.tag("ResponseType","eps11"); + output.tag("ResponseType","eps22"); + output.tag("ResponseType","eps33"); + output.tag("ResponseType","eps12"); + output.tag("ResponseType","eps23"); + output.tag("ResponseType","eps13"); + + output.endTag(); // NdMaterialOutput + output.endTag(); // GaussPoint + theResponse = new ElementResponse(this, 7, Vector(6)); } + + + output.endTag(); // ElementOutput return theResponse; @@ -1626,6 +1663,34 @@ BBarBrickUP::getResponse(int responseID, Information &eleInfo) return eleInfo.setVector(stresses); } + else if (responseID == 6) { + + Vector tmpStress(6); + for (int i = 0; i < 8; i++) { + // Get material stress response + const Vector &sigma = materialPointers[i]->getStress(); + tmpStress(0) = sigma(0) * 0.125; + tmpStress(1) = sigma(1) * 0.125; + tmpStress(2) = sigma(2) * 0.125; + tmpStress(3) = sigma(3) * 0.125; + tmpStress(4) = sigma(4) * 0.125; + tmpStress(5) = sigma(5) * 0.125; + } + return eleInfo.setVector(tmpStress); + } else if (responseID == 7) { + Vector tmpStrain(6); + for (int i = 0; i < 8; i++) { + // Get material strain response + const Vector &eps = materialPointers[i]->getStrain(); + tmpStrain(0) = eps(0) * 0.125; + tmpStrain(1) = eps(1) * 0.125; + tmpStrain(2) = eps(2) * 0.125; + tmpStrain(3) = eps(3) * 0.125; + tmpStrain(4) = eps(4) * 0.125; + tmpStrain(5) = eps(5) * 0.125; + } + return eleInfo.setVector(tmpStrain); + } else return -1; diff --git a/SRC/element/UP-ucsd/BrickUP.cpp b/SRC/element/UP-ucsd/BrickUP.cpp index 8617cd6555..350efbeede 100644 --- a/SRC/element/UP-ucsd/BrickUP.cpp +++ b/SRC/element/UP-ucsd/BrickUP.cpp @@ -1567,6 +1567,40 @@ BrickUP::setResponse(const char **argv, int argc, OPS_Stream &output) output.endTag(); // GaussPoint } theResponse = new ElementResponse(this, 5, Vector(48)); + } else if (strcmp(argv[0],"stress3D6")==0) { + output.tag("GaussPoint"); + output.attr("number",1); + output.tag("NdMaterialOutput"); + output.attr("classType", materialPointers[0]->getClassTag()); + output.attr("tag", materialPointers[0]->getTag()); + + output.tag("ResponseType","sigma11"); + output.tag("ResponseType","sigma22"); + output.tag("ResponseType","sigma33"); + output.tag("ResponseType","sigma12"); + output.tag("ResponseType","sigma23"); + output.tag("ResponseType","sigma13"); + + output.endTag(); // NdMaterialOutput + output.endTag(); // GaussPoint + theResponse = new ElementResponse(this, 6, Vector(6)); + } else if (strcmp(argv[0],"strain3D6")==0) { + output.tag("GaussPoint"); + output.attr("number",1); + output.tag("NdMaterialOutput"); + output.attr("classType", materialPointers[0]->getClassTag()); + output.attr("tag", materialPointers[0]->getTag()); + + output.tag("ResponseType","eps11"); + output.tag("ResponseType","eps22"); + output.tag("ResponseType","eps33"); + output.tag("ResponseType","eps12"); + output.tag("ResponseType","eps23"); + output.tag("ResponseType","eps13"); + + output.endTag(); // NdMaterialOutput + output.endTag(); // GaussPoint + theResponse = new ElementResponse(this, 7, Vector(6)); } output.endTag(); // ElementOutput @@ -1608,7 +1642,34 @@ BrickUP::getResponse(int responseID, Information &eleInfo) } return eleInfo.setVector(stresses); - } + } else if (responseID == 6) { + + Vector tmpStress(6); + for (int i = 0; i < 8; i++) { + // Get material stress response + const Vector &sigma = materialPointers[i]->getStress(); + tmpStress(0) = sigma(0) * 0.125; + tmpStress(1) = sigma(1) * 0.125; + tmpStress(2) = sigma(2) * 0.125; + tmpStress(3) = sigma(3) * 0.125; + tmpStress(4) = sigma(4) * 0.125; + tmpStress(5) = sigma(5) * 0.125; + } + return eleInfo.setVector(tmpStress); + } else if (responseID == 7) { + Vector tmpStrain(6); + for (int i = 0; i < 8; i++) { + // Get material strain response + const Vector &eps = materialPointers[i]->getStrain(); + tmpStrain(0) = eps(0) * 0.125; + tmpStrain(1) = eps(1) * 0.125; + tmpStrain(2) = eps(2) * 0.125; + tmpStrain(3) = eps(3) * 0.125; + tmpStrain(4) = eps(4) * 0.125; + tmpStrain(5) = eps(5) * 0.125; + } + return eleInfo.setVector(tmpStrain); + } else return -1; diff --git a/SRC/element/UWelements/SSPbrick.cpp b/SRC/element/UWelements/SSPbrick.cpp index 9e0e14acc8..3ef1951e46 100644 --- a/SRC/element/UWelements/SSPbrick.cpp +++ b/SRC/element/UWelements/SSPbrick.cpp @@ -983,15 +983,33 @@ SSPbrick::Print(OPS_Stream &s, int flag) Response* SSPbrick::setResponse(const char **argv, int argc, OPS_Stream &eleInfo) { - // no special recorders for this element, call the method in the material class - return theMaterial->setResponse(argv, argc, eleInfo); + if (strcmp(argv[0],"stress3D6") == 0) { + return new ElementResponse(this, 1234432100, Vector(6)); + } + if (strcmp(argv[0],"strain3D6") == 0) { + return new ElementResponse(this, 1234432101, Vector(6)); + } else { + // no special recorders for this element, call the method in the material class + return theMaterial->setResponse(argv, argc, eleInfo); + } } int SSPbrick::getResponse(int responseID, Information &eleInfo) { - // no special recorders for this element, call the method in the material class - return theMaterial->getResponse(responseID, eleInfo); + if (responseID == 1234432100) { + // get stress from the material + const Vector &mStress = theMaterial->getStress(); + return eleInfo.setVector(mStress); + } else if (responseID == 1234432101) { + // get strain from the material + + const Vector &mStrain = theMaterial->getStrain(); + return eleInfo.setVector(mStrain); + } else { + // no special recorders for this element, call the method in the material class + return theMaterial->getResponse(responseID, eleInfo); + } } int diff --git a/SRC/element/UWelements/SSPbrickUP.cpp b/SRC/element/UWelements/SSPbrickUP.cpp index 68a6bb507b..25cbd7210c 100644 --- a/SRC/element/UWelements/SSPbrickUP.cpp +++ b/SRC/element/UWelements/SSPbrickUP.cpp @@ -1132,15 +1132,35 @@ SSPbrickUP::Print(OPS_Stream &s, int flag) Response* SSPbrickUP::setResponse(const char **argv, int argc, OPS_Stream &eleInfo) { - // no special recorders for this element, call the method in the material class - return theMaterial->setResponse(argv, argc, eleInfo); + + if (strcmp(argv[0],"stress3D6") == 0) { + return new ElementResponse(this, 1, Vector(6)); + } + if (strcmp(argv[0],"strain3D6") == 0) { + return new ElementResponse(this, 2, Vector(6)); + } else { + // no special recorders for this element, call the method in the material class + return theMaterial->setResponse(argv, argc, eleInfo); + } } int SSPbrickUP::getResponse(int responseID, Information &eleInfo) { // no special recorders for this element, call the method in the material class - return theMaterial->getResponse(responseID, eleInfo); + if (responseID == 1) { + // get stress from the material + const Vector &mStress = theMaterial->getStress(); + return eleInfo.setVector(mStress); + } else if (responseID == 2) { + // get strain from the material + + const Vector &mStrain = theMaterial->getStrain(); + return eleInfo.setVector(mStrain); + } else { + // no special recorders for this element, call the method in the material class + return theMaterial->getResponse(responseID, eleInfo); + } } int diff --git a/SRC/element/UWelements/SSPquad.cpp b/SRC/element/UWelements/SSPquad.cpp index a7e4df4145..4db3296ab9 100644 --- a/SRC/element/UWelements/SSPquad.cpp +++ b/SRC/element/UWelements/SSPquad.cpp @@ -839,15 +839,34 @@ SSPquad::Print(OPS_Stream &s, int flag) Response* SSPquad::setResponse(const char **argv, int argc, OPS_Stream &eleInfo) { - // no special recorders for this element, call the method in the material class - return theMaterial->setResponse(argv, argc, eleInfo); + if (strcmp(argv[0],"stress2D3")==0) { + return new ElementResponse(this, 1234432101, Vector(3)); + } else if (strcmp(argv[0],"strain2D3")==0) { + return new ElementResponse(this, 1234432102, Vector(3)); + } else { + return theMaterial->setResponse(argv, argc, eleInfo); + } } int SSPquad::getResponse(int responseID, Information &eleInfo) { - // no special recorders for this element, call the method in the material class - return theMaterial->getResponse(responseID, eleInfo); + if (responseID == 1234432101) { + // return the stress vector + Vector stress(3); + stress = theMaterial->getStress(); + eleInfo.setVector(stress); + return 0; + } else if (responseID == 1234432102) { + // return the strain vector + Vector strain(3); + strain = theMaterial->getStrain(); + eleInfo.setVector(strain); + return 0; + } else { + // default is to call getResponse in the material + return theMaterial->getResponse(responseID, eleInfo); + } } int diff --git a/SRC/element/UWelements/SSPquadUP.cpp b/SRC/element/UWelements/SSPquadUP.cpp index 105cbabd5c..ecf6bff71a 100644 --- a/SRC/element/UWelements/SSPquadUP.cpp +++ b/SRC/element/UWelements/SSPquadUP.cpp @@ -978,15 +978,34 @@ SSPquadUP::Print(OPS_Stream &s, int flag) Response* SSPquadUP::setResponse(const char **argv, int argc, OPS_Stream &eleInfo) { - // no special recorders for this element, call the method in the material class - return theMaterial->setResponse(argv, argc, eleInfo); + if (strcmp(argv[0],"stress2D3")==0) { + return new ElementResponse(this, 1234432100, Vector(3)); + } else if (strcmp(argv[0],"strain2D3")==0) { + return new ElementResponse(this, 1234432101, Vector(3)); + } else { + return theMaterial->setResponse(argv, argc, eleInfo); + } } int SSPquadUP::getResponse(int responseID, Information &eleInfo) { - // no special recorders for this element, call the method in the material class - return theMaterial->getResponse(responseID, eleInfo); + if (responseID == 1234432100) { + // return the stress vector + Vector stress(3); + stress = theMaterial->getStress(); + eleInfo.setVector(stress); + return 0; + } else if (responseID == 1234432101) { + // return the strain vector + Vector strain(3); + strain = theMaterial->getStrain(); + eleInfo.setVector(strain); + return 0; + } else { + // default is to call getResponse in the material + return theMaterial->getResponse(responseID, eleInfo); + } } int diff --git a/SRC/element/UWelements/Tcl_generateInterfacePoints.cpp b/SRC/element/UWelements/Tcl_generateInterfacePoints.cpp index 6119d2894d..f0cf17ccd8 100644 --- a/SRC/element/UWelements/Tcl_generateInterfacePoints.cpp +++ b/SRC/element/UWelements/Tcl_generateInterfacePoints.cpp @@ -63,8 +63,10 @@ TclCommand_GenerateInterfacePoints(ClientData clientData, Tcl_Interp *interp, in bool readingBeamEleTag = false; bool readingSolidEleTag = false; bool readingConBeamEleTag = false; + bool startTagSet = false; int lagrangeTag = 8; // 0 = local penalty, 1 = local Augmented Lagrangian, 2 = global Lagrange, 3 = global embedded lagrange, 4 = global penalty + int interfaceStartTag = 0; const char * crdsFN; const char * connectivityFN; @@ -380,6 +382,18 @@ TclCommand_GenerateInterfacePoints(ClientData clientData, Tcl_Interp *interp, in baseNodeTag = strtol(argv[curArgPos], NULL, 10); numArgsRemaining--; curArgPos++; } + else if ((strcmp(argv[curArgPos], "-startTag") == 0) && (numArgsRemaining >= 2)) + { + // This sets the starting tag for interface elements + readingSolidEleTag = false; + readingConBeamEleTag = false; + readingBeamEleTag = false; + startTagSet = true; + + numArgsRemaining--; curArgPos++; + interfaceStartTag = strtol(argv[curArgPos], NULL, 10); + numArgsRemaining--; curArgPos++; + } else { if (readingSolidEleTag) { @@ -437,7 +451,13 @@ TclCommand_GenerateInterfacePoints(ClientData clientData, Tcl_Interp *interp, in if (theElement->getTag() > maxTag) maxTag = theElement->getTag(); } - int startTag = maxTag + 1; + + // Use the provided startTag if set, otherwise use maxTag + 1 + int startTag; + if (startTagSet) + startTag = interfaceStartTag; + else + startTag = maxTag + 1; FileStream crdsFile, quadNodes, quadElems; if (writeCoords) @@ -451,6 +471,9 @@ TclCommand_GenerateInterfacePoints(ClientData clientData, Tcl_Interp *interp, in // Define variables needed int contactElemCount = 0, contactPointCount = 0; double area; + + // Initialize maxTag to startTag for interface element creation + maxTag = startTag; // Loop over beam elements for (int beamCount = 0; beamCount < beamEleTags.size(); beamCount++) @@ -700,8 +723,10 @@ TclCommand_GenerateInterfacePoints(ClientData clientData, Tcl_Interp *interp, in // 0 = local penalty, 1 = local Augmented Lagrangian, 2 = global Lagrange, 3 = global embedded lagrange if (lagrangeTag > 1) { - if (lagrangeTag == 2) + if (lagrangeTag == 2) { theElement = new EmbeddedBeamInterfaceL(maxTag, beamEleTagsInContact, solidEleTagsInContact, transfTag, contactPt_rho, contactPt_theta, contactPt_xi, contactPt_eta, contactPt_zeta, radius, contactPt_area, contactPt_length, writeConnectivity, connectivityFN); + opserr << "Creating EmbeddedBeamInterfaceL" << endln; + } else if (lagrangeTag == 3) { // if (beamConnected) @@ -709,8 +734,10 @@ TclCommand_GenerateInterfacePoints(ClientData clientData, Tcl_Interp *interp, in // else // theElement = new EmbeddedBeamInterfaceAL2(maxTag, beamEleTagsInContact, solidEleTagsInContact, transfTag, contactPt_rho, contactPt_theta, contactPt_xi, contactPt_eta, contactPt_zeta, radius, contactPt_area, writeConnectivity, connectivityFN); } - else if (lagrangeTag == 4) + else if (lagrangeTag == 4) { theElement = new EmbeddedBeamInterfaceP(maxTag, beamEleTagsInContact, solidEleTagsInContact, transfTag, contactPt_rho, contactPt_theta, contactPt_xi, contactPt_eta, contactPt_zeta, radius, contactPt_area, contactPt_length, penaltyParam, writeConnectivity, connectivityFN); + opserr << "Creating EmbeddedBeamInterfaceP " << endln; + } else if (lagrangeTag == 5) { // theElement = new EmbeddedBeamInterfaceAL2(maxTag, beamTag, solidEleTagsInContact, transfTag, contactPt_rho, contactPt_theta, contactPt_xi, contactPt_eta, contactPt_zeta, radius, area); @@ -832,7 +859,9 @@ TclCommand_GenerateToeInterfacePoints(ClientData clientData, Tcl_Interp *interp, bool solidEleSetDefined = false; bool debugFlag = false; bool writeCoords = false; + bool startTagSet = false; int lagrangeTag = 3; // 0 = local penalty, 1 = local Augmented Lagrangian, 2 = global Lagrange, 3 = global embedded lagrange + int interfaceStartTag = 0; const char * crdsFN; std::vector solidEleTags; @@ -991,6 +1020,16 @@ TclCommand_GenerateToeInterfacePoints(ClientData clientData, Tcl_Interp *interp, lagrangeTag = 4; numArgsRemaining--; curArgPos++; } + else if ((strcmp(argv[curArgPos], "-startTag") == 0) && (numArgsRemaining >= 2)) + { + // This sets the starting tag for interface elements + readingSolidEleTag = false; + startTagSet = true; + + numArgsRemaining--; curArgPos++; + interfaceStartTag = strtol(argv[curArgPos], NULL, 10); + numArgsRemaining--; curArgPos++; + } else { if (readingSolidEleTag) @@ -1042,7 +1081,16 @@ TclCommand_GenerateToeInterfacePoints(ClientData clientData, Tcl_Interp *interp, if (theElement->getTag() > maxTag) maxTag = theElement->getTag(); } - int startTag = maxTag + 1; + + // Use the provided startTag if set, otherwise use maxTag + 1 + int startTag; + if (startTagSet) + startTag = interfaceStartTag; + else + startTag = maxTag + 1; + + // Initialize maxTag to startTag for interface element creation + maxTag = startTag; diff --git a/SRC/element/brick/BbarBrick.cpp b/SRC/element/brick/BbarBrick.cpp index eb2c00b422..5b124b6057 100644 --- a/SRC/element/brick/BbarBrick.cpp +++ b/SRC/element/brick/BbarBrick.cpp @@ -1464,7 +1464,43 @@ BbarBrick::setResponse(const char **argv, int argc, OPS_Stream &output) output.endTag(); // GaussPoint } theResponse = new ElementResponse(this, 4, Vector(48)); + } else if (strcmp(argv[0],"stress3D6") == 0) { + + output.tag("GaussPoint"); + output.attr("number",1); + output.tag("NdMaterialOutput"); + output.attr("classType", materialPointers[0]->getClassTag()); + output.attr("tag", materialPointers[0]->getTag()); + + output.tag("ResponseType","sigma11"); + output.tag("ResponseType","sigma22"); + output.tag("ResponseType","sigma33"); + output.tag("ResponseType","sigma12"); + output.tag("ResponseType","sigma23"); + output.tag("ResponseType","sigma13"); + + output.endTag(); // NdMaterialOutput + output.endTag(); // GaussPoint + theResponse = new ElementResponse(this, 5, Vector(6)); + } else if (strcmp(argv[0],"strain3D6") == 0) { + output.tag("GaussPoint"); + output.attr("number",1); + output.tag("NdMaterialOutput"); + output.attr("classType", materialPointers[0]->getClassTag()); + output.attr("tag", materialPointers[0]->getTag()); + + output.tag("ResponseType","eps11"); + output.tag("ResponseType","eps22"); + output.tag("ResponseType","eps33"); + output.tag("ResponseType","eps12"); + output.tag("ResponseType","eps23"); + output.tag("ResponseType","eps13"); + + output.endTag(); // NdMaterialOutput + output.endTag(); // GaussPoint + theResponse = new ElementResponse(this, 6, Vector(6)); } + output.endTag(); // ElementOutput return theResponse; @@ -1513,7 +1549,33 @@ BbarBrick::getResponse(int responseID, Information &eleInfo) stresses(cnt++) = sigma(5); } return eleInfo.setVector(stresses); + } else if (responseID == 5) { + + Vector tmpStress(6); + for (int i = 0; i < 8; i++) { + const Vector &sigma = materialPointers[i]->getStress(); + tmpStress(0) += sigma(0) * 0.125; + tmpStress(1) += sigma(1) * 0.125; + tmpStress(2) += sigma(2) * 0.125; + tmpStress(3) += sigma(3) * 0.125; + tmpStress(4) += sigma(4) * 0.125; + tmpStress(5) += sigma(5) * 0.125; + } + return eleInfo.setVector(tmpStress); + } else if (responseID == 6) { + Vector tmpStrain(6); + for (int i = 0; i < 8; i++) { + const Vector &sigma = materialPointers[i]->getStrain(); + tmpStrain(0) += sigma(0) * 0.125; + tmpStrain(1) += sigma(1) * 0.125; + tmpStrain(2) += sigma(2) * 0.125; + tmpStrain(3) += sigma(3) * 0.125; + tmpStrain(4) += sigma(4) * 0.125; + tmpStrain(5) += sigma(5) * 0.125; + } + return eleInfo.setVector(tmpStrain); } + // Get) else return -1; diff --git a/SRC/element/brick/Brick.cpp b/SRC/element/brick/Brick.cpp index 5d263e12df..2da0992f57 100644 --- a/SRC/element/brick/Brick.cpp +++ b/SRC/element/brick/Brick.cpp @@ -1777,9 +1777,47 @@ Brick::setResponse(const char **argv, int argc, OPS_Stream &output) } theResponse = new ElementResponse(this, 5, Vector(48)); + } else if (strcmp(argv[0],"stress3D6") == 0) { + // this response if for vtkhdf recorder which averages the stresses + // over the 8 gauss points and returns the 6 values + output.tag("GaussPoint"); + output.attr("number",1); + output.tag("NdMaterialOutput"); + output.attr("classType", materialPointers[0]->getClassTag()); + output.attr("tag", materialPointers[0]->getTag()); + + output.tag("ResponseType","sigma11"); + output.tag("ResponseType","sigma22"); + output.tag("ResponseType","sigma33"); + output.tag("ResponseType","sigma12"); + output.tag("ResponseType","sigma23"); + output.tag("ResponseType","sigma13"); + + output.endTag(); // NdMaterialOutput + output.endTag(); // GaussPoint + theResponse = new ElementResponse(this, 6, Vector(6)); + + } else if (strcmp(argv[0],"strain3D6") == 0) { + // this response if for vtkhdf recorder which averages the strains + // over the 8 gauss points and returns the 6 values + output.tag("GaussPoint"); + output.attr("number",1); + output.tag("NdMaterialOutput"); + output.attr("classType", materialPointers[0]->getClassTag()); + output.attr("tag", materialPointers[0]->getTag()); + + output.tag("ResponseType","eps11"); + output.tag("ResponseType","eps22"); + output.tag("ResponseType","eps33"); + output.tag("ResponseType","eps12"); + output.tag("ResponseType","eps23"); + output.tag("ResponseType","eps13"); + + output.endTag(); // NdMaterialOutput + output.endTag(); // GaussPoint + + theResponse = new ElementResponse(this, 7, Vector(6)); } - - output.endTag(); // ElementOutput return theResponse; } @@ -1846,8 +1884,43 @@ Brick::getResponse(int responseID, Information &eleInfo) } return eleInfo.setVector(stresses); - } + } else if (responseID == 6) { + + // Loop over the integration points + Vector tmpStress(6); + for (int i = 0; i < 8; i++) { + + // Get material stress + const Vector &sigma = materialPointers[i]->getStress(); + tmpStress(0) += sigma(0)*0.125; + tmpStress(1) += sigma(1)*0.125; + tmpStress(2) += sigma(2)*0.125; + tmpStress(3) += sigma(3)*0.125; + tmpStress(4) += sigma(4)*0.125; + tmpStress(5) += sigma(5)*0.125; + } + + return eleInfo.setVector(tmpStress); + } else if (responseID == 7) { + + // Loop over the integration points + int cnt = 0; + Vector tmpStrain(6); + for (int i = 0; i < 8; i++) { + + // Get material strain + const Vector &sigma = materialPointers[i]->getStrain(); + tmpStrain(0) += sigma(0); + tmpStrain(1) += sigma(1); + tmpStrain(2) += sigma(2); + tmpStrain(3) += sigma(3); + tmpStrain(4) += sigma(4); + tmpStrain(5) += sigma(5); + } + tmpStrain /= 8.0; + return eleInfo.setVector(tmpStrain); + } else return -1; } diff --git a/SRC/element/dispBeamColumn/DispBeamColumn2d.cpp b/SRC/element/dispBeamColumn/DispBeamColumn2d.cpp index a321830d41..ac80ae70eb 100644 --- a/SRC/element/dispBeamColumn/DispBeamColumn2d.cpp +++ b/SRC/element/dispBeamColumn/DispBeamColumn2d.cpp @@ -907,6 +907,17 @@ DispBeamColumn2d::addLoad(ElementalLoad *theLoad, double loadFactor) q0[1] -= M; q0[2] += M; } + else if (type == LOAD_TAG_BeamUniformMoment) { + double mz = data(2)*loadFactor; // About z + + // Reactions in basic system + p0[1] += mz; + p0[2] -= mz; + + // Fixed end forces in basic system + //q0[1] -= 0.0; + //q0[2] += 0.0; + } else if (type == LOAD_TAG_Beam2dPointLoad) { double P = data(0)*loadFactor; double N = data(1)*loadFactor; diff --git a/SRC/element/elasticBeamColumn/ElasticBeam2d.cpp b/SRC/element/elasticBeamColumn/ElasticBeam2d.cpp index 43eaf9d232..e3b3486da5 100644 --- a/SRC/element/elasticBeamColumn/ElasticBeam2d.cpp +++ b/SRC/element/elasticBeamColumn/ElasticBeam2d.cpp @@ -827,7 +827,17 @@ ElasticBeam2d::addLoad(ElementalLoad *theLoad, double loadFactor) // Nothing to do } } + else if (type == LOAD_TAG_BeamUniformMoment) { + double mz = data(2)*loadFactor; // About z + // Reactions in basic system + p0[1] += mz; + p0[2] -= mz; + + // Fixed end forces in basic system + //q0[1] -= 0.0; + //q0[2] += 0.0; + } else if (type == LOAD_TAG_Beam2dPartialUniformLoad) { // These equations should works for partial trapezoidal load double waa = data(2)*loadFactor; // Axial diff --git a/SRC/element/forceBeamColumn/ForceBeamColumn2d.cpp b/SRC/element/forceBeamColumn/ForceBeamColumn2d.cpp index 8a5074d8eb..fef58eafd7 100644 --- a/SRC/element/forceBeamColumn/ForceBeamColumn2d.cpp +++ b/SRC/element/forceBeamColumn/ForceBeamColumn2d.cpp @@ -1084,6 +1084,12 @@ ForceBeamColumn2d::computeReactions(double *p0) p0[1] -= V; p0[2] -= V; } + if (type == LOAD_TAG_BeamUniformMoment) { + double mz = data(2)*loadFactor; // About z + + p0[1] += mz; + p0[2] -= mz; + } else if (type == LOAD_TAG_Beam2dPartialUniformLoad) { double waa = data(2)*loadFactor; // Axial double wab = data(3)*loadFactor; // Axial @@ -1347,6 +1353,9 @@ ForceBeamColumn2d::update() double xL1 = xL-1.0; double wtL = wt[i]*L; + // store the length of the current integration point + current_section_lch = wtL; + // calculate total section forces // Ss = b*Se + bp*currDistrLoad; // Ss.addMatrixVector(0.0, b[i], Se, 1.0); @@ -1510,6 +1519,10 @@ ForceBeamColumn2d::update() } } + // reset it to the default (whole length) in case the getChatacteristiLength function + // is called in the wrong place + current_section_lch = L; + // calculate element stiffness matrix // invert3by3Matrix(f, kv); if (f.Solve(I, kvTrial) < 0) @@ -1735,6 +1748,24 @@ ForceBeamColumn2d::computeSectionForces(Vector &sp, int isec) } } } + else if (type == LOAD_TAG_BeamUniformMoment) { + double mz = data(2)*loadFactor; // About z + + for (int ii = 0; ii < order; ii++) { + + switch(code(ii)) { + case SECTION_RESPONSE_P: + break; + case SECTION_RESPONSE_MZ: + break; + case SECTION_RESPONSE_VY: + sp(ii) += mz; + break; + default: + break; + } + } + } else if (type == LOAD_TAG_Beam2dPartialUniformLoad) { double waa = data(2)*loadFactor; // Axial double wab = data(3)*loadFactor; // Axial @@ -3413,6 +3444,17 @@ ForceBeamColumn2d::getResponse(int responseID, Information &eleInfo) else return -1; +} + +double ForceBeamColumn2d::getCharacteristicLength(void) +{ + // The default implementation of Element::getCharacteristicLength() + // returns the whole element length. + // However, FB element localizes only in a 1 integration point + // so we should return the i-th integration-point's length + if (current_section_lch > 0.0) + return current_section_lch; + return Element::getCharacteristicLength(); } int diff --git a/SRC/element/forceBeamColumn/ForceBeamColumn2d.h b/SRC/element/forceBeamColumn/ForceBeamColumn2d.h index 486980c9d2..1c02712892 100644 --- a/SRC/element/forceBeamColumn/ForceBeamColumn2d.h +++ b/SRC/element/forceBeamColumn/ForceBeamColumn2d.h @@ -124,7 +124,10 @@ class ForceBeamColumn2d: public Element Response *setResponse(const char **argv, int argc, OPS_Stream &s); int getResponse(int responseID, Information &eleInformation); - + + // calculate the characteristic length for this element + double getCharacteristicLength(void); + // AddingSensitivity:BEGIN ////////////////////////////////////////// int setParameter(const char **argv, int argc, Parameter ¶m); int updateParameter(int parameterID, Information &info); @@ -197,6 +200,10 @@ class ForceBeamColumn2d: public Element Matrix *Ki; + // this variable holds the length of the i-th integration point + // undergoing the update (FB element localizes at the integration point level) + double current_section_lch = 0.0; + static Matrix theMatrix; static Vector theVector; static double workArea[]; diff --git a/SRC/element/forceBeamColumn/ForceBeamColumn3d.cpp b/SRC/element/forceBeamColumn/ForceBeamColumn3d.cpp index 51add0480c..29e34d9499 100644 --- a/SRC/element/forceBeamColumn/ForceBeamColumn3d.cpp +++ b/SRC/element/forceBeamColumn/ForceBeamColumn3d.cpp @@ -1072,6 +1072,9 @@ void double xL = xi[i]; double xL1 = xL-1.0; double wtL = wt[i]*L; + + // store the length of the current integration point + current_section_lch = wtL; // calculate total section forces // Ss = b*Se + bp*currDistrLoad; @@ -1302,6 +1305,10 @@ void } } + // reset it to the default (whole length) in case the getChatacteristiLength function + // is called in the wrong place + current_section_lch = L; + if (!isTorsion) { f(5,5) = DefaultLoverGJ; vr(5) = SeTrial(5)*DefaultLoverGJ; @@ -1697,7 +1704,7 @@ ForceBeamColumn3d::computeSectionForces(Vector &sp, int isec) sp(ii) += x*Vz1; break; case SECTION_RESPONSE_VZ: - sp(ii) -= Vz1; + sp(ii) += Vz1; break; default: break; @@ -1715,7 +1722,7 @@ ForceBeamColumn3d::computeSectionForces(Vector &sp, int isec) sp(ii) += (L-x)*Vz2; break; case SECTION_RESPONSE_VZ: - sp(ii) += Vz2; + sp(ii) -= Vz2; break; default: break; @@ -3670,6 +3677,17 @@ ForceBeamColumn3d::getResponse(int responseID, Information &eleInfo) else return -1; +} + +double ForceBeamColumn3d::getCharacteristicLength(void) +{ + // The default implementation of Element::getCharacteristicLength() + // returns the whole element length. + // However, FB element localizes only in a 1 integration point + // so we should return the i-th integration-point's length + if (current_section_lch > 0.0) + return current_section_lch; + return Element::getCharacteristicLength(); } int diff --git a/SRC/element/forceBeamColumn/ForceBeamColumn3d.h b/SRC/element/forceBeamColumn/ForceBeamColumn3d.h index 83c2f36bf6..72be657e66 100644 --- a/SRC/element/forceBeamColumn/ForceBeamColumn3d.h +++ b/SRC/element/forceBeamColumn/ForceBeamColumn3d.h @@ -124,6 +124,9 @@ class ForceBeamColumn3d: public Element Response *setResponse(const char **argv, int argc, OPS_Stream &s); int getResponse(int responseID, Information &eleInformation); + + // calculate the characteristic length for this element + double getCharacteristicLength(void); // AddingSensitivity:BEGIN ////////////////////////////////////////// int setParameter(const char **argv, int argc, Parameter ¶m); @@ -201,6 +204,10 @@ class ForceBeamColumn3d: public Element Damping *theDamping; + // this variable holds the length of the i-th integration point + // undergoing the update (FB element localizes at the integration point level) + double current_section_lch = 0.0; + static Matrix theMatrix; static Vector theVector; static double workArea[]; diff --git a/SRC/element/frictionBearing/SingleFPSimple2d.cpp b/SRC/element/frictionBearing/SingleFPSimple2d.cpp index 519f0c580a..669e822961 100755 --- a/SRC/element/frictionBearing/SingleFPSimple2d.cpp +++ b/SRC/element/frictionBearing/SingleFPSimple2d.cpp @@ -182,7 +182,7 @@ void* OPS_SingleFPSimple2d() opserr<<"WARNING: invalid tol\n"; return 0; } - } else if (strcmp(type,"-inclVertdisp") == 0) { + } else if (strcmp(type,"-inclVertDisp") == 0) { inclVertDisp = 1; } else if (strcmp(type,"-kFactUplift") == 0) { if (OPS_GetNumRemainingInputArgs() < 1) { @@ -1190,3 +1190,4 @@ SingleFPSimple2d::updateParameter(int parameterID, Information &info) return -1; } } + diff --git a/SRC/element/frictionBearing/SingleFPSimple3d.cpp b/SRC/element/frictionBearing/SingleFPSimple3d.cpp index 95c8c93ffe..d13758cc90 100755 --- a/SRC/element/frictionBearing/SingleFPSimple3d.cpp +++ b/SRC/element/frictionBearing/SingleFPSimple3d.cpp @@ -221,7 +221,7 @@ void* OPS_SingleFPSimple3d() opserr<<"WARNING: invalid tol\n"; return 0; } - } else if (strcmp(type,"-inclVertdisp") == 0) { + } else if (strcmp(type,"-inclVertDisp") == 0) { inclVertDisp = 1; } else if (strcmp(type,"-kFactUplift") == 0) { if (OPS_GetNumRemainingInputArgs() < 1) { @@ -1338,3 +1338,4 @@ SingleFPSimple3d::updateParameter(int parameterID, Information &info) return -1; } } + diff --git a/SRC/element/mvlem/SFI_MVLEM.cpp b/SRC/element/mvlem/SFI_MVLEM.cpp index bcf69155af..f742d89aed 100755 --- a/SRC/element/mvlem/SFI_MVLEM.cpp +++ b/SRC/element/mvlem/SFI_MVLEM.cpp @@ -68,6 +68,7 @@ void *OPS_SFI_MVLEM(void) int iData[4]; double dData[1]; + int coupling = 0; int numData = 4; if (OPS_GetIntInput(&numData, iData) != 0) { @@ -134,10 +135,25 @@ void *OPS_SFI_MVLEM(void) numArgs = OPS_GetNumRemainingInputArgs(); } +if (numArgs > 0) { + str = OPS_GetString(); + numData = 1; + if (strcmp(str, "-Coupling") == 0) { + if (OPS_GetIntInput(&numData, &coupling) != 0) { + opserr << "WARNING invalid coupling data for element SFI_MVLEM" << endln; + return 0; + } + if (coupling < 0 || coupling>2) { + opserr << "WARNING invalid int data for element SFI_MVLEM coupling (it should be 0,1,or 2)" << endln; + return 0; + } + + } + } theElement = new SFI_MVLEM(iData[0], iData[1], iData[2], theMaterials, - theThickness, theWidth, iData[3], dData[0]); + theThickness, theWidth , iData[3], dData[0], coupling); // Cleanup dynamic memory @@ -161,14 +177,15 @@ SFI_MVLEM::SFI_MVLEM(int tag, double *thickness, double *width, int mm, - double cc) + double cc, + int coupling) :Element(tag,ELE_TAG_SFI_MVLEM), theNd1(0), theNd2(0), theNodesX(0), theNodesALL(0), theMaterial(0), theLoad(0), - m(mm),c(cc), + m(mm),c(cc),Coupling(coupling), externalNodes(2+m), SFI_MVLEMStrainX(0),SFI_MVLEMStrainY(0),SFI_MVLEMStrainXY(0),SFI_MVLEMStrain(0), x(0), b(0), AcX(0), AcY(0), kx(0), ky(0), kh(0), Fx(0), Fy(0), Fxy(0), Dens(0), Dx(0), Dy(0), Dxy(0), @@ -396,7 +413,7 @@ SFI_MVLEM::SFI_MVLEM() x(0), b(0), AcX(0), AcY(0), kx(0), ky(0), kh(0), Fx(0), Fy(0), Fxy(0), Dens(0), Dx(0), Dy(0), Dxy(0), SFI_MVLEMK(6+m,6+m), SFI_MVLEMR(6+m), SFI_MVLEMD(6+m,6+m), SFI_MVLEMM(6+m,6+m), P_6DOF(6), - m(0),c(0) + m(0),c(0), Coupling(0) { if (externalNodes.Size() != 2+m) opserr << "FATAL SFI_MVLEM::SFI_MVLEM() - out of memory, could not create an ID of size 2\n"; @@ -616,7 +633,7 @@ void SFI_MVLEM::setDomain(Domain *theDomain) // Create coordinates wrt top and bottom element node double xLoc_temp = end1Crd(0) + x[i]; double yLoc_temp = 0.5*(end1Crd(1)+end2Crd(1)); // Mid-height - double zloc_temp = end1Crd(2); // Not currently used since Domain is 2D + //double zloc_temp = end1Crd(2); // Not currently used since Domain is 2D // Create Node and add it to the domain Node *theNode = 0; @@ -1161,6 +1178,7 @@ int SFI_MVLEM::getResponse(int responseID, Information &eleInfo) const Matrix & SFI_MVLEM::getInitialStiff(void) { double Kh=0.0; +SFI_MVLEMK.Zero(); for (int i=0; i < m; i++) { @@ -1174,8 +1192,136 @@ const Matrix & SFI_MVLEM::getInitialStiff(void) kx[i] = D00 * h*t[i] / b[i]; ky[i] = D11 * b[i]*t[i] / h; Kh += D22 * b[i]*t[i] / h; + + // defining the coupling terms of stress strain relationship + double kxy = D01 * t[i]; //Zakariya Waezi + double ktaux = D02 * t[i]; //Zakariya Waezi + double ktauy = D12 * b[i] * t[i] / h; //Zakariya Waezi + + double exy = kxy * x[i]; //Zakariya Waezi + double etauy = ktauy * x[i]; //Zakariya Waezi + double etaux = ktaux * x[i]; //Zakariya Waezi + + //Considering the coupling between axial stresses sigmax and sigma y is taken care of here: Zakariya Waezi + // if the material is linear elastic, Coupling 1 is enough + if (Coupling == 1 || Coupling==2) { //Zakariya Waezi + SFI_MVLEMK(1, 6 + i) = -kxy; + SFI_MVLEMK(6 + i, 1) = SFI_MVLEMK(1, 6 + i); + + SFI_MVLEMK(2, 6 + i) = -exy; + SFI_MVLEMK(6 + i, 2) = SFI_MVLEMK(2, 6 + i); + + SFI_MVLEMK(4, 6 + i) = kxy; + SFI_MVLEMK(6 + i, 4) = SFI_MVLEMK(4, 6 + i); + + SFI_MVLEMK(5, 6 + i) = exy; + SFI_MVLEMK(6 + i, 5) = SFI_MVLEMK(5, 6 + i); + } + + //Considering the coupling between shear stress and axial stresses in addition to axial stresses coupling + // is taken care of here: + // if the material is nonlinear, for complete consideration of coupling, Coupling variable should be 2 + // Zakariya Waezi + if (Coupling == 2) { + //SFI_MVLEMK(0, 0) += 0; + + SFI_MVLEMK(0, 1) += ktauy; + + SFI_MVLEMK(0, 2) += etauy; + + //SFI_MVLEMK(0, 3) += 0; + + SFI_MVLEMK(0, 4) += -ktauy; + + SFI_MVLEMK(0, 5) += -etauy; + + SFI_MVLEMK(0, 6 + i) += -ktaux; + + SFI_MVLEMK(1, 0) += ktauy; + + //SFI_MVLEMK(1, 1) += 0; + + SFI_MVLEMK(1, 2) += -c * h * ktauy; + + SFI_MVLEMK(1, 3) += -ktauy; + + //SFI_MVLEMK(1, 4) += 0; + + SFI_MVLEMK(1, 5) += (-1 + c) * h * ktauy; + + //SFI_MVLEMK(1, 6+i) += 0; + + SFI_MVLEMK(2, 0) += etauy; + + SFI_MVLEMK(2, 1) += -c * h * ktauy; + + SFI_MVLEMK(2, 2) += -2 * c * etauy * h; + + SFI_MVLEMK(2, 3) += -etauy; + + SFI_MVLEMK(2, 4) += c * h * ktauy; + + SFI_MVLEMK(2, 5) += (-1 + 2 * c) * etauy * h; + + SFI_MVLEMK(2, 6 + i) += c * h * ktaux; + + //SFI_MVLEMK(3, 0) += 0; + + SFI_MVLEMK(3, 1) += -ktauy; + + SFI_MVLEMK(3, 2) += -etauy; + + //SFI_MVLEMK(3, 3) += 0; + + SFI_MVLEMK(3, 4) += ktauy; + + SFI_MVLEMK(3, 5) += etauy; + + SFI_MVLEMK(3, 6 + i) += ktaux; + + SFI_MVLEMK(4, 0) += -ktauy; + + //SFI_MVLEMK(4, 1) += 0; + + SFI_MVLEMK(4, 2) += c * h * ktauy; + + SFI_MVLEMK(4, 3) += ktauy; + + //SFI_MVLEMK(4, 4) += 0; + + SFI_MVLEMK(4, 5) += -(-1 + c) * h * ktauy; + + //SFI_MVLEMK(4, 6+i) += 0; + + SFI_MVLEMK(5, 0) += -etauy; + + SFI_MVLEMK(5, 1) += (-1 + c) * h * ktauy; + + SFI_MVLEMK(5, 2) += (-1 + 2 * c) * etauy * h; + + SFI_MVLEMK(5, 3) += etauy; + + SFI_MVLEMK(5, 4) += (1 - c) * h * ktauy; + + SFI_MVLEMK(5, 5) += 2 * (1 - c) * etauy * h; + + SFI_MVLEMK(5, 6 + i) += (1 - c) * h * ktaux; + + SFI_MVLEMK(6 + i, 0) += -ktaux; + + //SFI_MVLEMK(6+i, 1) += 0; + + SFI_MVLEMK(6 + i, 2) += c * h * ktaux; + + SFI_MVLEMK(6 + i, 3) += ktaux; + + //SFI_MVLEMK(6+i, 4) += 0; + + SFI_MVLEMK(6 + i, 5) += (1 - c) * h * ktaux; + } } + // end of coupling terms effect ZW // Build the initial stiffness matrix double Kv=0.0; double Km=0.0; double e=0.0; double ex=0.0; @@ -1186,50 +1332,50 @@ const Matrix & SFI_MVLEM::getInitialStiff(void) Km+=ky[i]*x[i]*x[i]; e+=ky[i]*x[i]; - SFI_MVLEMK(6+i,6+i) = kx[i]; // Diagonal terms accounting for horizontal stiffness + SFI_MVLEMK(6+i,6+i) += kx[i]; // Diagonal terms accounting for horizontal stiffness } - SFI_MVLEMK(0,0) = Kh; - SFI_MVLEMK(0,1) = 0.0; - SFI_MVLEMK(0,2) = -Kh*c*h; - SFI_MVLEMK(0,3) = -Kh; - SFI_MVLEMK(0,4) = 0.0; - SFI_MVLEMK(0,5) = -Kh*(1-c)*h; + SFI_MVLEMK(0,0) += Kh; + //SFI_MVLEMK(0,1) += 0.0; + SFI_MVLEMK(0,2) += -Kh*c*h; + SFI_MVLEMK(0,3) += -Kh; + //SFI_MVLEMK(0,4) += 0.0; + SFI_MVLEMK(0,5) += -Kh*(1-c)*h; SFI_MVLEMK(1,0) = SFI_MVLEMK(0,1); - SFI_MVLEMK(1,1) = Kv; - SFI_MVLEMK(1,2) = e; - SFI_MVLEMK(1,3) = 0.0; - SFI_MVLEMK(1,4) = -Kv; - SFI_MVLEMK(1,5) = -e; + SFI_MVLEMK(1,1) += Kv; + SFI_MVLEMK(1,2) += e; + //SFI_MVLEMK(1,3) += 0.0; + SFI_MVLEMK(1,4) += -Kv; + SFI_MVLEMK(1,5) += -e; SFI_MVLEMK(2,0) = SFI_MVLEMK(0,2); SFI_MVLEMK(2,1) = SFI_MVLEMK(1,2); - SFI_MVLEMK(2,2) = h*h*c*c*Kh+Km; - SFI_MVLEMK(2,3) = h*c*Kh; - SFI_MVLEMK(2,4) = -e; - SFI_MVLEMK(2,5) = (1-c)*c*h*h*Kh-Km; + SFI_MVLEMK(2,2) += h*h*c*c*Kh+Km; + SFI_MVLEMK(2,3) += h*c*Kh; + SFI_MVLEMK(2,4) += -e; + SFI_MVLEMK(2,5) += (1-c)*c*h*h*Kh-Km; SFI_MVLEMK(3,0) = SFI_MVLEMK(0,3); SFI_MVLEMK(3,1) = SFI_MVLEMK(1,3); SFI_MVLEMK(3,2) = SFI_MVLEMK(2,3); - SFI_MVLEMK(3,3) = Kh; - SFI_MVLEMK(3,4) = 0.0; - SFI_MVLEMK(3,5) = Kh*(1-c)*h; + SFI_MVLEMK(3,3) += Kh; + //SFI_MVLEMK(3,4) += 0.0; + SFI_MVLEMK(3,5) += Kh*(1-c)*h; SFI_MVLEMK(4,0) = SFI_MVLEMK(0,4); SFI_MVLEMK(4,1) = SFI_MVLEMK(1,4); SFI_MVLEMK(4,2) = SFI_MVLEMK(2,4); SFI_MVLEMK(4,3) = SFI_MVLEMK(3,4); - SFI_MVLEMK(4,4) = Kv; - SFI_MVLEMK(4,5) = e; + SFI_MVLEMK(4,4) += Kv; + SFI_MVLEMK(4,5) += e; SFI_MVLEMK(5,0) = SFI_MVLEMK(0,5); SFI_MVLEMK(5,1) = SFI_MVLEMK(1,5); SFI_MVLEMK(5,2) = SFI_MVLEMK(2,5); SFI_MVLEMK(5,3) = SFI_MVLEMK(3,5); SFI_MVLEMK(5,4) = SFI_MVLEMK(4,5); - SFI_MVLEMK(5,5) = (1-c)*(1-c)*h*h*Kh+Km; + SFI_MVLEMK(5,5) += (1-c)*(1-c)*h*h*Kh+Km; for(int i=0; i<6+m; ++i) { @@ -1263,62 +1409,190 @@ const Matrix & SFI_MVLEM::getTangentStiff(void) ky[i] = D11 * b[i]*t[i] / h; Kh += D22 * b[i]*t[i] / h; - } + // defining the coupling terms of stress-strain relationship + double kxy = D01 * t[i]; //Zakariya Waezi + double ktaux = D02 * t[i]; //Zakariya Waezi + double ktauy = D12 * b[i] * t[i] / h; //Zakariya Waezi - // Build the tangent stiffness matrix - double Kv=0.0; double Km=0.0; double e=0.0; double ex=0.0; + double exy = kxy * x[i]; //Zakariya Waezi + double etauy = ktauy * x[i]; //Zakariya Waezi + double etaux = ktaux * x[i]; //Zakariya Waezi - for(int i=0; igetNodes()[1]->getCrds()); Vector3Type P3(m_transformation->getNodes()[2]->getCrds()); Vector3Type P4(m_transformation->getNodes()[3]->getCrds()); - Vector3Type e1 = (P2 + P3) / 2.0 - (P1 + P4) / 2.0; + e1 = (P2 + P3) / 2.0 - (P1 + P4) / 2.0; e1.normalize(); } m_angle = std::acos(std::max(-1.0, std::min(1.0, e1.dot(e1_local)))); diff --git a/SRC/element/shell/ASDShellT3.cpp b/SRC/element/shell/ASDShellT3.cpp index 0ddbddbb3f..31c04e6b45 100644 --- a/SRC/element/shell/ASDShellT3.cpp +++ b/SRC/element/shell/ASDShellT3.cpp @@ -514,8 +514,8 @@ namespace T(4, 3) = s * s; T(4, 4) = c * c; T(4, 5) = s * c; T(5, 3) = 2.0 * s * c; T(5, 4) = -2.0 * s * c; T(5, 5) = c * c - s * s; - T(6, 6) = c; T(6, 7) = s; - T(7, 6) = -s; T(7, 7) = c; + T(6, 6) = c; T(6, 7) = -s; + T(7, 6) = s; T(7, 7) = c; } // computes the transformation matrix for generalized stresses @@ -534,8 +534,8 @@ namespace T(4, 3) = s * s; T(4, 4) = c * c; T(4, 5) = 2.0 * s * c; T(5, 3) = s * c; T(5, 4) = -s * c; T(5, 5) = c * c - s * s; - T(6, 6) = c; T(6, 7) = s; - T(7, 6) = -s; T(7, 7) = c; + T(6, 6) = c; T(6, 7) = -s; + T(7, 6) = s; T(7, 7) = c; } } @@ -678,7 +678,7 @@ void ASDShellT3::setDomain(Domain* theDomain) // default one Vector3Type P1(m_transformation->getNodes()[0]->getCrds()); Vector3Type P2(m_transformation->getNodes()[1]->getCrds()); - Vector3Type e1 = (P2 - P1) / 2.0; + e1 = (P2 - P1) / 2.0; e1.normalize(); } m_angle = std::acos(std::max(-1.0, std::min(1.0, e1.dot(e1_local)))); diff --git a/SRC/element/surfaceLoad/SurfaceLoad.cpp b/SRC/element/surfaceLoad/SurfaceLoad.cpp index 962bbc424c..09186a4623 100644 --- a/SRC/element/surfaceLoad/SurfaceLoad.cpp +++ b/SRC/element/surfaceLoad/SurfaceLoad.cpp @@ -47,9 +47,10 @@ double SurfaceLoad :: oneOverRoot3 = 1.0/sqrt(3.0); double SurfaceLoad :: GsPts[4][2]; -Matrix SurfaceLoad::tangentStiffness(SL_NUM_DOF, SL_NUM_DOF); -Vector SurfaceLoad::internalForces(SL_NUM_DOF); -Vector SurfaceLoad::theVector(SL_NUM_DOF); +Matrix SurfaceLoad::tangentStiffness12(12,12); +Matrix SurfaceLoad::tangentStiffness24(24,24); +Vector SurfaceLoad::internalForces12(12); +Vector SurfaceLoad::internalForces24(24); #include static int num_SurfaceLoad = 0; @@ -100,14 +101,15 @@ OPS_SurfaceLoad(void) SurfaceLoad::SurfaceLoad(int tag, int Nd1, int Nd2, int Nd3, int Nd4, double pressure) :Element(tag,ELE_TAG_SurfaceLoad), myExternalNodes(SL_NUM_NODE), + numDOF(0), theMatrix(0), theVector(0), g1(SL_NUM_NDF), g2(SL_NUM_NDF), myNhat(SL_NUM_NDF), myNI(SL_NUM_NODE), - dcrd1(SL_NUM_NDF), - dcrd2(SL_NUM_NDF), - dcrd3(SL_NUM_NDF), - dcrd4(SL_NUM_NDF) + dcrd1(3), + dcrd2(3), + dcrd3(3), + dcrd4(3) { myExternalNodes(0) = Nd1; myExternalNodes(1) = Nd2; @@ -126,19 +128,26 @@ SurfaceLoad::SurfaceLoad(int tag, int Nd1, int Nd2, int Nd3, int Nd4, double pre my_pressure = pressure; mLoadFactor = 1.0; + + tangentStiffness12.Zero(); + tangentStiffness24.Zero(); + + internalForces12.Zero(); + internalForces24.Zero(); } SurfaceLoad::SurfaceLoad() :Element(0,ELE_TAG_SurfaceLoad), myExternalNodes(SL_NUM_NODE), + numDOF(0), theMatrix(0), theVector(0), g1(SL_NUM_NDF), g2(SL_NUM_NDF), myNhat(SL_NUM_NDF), myNI(SL_NUM_NODE), - dcrd1(SL_NUM_NDF), - dcrd2(SL_NUM_NDF), - dcrd3(SL_NUM_NDF), - dcrd4(SL_NUM_NDF) + dcrd1(3), + dcrd2(3), + dcrd3(3), + dcrd4(3) { } @@ -168,7 +177,7 @@ SurfaceLoad::getNodePtrs(void) int SurfaceLoad::getNumDOF(void) { - return SL_NUM_DOF; + return numDOF; } void @@ -188,7 +197,24 @@ SurfaceLoad::setDomain(Domain *theDomain) dcrd2 = theNodes[1]->getCrds(); dcrd3 = theNodes[2]->getCrds(); dcrd4 = theNodes[3]->getCrds(); + if (3 != dcrd1.Size() || 3 != dcrd2.Size() || 3 != dcrd3.Size() || 3 != dcrd4.Size()) { + opserr << "SurfaceLoad::setDomain() - nodes are not defined in three dimensions" << endln; + return; + } + int ndf1 = theNodes[0]->getNumberDOF(); + int ndf2 = theNodes[1]->getNumberDOF(); + int ndf3 = theNodes[2]->getNumberDOF(); + int ndf4 = theNodes[3]->getNumberDOF(); + if (ndf1 != ndf2 || ndf1 != ndf3 || ndf1 != ndf4) { + opserr << "SurfaceLoad::setDomain() - nodes have differing numbers of DOFs" << endln; + return; + } + + numDOF = SL_NUM_NODE*ndf1; + theMatrix = (numDOF == 12) ? &tangentStiffness12 : &tangentStiffness24; + theVector = (numDOF == 12) ? &internalForces12 : &internalForces24; + // call the base class method this->DomainComponent::setDomain(theDomain); } @@ -254,14 +280,15 @@ SurfaceLoad::UpdateBase(double Xi, double Eta) const Matrix & SurfaceLoad::getTangentStiff(void) { - tangentStiffness.Zero(); - return tangentStiffness; + //theMatrix->Zero(); + return *theMatrix; } const Matrix & SurfaceLoad::getInitialStiff(void) { - return getTangentStiff(); + //theMatrix->Zero(); + return *theMatrix; } void @@ -296,22 +323,23 @@ SurfaceLoad::addInertiaLoadToUnbalance(const Vector &accel) const Vector & SurfaceLoad::getResistingForce() { - internalForces.Zero(); + theVector->Zero(); + int nodeDOF = (numDOF == 12) ? 3 : 6; // loop over Gauss points for(int i = 0; i < 4; i++) { this->UpdateBase(GsPts[i][0],GsPts[i][1]); // loop over nodes - for(int j = 0; j < 4; j++) { - // loop over dof + for(int j = 0; j < SL_NUM_NODE; j++) { + // loop over displacement dof for(int k = 0; k < 3; k++) { - internalForces[j*3+k] = internalForces[j*3+k] - mLoadFactor*my_pressure*myNhat(k)*myNI(j); + (*theVector)[j*nodeDOF+k] -= mLoadFactor*my_pressure*myNhat(k)*myNI(j); } } } - return internalForces; + return *theVector; } const Vector & diff --git a/SRC/element/surfaceLoad/SurfaceLoad.h b/SRC/element/surfaceLoad/SurfaceLoad.h index 87b96ebc2a..f2d396e26d 100644 --- a/SRC/element/surfaceLoad/SurfaceLoad.h +++ b/SRC/element/surfaceLoad/SurfaceLoad.h @@ -97,10 +97,16 @@ class SurfaceLoad : public Element int UpdateBase(double Xi, double Eta); ID myExternalNodes; // contains the tags of the end nodes - static Matrix tangentStiffness; // Tangent Stiffness matrix - static Vector internalForces; // vector of Internal Forces - static Vector theVector; // vector to return the residual + static Matrix tangentStiffness12; // Tangent Stiffness matrix for 4 x 3 dofs/node + static Vector internalForces12; // vector of Internal Forces for 4 x 3 dofs/node + static Matrix tangentStiffness24; // Tangent Stiffness matrix for 4 x 6 dofs/node + static Vector internalForces24; // vector of Internal Forces for 4 x 6 dofs/node + int numDOF; // number of element dofs (12 or 24) + + Matrix *theMatrix; + Vector *theVector; + double my_pressure; // pressure applied to surface of element Node *theNodes[SL_NUM_NODE]; diff --git a/SRC/element/surfaceLoad/TriSurfaceLoad.cpp b/SRC/element/surfaceLoad/TriSurfaceLoad.cpp index 543f532e28..d0d8245534 100644 --- a/SRC/element/surfaceLoad/TriSurfaceLoad.cpp +++ b/SRC/element/surfaceLoad/TriSurfaceLoad.cpp @@ -45,10 +45,10 @@ double TriSurfaceLoad::oneOverRoot3 = 1.0/sqrt(3.0); double TriSurfaceLoad::GsPts[1][1]; -Matrix TriSurfaceLoad::tangentStiffness(SL_NUM_DOF, SL_NUM_DOF); -Matrix TriSurfaceLoad::mass(SL_NUM_DOF, SL_NUM_DOF); -Matrix TriSurfaceLoad::damp(SL_NUM_DOF, SL_NUM_DOF); -Vector TriSurfaceLoad::internalForces(SL_NUM_DOF); +Matrix TriSurfaceLoad::tangentStiffness9(9,9); +Matrix TriSurfaceLoad::tangentStiffness18(18,18); +Vector TriSurfaceLoad::internalForces9(9); +Vector TriSurfaceLoad::internalForces18(18); #include static int num_TriSurfaceLoad = 0; @@ -109,13 +109,14 @@ OPS_TriSurfaceLoad(void) TriSurfaceLoad::TriSurfaceLoad(int tag, int Nd1, int Nd2, int Nd3, double pressure, double rhoH_) :Element(tag,ELE_TAG_TriSurfaceLoad), myExternalNodes(SL_NUM_NODE), + numDOF(0), theMatrix(0), theVector(0), g1(SL_NUM_NDF), g2(SL_NUM_NDF), myNhat(SL_NUM_NDF), myNI(SL_NUM_NODE), - dcrd1(SL_NUM_NDF), - dcrd2(SL_NUM_NDF), - dcrd3(SL_NUM_NDF) + dcrd1(3), + dcrd2(3), + dcrd3(3) { myExternalNodes(0) = Nd1; myExternalNodes(1) = Nd2; @@ -127,18 +128,25 @@ TriSurfaceLoad::TriSurfaceLoad(int tag, int Nd1, int Nd2, int Nd3, double pressu rhoH = rhoH_; mLoadFactor = 1.0; + + tangentStiffness9.Zero(); + tangentStiffness18.Zero(); + + internalForces9.Zero(); + internalForces18.Zero(); } TriSurfaceLoad::TriSurfaceLoad() :Element(0,ELE_TAG_TriSurfaceLoad), myExternalNodes(SL_NUM_NODE), + numDOF(0), theMatrix(0), theVector(0), g1(SL_NUM_NDF), g2(SL_NUM_NDF), myNhat(SL_NUM_NDF), myNI(SL_NUM_NODE), - dcrd1(SL_NUM_NDF), - dcrd2(SL_NUM_NDF), - dcrd3(SL_NUM_NDF) + dcrd1(3), + dcrd2(3), + dcrd3(3) { GsPts[0][0] = 1.0/3; my_pressure = 0; @@ -172,7 +180,7 @@ TriSurfaceLoad::getNodePtrs(void) int TriSurfaceLoad::getNumDOF(void) { - return SL_NUM_DOF; + return numDOF; } void @@ -190,7 +198,23 @@ TriSurfaceLoad::setDomain(Domain *theDomain) dcrd1 = theNodes[0]->getCrds(); dcrd2 = theNodes[1]->getCrds(); dcrd3 = theNodes[2]->getCrds(); + if (3 != dcrd1.Size() || 3 != dcrd2.Size() || 3 != dcrd3.Size()) { + opserr << "TriSurfaceLoad::setDomain() - nodes are not defined in three dimensions" << endln; + return; + } + + int ndf1 = theNodes[0]->getNumberDOF(); + int ndf2 = theNodes[1]->getNumberDOF(); + int ndf3 = theNodes[2]->getNumberDOF(); + if (ndf1 != ndf2 || ndf1 != ndf3) { + opserr << "TriSurfaceLoad::setDomain() - nodes have differing numbers of DOFs" << endln; + return; + } + numDOF = SL_NUM_NODE*ndf1; + theMatrix = (numDOF == 9) ? &tangentStiffness9 : &tangentStiffness18; + theVector = (numDOF == 9) ? &internalForces9 : &internalForces18; + // call the base class method this->DomainComponent::setDomain(theDomain); } @@ -252,14 +276,17 @@ TriSurfaceLoad::UpdateBase(double Xi, double Eta) const Matrix & TriSurfaceLoad::getTangentStiff(void) { - tangentStiffness.Zero(); - return tangentStiffness; + theMatrix->Zero(); // have to call bc of getMass + + return *theMatrix; } const Matrix & TriSurfaceLoad::getInitialStiff(void) { - return getTangentStiff(); + theMatrix->Zero(); // have to call bc of getMass + + return *theMatrix; } void @@ -295,22 +322,23 @@ TriSurfaceLoad::addInertiaLoadToUnbalance(const Vector &accel) const Vector & TriSurfaceLoad::getResistingForce() { - internalForces.Zero(); + theVector->Zero(); + int nodeDOF = (numDOF == 9) ? 3 : 6; // loop over Gauss points for(int i = 0; i < 1; i++) { this->UpdateBase(GsPts[i][0],GsPts[i][0]); // loop over nodes - for(int j = 0; j < 3; j++) { - // loop over dof + for(int j = 0; j < SL_NUM_NODE; j++) { + // loop over displacement dof for(int k = 0; k < 3; k++) { - internalForces[j*3+k] = internalForces[j*3+k] - mLoadFactor*my_pressure*myNhat(k)*myNI(j); + (*theVector)[j*nodeDOF+k] -= mLoadFactor*my_pressure*myNhat(k)*myNI(j); } } } - return internalForces; + return *theVector; } const Vector & @@ -319,7 +347,7 @@ TriSurfaceLoad::getResistingForceIncInertia() static Vector accel(SL_NUM_DOF); accel.Zero(); - internalForces = getResistingForce(); + *theVector = getResistingForce(); int pos = 0; for (int i = 0; i < SL_NUM_NODE; ++i) @@ -327,11 +355,19 @@ TriSurfaceLoad::getResistingForceIncInertia() const Vector &a = theNodes[i]->getAccel(); accel(pos++) = a(i); } + + if (rhoH != 0.0) { + double Area = myNhat.Norm(); + double m = rhoH*Area/3; + int nodeDOF = (numDOF == 9) ? 3 : 6; + for (int i = 0; i < 3; i++) { + (*theVector)(i) -= m*accel(i); + (*theVector)(i+nodeDOF) -= m*accel(i+nodeDOF); + (*theVector)(i+2*nodeDOF) -= m*accel(i+2*nodeDOF); + } + } - mass = getMass(); - internalForces.addMatrixVector(1.0, mass, accel, -1.0); - - return internalForces; + return *theVector; } int @@ -454,17 +490,19 @@ TriSurfaceLoad::getResponse(int responseID, Information &eleInfo) // Compute a mass matrix using zangar's idea: const Matrix & TriSurfaceLoad::getMass(void) { - double Area = myNhat.Norm(); - - mass.Zero(); + theMatrix->Zero(); - if(rhoH > 0) + if(rhoH != 0) { - for (int i = 0; i < SL_NUM_DOF; ++i) - { - mass(i,i) = rhoH * Area /3; - } + double Area = myNhat.Norm(); + double m = rhoH*Area/3; + int nodeDOF = (numDOF == 9) ? 3 : 6; + for (int i = 0; i < 3; i++) { + (*theMatrix)(i,i) = m; + (*theMatrix)(i+nodeDOF,i+nodeDOF) = m; + (*theMatrix)(i+2*nodeDOF,i+2*nodeDOF) = m; + } } - return mass; + return *theMatrix; } diff --git a/SRC/element/surfaceLoad/TriSurfaceLoad.h b/SRC/element/surfaceLoad/TriSurfaceLoad.h index 097b60321a..77bb1cfad3 100644 --- a/SRC/element/surfaceLoad/TriSurfaceLoad.h +++ b/SRC/element/surfaceLoad/TriSurfaceLoad.h @@ -97,11 +97,16 @@ class TriSurfaceLoad : public Element int UpdateBase(double Xi, double Eta); ID myExternalNodes; // contains the tags of the end nodes - static Matrix tangentStiffness; // Tangent Stiffness matrix - static Matrix mass; // mass matrix - static Matrix damp; // damping matrix - static Vector internalForces; // vector of Internal Forces + static Matrix tangentStiffness9; // Tangent Stiffness matrix for 3 x 3 dofs/node + static Matrix tangentStiffness18; // Tangent Stiffness matrix for 3 x 6 dofs/node + static Vector internalForces9; // vector of Internal Forces for 3 x 3 dofs/node + static Vector internalForces18; // vector of Internal Forces for 3 x 6 dofs/node + + int numDOF; // number of element dofs (9 or 18) + Matrix *theMatrix; + Vector *theVector; + double my_pressure; // pressure applied to surface of element double rhoH; // A density per unit area to compute a mass matrix (lumped) diff --git a/SRC/interpreter/OpenSeesCommands.cpp b/SRC/interpreter/OpenSeesCommands.cpp index 0fa877a2f3..10eb2754b2 100644 --- a/SRC/interpreter/OpenSeesCommands.cpp +++ b/SRC/interpreter/OpenSeesCommands.cpp @@ -79,6 +79,8 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #include #include #include +#include +#include #include #include #include @@ -108,6 +110,11 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #endif #include +#ifdef _ITPACK +#include +#include +#endif + #ifdef _PARALLEL_INTERPRETERS bool setMPIDSOEFlag = false; @@ -316,6 +323,15 @@ OpenSeesCommands::eigen(int typeSolver, double shift, FullGenEigenSolver *theEigenSolver = new FullGenEigenSolver(); theEigenSOE = new FullGenEigenSOE(*theEigenSolver, *theAnalysisModel); + } else if (typeSolver == EigenSOE_TAGS_SymmGeneralizedEigenSOE) { + +#ifdef _WIN32 + opserr << "SymmGeneralizedEigenSolver not currently compiled for Windows" << endln; +#else + SymmGeneralizedEigenSolver *theEigenSolver = new SymmGeneralizedEigenSolver(); + theEigenSOE = new SymmGeneralizedEigenSOE(*theEigenSolver, *theAnalysisModel); +#endif + } else { theEigenSOE = new ArpackSOE(shift); @@ -861,6 +877,26 @@ OpenSeesCommands::setTransientAnalysis(bool suppress) theSOE = new ProfileSPDLinSOE(*theSolver); } + // Get the number of sub-levels and sub-steps + OPS_ResetCurrentInputArg(2); + int numSubLevels = 0; + int numSubSteps = 10; + int numData = 1; + while (OPS_GetNumRemainingInputArgs() >= 2) { + const char* opt = OPS_GetString(); + if (strcmp(opt, "-numSubLevels") == 0 || strcmp(opt, "numSubLevels") == 0) { + if (OPS_GetIntInput(&numData, &numSubLevels) < 0) { + opserr << "WARNING analysis Transient - failed to read -numSubLevels \n"; + return; + } + } else if (strcmp(opt, "-numSubSteps") == 0 || strcmp(opt, "numSubSteps") == 0) { + if (OPS_GetIntInput(&numData, &numSubSteps) < 0) { + opserr << "WARNING analysis Transient - failed to read -numSubSteps \n"; + return; + } + } + } + theTransientAnalysis = new DirectIntegrationAnalysis(*theDomain, *theHandler, *theNumberer, @@ -868,7 +904,7 @@ OpenSeesCommands::setTransientAnalysis(bool suppress) *theAlgorithm, *theSOE, *theTransientIntegrator, - theTest); + theTest, numSubLevels, numSubSteps); if (theEigenSOE != 0) { theTransientAnalysis->setEigenSOE(*theEigenSOE); } @@ -1451,6 +1487,10 @@ int OPS_System() #ifdef _MUMPS } else if (strcmp(type,"Mumps") == 0) { theSOE = (LinearSOE*)OPS_MumpsSolver(); +#endif +#ifdef _ITPACK + } else if (strcmp(type,"Itpack") == 0) { + theSOE = (LinearSOE*)OPS_ItpackLinSolver(); #endif } else { opserr<<"WARNING unknown system type "<\n"; + return -1; + } + + // tag and dof + int data[2] = {0, -1}; + int numdata = OPS_GetNumRemainingInputArgs(); + if (numdata > 2) { + numdata = 2; + } + + if (OPS_GetIntInput(&numdata, data) < 0) { + opserr<<"WARNING nodeDisp - failed to read int inputs\n"; + return -1; + } + data[1]--; + + // get Crds + Domain* theDomain = OPS_GetDomain(); + if (theDomain == 0) return -1; + Node *theNode = theDomain->getNode(data[0]); + if (theNode == 0) return -1; + + const Vector &crd = theNode->getCrds(); + + + // set outputs + int size = crd.Size(); + if (data[1] >= 0) { + if (data[1] >= size) { + opserr << "WARNING nodeDisp nodeTag? dof? - dofTag? too large\n"; + return -1; + } + + double value = crd(data[1]); + numdata = 1; + + if (OPS_SetDoubleOutput(&numdata, &value, true) < 0) { + opserr<<"WARNING nodeDisp - failed to read double inputs\n"; + return -1; + } + + + } else { + + int size = crd.Size(); + std::vector values(size); + for (int i=0; i #include #include +#include #include #include #include @@ -366,6 +367,53 @@ int OPS_ElementalLoad() return -1; } + } else if (strncmp(type,"-beamUniformMoment",80) == 0 || strncmp(type,"beamUniformMoment",80) == 0) { + double data[3] = {0.0,0.0,0.0}; + int numdata = OPS_GetNumRemainingInputArgs(); + if (ndm == 2) { + if (numdata < 1) { + opserr << "WARNING eleLoad - beamUniformMoment want mz" << endln; + return -1; + } + if (numdata > 1) numdata = 1; + if (OPS_GetDoubleInput(&numdata, &data[2]) < 0) { + opserr<<"WARNING eleLoad - invalid value for beamUniformMoment\n"; + return -1; + } + } + if (ndm == 3) { + if (numdata < 3) { + opserr << "WARNING eleLoad - beamUniformMoment want mx my mz" << endln; + return -1; + } + if (numdata > 3) numdata = 3; + if (OPS_GetDoubleInput(&numdata, data) < 0) { + opserr<<"WARNING eleLoad - invalid value for beamUniformMoment\n"; + return -1; + } + } + for (int i=0; igetTag(); + + // add the load to the domain + if (theDomain->addElementalLoad(theLoad, loadPatternTag) == false) { + opserr << "WARNING eleLoad - could not add following load to domain:\n "; + opserr << theLoad; + delete theLoad; + return -1; + } + eleLoadTag++; + } + + return 0; } else if (strcmp(type,"-beamPoint") == 0 || strcmp(type,"beamPoint") == 0 ) { diff --git a/SRC/interpreter/OpenSeesUniaxialMaterialCommands.cpp b/SRC/interpreter/OpenSeesUniaxialMaterialCommands.cpp index 89d7377a23..bb646df9b8 100644 --- a/SRC/interpreter/OpenSeesUniaxialMaterialCommands.cpp +++ b/SRC/interpreter/OpenSeesUniaxialMaterialCommands.cpp @@ -150,6 +150,7 @@ void* OPS_ECC01(); void* OPS_SelfCenteringMaterial(); void* OPS_ASD_SMA_3K(); void* OPS_ASDConcrete1DMaterial(); +void* OPS_ASDSteel1DMaterial(); void* OPS_ViscousMaterial(); void* OPS_BoucWenMaterial(); void* OPS_BoucWenOriginal(); @@ -263,6 +264,7 @@ void* OPS_TDConcreteNL(void); void* OPS_TDConcreteMC10(void); void* OPS_TDConcreteMC10NL(void); void* OPS_CreepMaterial(void); +void* OPS_CreepShrinkageACI209(void); void* OPS_CoulombDamperMaterial(); void* OPS_GMG_CyclicReinforcedConcrete(); @@ -462,6 +464,8 @@ static int setUpUniaxialMaterials(void) { std::make_pair("ASD_SMA_3K", &OPS_ASD_SMA_3K)); uniaxialMaterialsMap.insert( std::make_pair("ASDConcrete1D", &OPS_ASDConcrete1DMaterial)); + uniaxialMaterialsMap.insert( + std::make_pair("ASDSteel1D", &OPS_ASDSteel1DMaterial)); uniaxialMaterialsMap.insert( std::make_pair("Viscous", &OPS_ViscousMaterial)); uniaxialMaterialsMap.insert( @@ -622,6 +626,8 @@ static int setUpUniaxialMaterials(void) { std::make_pair("TDConcreteMC10NL", &OPS_TDConcreteMC10NL)); uniaxialMaterialsMap.insert( std::make_pair("Creep", &OPS_CreepMaterial)); + uniaxialMaterialsMap.insert( + std::make_pair("CreepShrinkageACI209", &OPS_CreepShrinkageACI209)); uniaxialMaterialsMap.insert( std::make_pair("CoulombDamper", &OPS_CoulombDamperMaterial)); uniaxialMaterialsMap.insert(std::make_pair( diff --git a/SRC/interpreter/PythonWrapper.cpp b/SRC/interpreter/PythonWrapper.cpp index 2cbabba270..c81b944983 100644 --- a/SRC/interpreter/PythonWrapper.cpp +++ b/SRC/interpreter/PythonWrapper.cpp @@ -1132,6 +1132,18 @@ static PyObject *Py_ops_nodeDisp(PyObject *self, PyObject *args) return wrapper->getResults(); } +static PyObject *Py_ops_nodeCrd(PyObject *self, PyObject *args) +{ + wrapper->resetCommandLine(PyTuple_Size(args), 1, args); + + if (OPS_nodeCoord() < 0) { + opserr<<(void*)0; + return NULL; + } + + return wrapper->getResults(); +} + static PyObject *Py_ops_nodeVel(PyObject *self, PyObject *args) { wrapper->resetCommandLine(PyTuple_Size(args), 1, args); diff --git a/SRC/material/nD/ElasticIsotropicMaterial.h b/SRC/material/nD/ElasticIsotropicMaterial.h index 2bdea004f8..30dd14e757 100644 --- a/SRC/material/nD/ElasticIsotropicMaterial.h +++ b/SRC/material/nD/ElasticIsotropicMaterial.h @@ -60,6 +60,8 @@ class ElasticIsotropicMaterial : public NDMaterial virtual const char *getClassType(void) const {return "ElasticIsotropicMaterial";}; virtual double getRho( ) ; + virtual double getElasticModulus( ) { return E; } + virtual double getPoissonsRatio( ) { return v; } virtual int setTrialStrain (const Vector &v); virtual int setTrialStrain (const Vector &v, const Vector &r); diff --git a/SRC/material/nD/Parallel3DMaterial.cpp b/SRC/material/nD/Parallel3DMaterial.cpp index 7a694525c8..2ca47d3bca 100644 --- a/SRC/material/nD/Parallel3DMaterial.cpp +++ b/SRC/material/nD/Parallel3DMaterial.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -227,6 +228,7 @@ Parallel3DMaterial::Parallel3DMaterial( m_materials[i] = the_copy; } computeInitialTangent(); + computeTangent(); } Parallel3DMaterial::Parallel3DMaterial() @@ -257,7 +259,7 @@ int Parallel3DMaterial::setTrialStrain(const Vector& v) m_strain = v; int result = 0; for (std::size_t i = 0; i < m_materials.size(); ++i) { - if (!m_materials[i]->setTrialStrain(v)) + if (m_materials[i]->setTrialStrain(v) != 0) result = -1; } computeStress(); @@ -270,7 +272,7 @@ int Parallel3DMaterial::setTrialStrain(const Vector& v, const Vector& r) m_strain = v; int result = 0; for (std::size_t i = 0; i < m_materials.size(); ++i) { - if (!m_materials[i]->setTrialStrain(v, r)) + if (m_materials[i]->setTrialStrain(v, r) != 0) result = -1; } computeStress(); @@ -513,6 +515,18 @@ int Parallel3DMaterial::recvSelf(int commitTag, Channel & theChannel, FEM_Object int Parallel3DMaterial::setParameter(const char** argv, int argc, Parameter& param) { + // handle parameters + if (argc > 0) { + if (strcmp(argv[0], "parallelWeight") == 0 || strcmp(argv[0], "ParallelWeight") == 0) { + if (argc == 2) { + int imat = atoi(argv[1]) - 1; + if (imat >= 0 && imat < static_cast(m_weights.size())) { + param.setValue(m_weights[static_cast(imat)]); + return param.addObject(1000 + imat, this); + } + } + } + } // forward to the sub-materials int res = -1; for (NDMaterial* item : m_materials) { @@ -522,6 +536,19 @@ int Parallel3DMaterial::setParameter(const char** argv, int argc, Parameter& par return res; } +int Parallel3DMaterial::updateParameter(int parameterID, Information& info) +{ + if (parameterID >= 1000) { + int imat = parameterID - 1000; + if (imat >= 0 && imat < static_cast(m_weights.size())) { + m_weights[static_cast(imat)] = info.theDouble; + computeInitialTangent(); + return 0; + } + } + return -1; +} + Response* Parallel3DMaterial::setResponse(const char** argv, int argc, OPS_Stream& output) { if (argc > 0) { diff --git a/SRC/material/nD/Parallel3DMaterial.h b/SRC/material/nD/Parallel3DMaterial.h index af137a1a86..34ec282807 100644 --- a/SRC/material/nD/Parallel3DMaterial.h +++ b/SRC/material/nD/Parallel3DMaterial.h @@ -83,6 +83,7 @@ class Parallel3DMaterial : public NDMaterial // parameters and responses int setParameter(const char** argv, int argc, Parameter& param); + int updateParameter(int parameterID, Information& info); Response* setResponse(const char** argv, int argc, OPS_Stream& output); int getResponse(int responseID, Information& matInformation); diff --git a/SRC/material/nD/PlaneStressLayeredMaterial.cpp b/SRC/material/nD/PlaneStressLayeredMaterial.cpp index 5da7d56e8a..235352291c 100644 --- a/SRC/material/nD/PlaneStressLayeredMaterial.cpp +++ b/SRC/material/nD/PlaneStressLayeredMaterial.cpp @@ -440,7 +440,18 @@ PlaneStressLayeredMaterial::recvSelf(int commitTag, Channel &theChannel, FEM_Obj -Response* +int PlaneStressLayeredMaterial::setParameter(const char** argv, int argc, Parameter& param) +{ + // forward to the sub-materials + int res = -1; + for (int i = 0; i < nLayers; ++i) { + if (theFibers[i]->setParameter(argv, argc, param) == 0) + res = 0; + } + return res; +} + +Response* PlaneStressLayeredMaterial::setResponse (const char **argv, int argc, OPS_Stream &output) { diff --git a/SRC/material/nD/PlaneStressLayeredMaterial.h b/SRC/material/nD/PlaneStressLayeredMaterial.h index b9b2e08fc6..5442030edd 100644 --- a/SRC/material/nD/PlaneStressLayeredMaterial.h +++ b/SRC/material/nD/PlaneStressLayeredMaterial.h @@ -71,7 +71,7 @@ class PlaneStressLayeredMaterial : public NDMaterial { int recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker); - + int setParameter(const char** argv, int argc, Parameter& param); Response *setResponse (const char **argv, int argc, OPS_Stream &s); int getResponse (int responseID, Information &matInformation); diff --git a/SRC/material/nD/PlaneStressRebarMaterial.cpp b/SRC/material/nD/PlaneStressRebarMaterial.cpp index e81e364145..1cbfa9a0e5 100644 --- a/SRC/material/nD/PlaneStressRebarMaterial.cpp +++ b/SRC/material/nD/PlaneStressRebarMaterial.cpp @@ -381,5 +381,10 @@ PlaneStressRebarMaterial::recvSelf(int commitTag, Channel &theChannel, FEM_Objec opserr << "PlaneStressRebarMaterial::recvSelf() - failed to receive material1" << endln; return res; +} + +int PlaneStressRebarMaterial::setParameter(const char** argv, int argc, Parameter& param) +{ + return theMat->setParameter(argv, argc, param); } diff --git a/SRC/material/nD/PlaneStressRebarMaterial.h b/SRC/material/nD/PlaneStressRebarMaterial.h index 5c689568eb..bd51881486 100644 --- a/SRC/material/nD/PlaneStressRebarMaterial.h +++ b/SRC/material/nD/PlaneStressRebarMaterial.h @@ -66,6 +66,8 @@ class PlaneStressRebarMaterial: public NDMaterial{ int sendSelf(int commitTag, Channel &theChannel); int recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker); + int setParameter(const char** argv, int argc, Parameter& param); + private : UniaxialMaterial *theMat ; double angle, c, s; diff --git a/SRC/material/nD/PlateFiberMaterialThermal.cpp b/SRC/material/nD/PlateFiberMaterialThermal.cpp index ce12e5a1f3..57b255dd79 100644 --- a/SRC/material/nD/PlateFiberMaterialThermal.cpp +++ b/SRC/material/nD/PlateFiberMaterialThermal.cpp @@ -578,6 +578,11 @@ PlateFiberMaterialThermal::recvSelf(int commitTag, Channel &theChannel, FEM_Obje opserr << "PlateFiberMaterialThermal::sendSelf() - failed to send vector material\n"; return res; +} + +int PlateFiberMaterialThermal::setParameter(const char** argv, int argc, Parameter& param) +{ + return theMaterial->setParameter(argv, argc, param); } diff --git a/SRC/material/nD/PlateFiberMaterialThermal.h b/SRC/material/nD/PlateFiberMaterialThermal.h index a9a3423e91..a56c3cecd5 100644 --- a/SRC/material/nD/PlateFiberMaterialThermal.h +++ b/SRC/material/nD/PlateFiberMaterialThermal.h @@ -100,6 +100,7 @@ class PlateFiberMaterialThermal: public NDMaterial{ int sendSelf(int commitTag, Channel &theChannel); int recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker); + int setParameter(const char** argv, int argc, Parameter& param); private : diff --git a/SRC/material/nD/PlateFromPlaneStressMaterial.cpp b/SRC/material/nD/PlateFromPlaneStressMaterial.cpp index 89cd2b82d2..35dff87b09 100644 --- a/SRC/material/nD/PlateFromPlaneStressMaterial.cpp +++ b/SRC/material/nD/PlateFromPlaneStressMaterial.cpp @@ -404,5 +404,11 @@ PlateFromPlaneStressMaterial::setResponse(const char** argv, int argc, OPS_Strea return NDMaterial::setResponse(argv, argc, output); // not implemented, get default (zero) response from NDMaterial return theResponse; // implemented, get damage response from theMat -} +} + //setResponse - added by V.K. Papanikolaou [AUTh] - end + +int PlateFromPlaneStressMaterial::setParameter(const char** argv, int argc, Parameter& param) +{ + return theMat->setParameter(argv, argc, param); +} diff --git a/SRC/material/nD/PlateFromPlaneStressMaterial.h b/SRC/material/nD/PlateFromPlaneStressMaterial.h index 4e562cc2d8..b6420f8a40 100644 --- a/SRC/material/nD/PlateFromPlaneStressMaterial.h +++ b/SRC/material/nD/PlateFromPlaneStressMaterial.h @@ -96,6 +96,8 @@ class PlateFromPlaneStressMaterial: public NDMaterial{ Response* setResponse(const char** argv, int argc, OPS_Stream& s); //setResponse - added by V.K. Papanikolaou [AUTh] - end + int setParameter(const char** argv, int argc, Parameter& param); + private : NDMaterial *theMat ; //pointer to three dimensional material double gmod; diff --git a/SRC/material/nD/PlateFromPlaneStressMaterialThermal.cpp b/SRC/material/nD/PlateFromPlaneStressMaterialThermal.cpp index 40d920b055..79a7123bfc 100644 --- a/SRC/material/nD/PlateFromPlaneStressMaterialThermal.cpp +++ b/SRC/material/nD/PlateFromPlaneStressMaterialThermal.cpp @@ -373,6 +373,11 @@ PlateFromPlaneStressMaterialThermal::recvSelf(int commitTag, Channel &theChannel opserr << "PlateFromPlaneStressMaterialThermal::sendSelf() - failed to receive material1" << endln; return res; +} + +int PlateFromPlaneStressMaterialThermal::setParameter(const char** argv, int argc, Parameter& param) +{ + return theMat->setParameter(argv, argc, param); } diff --git a/SRC/material/nD/PlateFromPlaneStressMaterialThermal.h b/SRC/material/nD/PlateFromPlaneStressMaterialThermal.h index 25abaddda7..6c9db5990d 100644 --- a/SRC/material/nD/PlateFromPlaneStressMaterialThermal.h +++ b/SRC/material/nD/PlateFromPlaneStressMaterialThermal.h @@ -97,6 +97,8 @@ class PlateFromPlaneStressMaterialThermal: public NDMaterial{ int sendSelf(int commitTag, Channel &theChannel); int recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker); + int setParameter(const char** argv, int argc, Parameter& param); + private : NDMaterial *theMat ; //pointer to three dimensional material double gmod; diff --git a/SRC/material/nD/PlateRebarMaterial.cpp b/SRC/material/nD/PlateRebarMaterial.cpp index fb4aacf539..a432dfa349 100644 --- a/SRC/material/nD/PlateRebarMaterial.cpp +++ b/SRC/material/nD/PlateRebarMaterial.cpp @@ -396,5 +396,10 @@ PlateRebarMaterial::recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroke opserr << "PlateRebarMaterial::sendSelf() - failed to receive material1" << endln; return res; +} + +int PlateRebarMaterial::setParameter(const char** argv, int argc, Parameter& param) +{ + return theMat->setParameter(argv, argc, param); } diff --git a/SRC/material/nD/PlateRebarMaterial.h b/SRC/material/nD/PlateRebarMaterial.h index fee3c67ca5..d1166ddcda 100644 --- a/SRC/material/nD/PlateRebarMaterial.h +++ b/SRC/material/nD/PlateRebarMaterial.h @@ -93,6 +93,8 @@ class PlateRebarMaterial: public NDMaterial{ int sendSelf(int commitTag, Channel &theChannel); int recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker); + int setParameter(const char** argv, int argc, Parameter& param); + private : UniaxialMaterial *theMat ; double angle, c, s; diff --git a/SRC/material/nD/PlateRebarMaterialThermal.cpp b/SRC/material/nD/PlateRebarMaterialThermal.cpp index 33939a752e..ced8f7e3c5 100644 --- a/SRC/material/nD/PlateRebarMaterialThermal.cpp +++ b/SRC/material/nD/PlateRebarMaterialThermal.cpp @@ -390,6 +390,11 @@ PlateRebarMaterialThermal::recvSelf(int commitTag, Channel &theChannel, FEM_Obje opserr << "PlateRebarMaterialThermal::sendSelf() - failed to receive material1" << endln; return res; +} + +int PlateRebarMaterialThermal::setParameter(const char** argv, int argc, Parameter& param) +{ + return theMat->setParameter(argv, argc, param); } diff --git a/SRC/material/nD/PlateRebarMaterialThermal.h b/SRC/material/nD/PlateRebarMaterialThermal.h index 746a471a7c..4eb0b7ee84 100644 --- a/SRC/material/nD/PlateRebarMaterialThermal.h +++ b/SRC/material/nD/PlateRebarMaterialThermal.h @@ -100,6 +100,8 @@ class PlateRebarMaterialThermal: public NDMaterial{ int sendSelf(int commitTag, Channel &theChannel); int recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker); + int setParameter(const char** argv, int argc, Parameter& param); + private : UniaxialMaterial *theMat ; double angle, c, s; diff --git a/SRC/material/nD/TclModelBuilderNDMaterialCommand.cpp b/SRC/material/nD/TclModelBuilderNDMaterialCommand.cpp index f7e2fc78e0..074185865f 100644 --- a/SRC/material/nD/TclModelBuilderNDMaterialCommand.cpp +++ b/SRC/material/nD/TclModelBuilderNDMaterialCommand.cpp @@ -20,6 +20,7 @@ ** Boris Jeremic (jeremic@ucdavis.edu) ** ** Zaohui Yang (zhyang@ucdavis.edu) ** ** Zhao Cheng (zcheng@ucdavis.edu) ** +** Pedro Arduino (parduino@uw.edu) ** ** ** ** ** ** ** @@ -83,6 +84,7 @@ extern void *OPS_ManzariDafaliasMaterial(void); extern void *OPS_ManzariDafaliasMaterialRO(void); extern void *OPS_PM4SandMaterial(void); extern void *OPS_PM4SiltMaterial(void); +extern void *OPS_LinearElasticGGmaxMaterial(void); extern void *OPS_J2CyclicBoundingSurfaceMaterial(void); extern void *OPS_CycLiqCPMaterial(void); extern void *OPS_CycLiqCPSPMaterial(void); @@ -494,23 +496,33 @@ TclModelBuilderNDMaterialCommand (ClientData clientData, Tcl_Interp *interp, int return TCL_ERROR; } - else if ((strcmp(argv[1], "J2CyclicBoundingSurface") == 0)) { + else if ((strcmp(argv[1], "J2CyclicBoundingSurface") == 0)) { - void *theMat = OPS_J2CyclicBoundingSurfaceMaterial(); - if (theMat != 0) - theMaterial = (NDMaterial *)theMat; - else - return TCL_ERROR; - } + void *theMat = OPS_J2CyclicBoundingSurfaceMaterial(); + if (theMat != 0) + theMaterial = (NDMaterial *)theMat; + else + return TCL_ERROR; + } - else if ((strcmp(argv[1], "PM4Silt") == 0)) { + else if ((strcmp(argv[1], "PM4Silt") == 0)) { + + void *theMat = OPS_PM4SiltMaterial(); + if (theMat != 0) + theMaterial = (NDMaterial *)theMat; + else + return TCL_ERROR; + } + + else if ((strcmp(argv[1], "LinearElasticGGmax") == 0)) { + + void *theMat = OPS_LinearElasticGGmaxMaterial(); + if (theMat != 0) + theMaterial = (NDMaterial *)theMat; + else + return TCL_ERROR; + } - void *theMat = OPS_PM4SiltMaterial(); - if (theMat != 0) - theMaterial = (NDMaterial *)theMat; - else - return TCL_ERROR; - } else if ((strcmp(argv[1],"ContactMaterial2D") == 0)){ diff --git a/SRC/material/nD/UWmaterials/CMakeLists.txt b/SRC/material/nD/UWmaterials/CMakeLists.txt index 00458f1a75..7ce5b26d4c 100644 --- a/SRC/material/nD/UWmaterials/CMakeLists.txt +++ b/SRC/material/nD/UWmaterials/CMakeLists.txt @@ -26,6 +26,7 @@ target_sources(OPS_Material ManzariDafaliasRO.cpp PM4Sand.cpp PM4Silt.cpp + LinearElasticGGmax.cpp PUBLIC BoundingCamClay.h BoundingCamClay3D.h @@ -47,6 +48,7 @@ target_sources(OPS_Material ManzariDafaliasRO.h PM4Sand.h PM4Silt.h + LinearElasticGGmax.h ) target_include_directories(OPS_Material PUBLIC ${CMAKE_CURRENT_LIST_DIR}) diff --git a/SRC/material/nD/UWmaterials/LinearElasticGGmax.cpp b/SRC/material/nD/UWmaterials/LinearElasticGGmax.cpp new file mode 100644 index 0000000000..f66ea5388a --- /dev/null +++ b/SRC/material/nD/UWmaterials/LinearElasticGGmax.cpp @@ -0,0 +1,472 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** LinearElasticGGmax: linear elastic nD with G/Gmax degradation ** +** ****************************************************************** */ + +#include "LinearElasticGGmax.h" +#include +#include +#include +#include +#include +#include +#include + +Vector LinearElasticGGmax::sigma(6); +Matrix LinearElasticGGmax::D(6,6); + +/* ----------------------- OPS Factory Function ---------------------- */ +void* OPS_LinearElasticGGmaxMaterial() +{ + int numdata = OPS_GetNumRemainingInputArgs(); + if (numdata < 5) { + opserr << "nDMaterial LinearElasticGGmax tag G K|nu rho curveType \n"; + return 0; + } + + int tag; int num = 1; + if (OPS_GetIntInput(&num, &tag) < 0) { + opserr << "LinearElasticGGmax: invalid tag\n"; + return 0; + } + + double props[3]; num = 3; + if (OPS_GetDoubleInput(&num, props) < 0) { + opserr << "LinearElasticGGmax: need G, K|nu, rho\n"; + return 0; + } + double G = props[0]; + double K_or_nu = props[1]; + double rho = props[2]; + + int curveType; num = 1; + if (OPS_GetIntInput(&num, &curveType) < 0) { + opserr << "LinearElasticGGmax: invalid curveType\n"; + return 0; + } + + if (curveType == 0) { + int npts; num = 1; + if (OPS_GetIntInput(&num, &npts) < 0 || npts < 2) { + opserr << "LinearElasticGGmax: user curve needs numPoints >= 2\n"; + return 0; + } + std::vector strains(npts), gg(npts); + num = npts; + if (OPS_GetDoubleInput(&num, strains.data()) < 0) { + opserr << "LinearElasticGGmax: bad strain list\n"; + return 0; + } + num = npts; + if (OPS_GetDoubleInput(&num, gg.data()) < 0) { + opserr << "LinearElasticGGmax: bad G/Gmax list\n"; + return 0; + } + return new LinearElasticGGmax(tag, G, K_or_nu, rho, strains, gg); + } else { + double params[3] = {0.,0.,0.}; + int rem = OPS_GetNumRemainingInputArgs(); + if (rem > 0) { + if (rem > 3) rem = 3; + num = rem; + if (OPS_GetDoubleInput(&num, params) < 0) { + opserr << "LinearElasticGGmax: invalid curve params\n"; + return 0; + } + } + return new LinearElasticGGmax(tag, G, K_or_nu, rho, curveType, params[0], params[1], params[2]); + } +} + +/* --------------------------- Constructors -------------------------- */ +LinearElasticGGmax::LinearElasticGGmax(int tag, double G_in, double K_or_nu_in, double r, + int cType, double p1, double p2, double p3) +: NDMaterial(tag, ND_TAG_LinearElasticGGmax), + G0(G_in), K0(0.0), nu(0.0), hasK(false), rho0(r), + mu_c(0.0), lambda_c(0.0), + curveType(cType), param1(p1), param2(p2), param3(p3), + epsilon(6), Cepsilon(6), nDim(3) +{ + // detect whether second is nu or K + if (K_or_nu_in > -0.999 && K_or_nu_in < 0.5) { nu = K_or_nu_in; hasK = false; } + else { K0 = K_or_nu_in; hasK = true; } + + epsilon.Zero(); Cepsilon.Zero(); + sigma.Zero(); D.Zero(); +} + +LinearElasticGGmax::LinearElasticGGmax(int tag, double G_in, double K_or_nu_in, double r, + const std::vector& strains, + const std::vector& ggmax) +: NDMaterial(tag, ND_TAG_LinearElasticGGmax), + G0(G_in), K0(0.0), nu(0.0), hasK(false), rho0(r), + mu_c(0.0), lambda_c(0.0), + curveType(0), param1(0.0), param2(0.0), param3(0.0), + userStrains(strains), userGGmax(ggmax), + epsilon(6), Cepsilon(6), nDim(3) +{ + if (K_or_nu_in > -0.999 && K_or_nu_in < 0.5) { nu = K_or_nu_in; hasK = false; } + else { K0 = K_or_nu_in; hasK = true; } + + epsilon.Zero(); Cepsilon.Zero(); + sigma.Zero(); D.Zero(); +} + +LinearElasticGGmax::LinearElasticGGmax() +: NDMaterial(0, ND_TAG_LinearElasticGGmax), + G0(0.0), K0(0.0), nu(0.0), hasK(true), rho0(0.0), + mu_c(0.0), lambda_c(0.0), + curveType(1), param1(0.0), param2(0.0), param3(0.0), + epsilon(6), Cepsilon(6), nDim(3) +{ + epsilon.Zero(); Cepsilon.Zero(); + sigma.Zero(); D.Zero(); +} + +LinearElasticGGmax::~LinearElasticGGmax() {} + +/* ------------------------ NDMaterial methods ----------------------- */ + +int LinearElasticGGmax::setTrialStrain(const Vector &strn) +{ + if (epsilon.Size() != strn.Size()) { + // detect dimensionality (3 for 2D plane strain/plane stress vectors) + if (strn.Size() == 3) { nDim = 2; epsilon.resize(3); Cepsilon.resize(3); } + else { nDim = 3; epsilon.resize(6); Cepsilon.resize(6); } + } + epsilon = strn; + + // compute G/Gmax from equivalent shear strain (uses normals too) + const double gamma_eq = computeShearStrain(epsilon); + const double gg = computeGGmax(gamma_eq); + computeTangent(gg); // sets mu_c, lambda_c and updates D + + // FAST path: sigma = 2*mu*eps + lambda*tr(eps)*I in Voigt form + if (nDim == 3) { + const double exx = epsilon(0), eyy = epsilon(1), ezz = epsilon(2); + const double gxy = epsilon(3), gyz = epsilon(4), gxz = epsilon(5); + const double tr = exx + eyy + ezz; + + sigma(0) = lambda_c*tr + 2.0*mu_c*exx; + sigma(1) = lambda_c*tr + 2.0*mu_c*eyy; + sigma(2) = lambda_c*tr + 2.0*mu_c*ezz; + sigma(3) = mu_c * gxy; // engineering shear + sigma(4) = mu_c * gyz; + sigma(5) = mu_c * gxz; + } else { + // plane strain: epsilon = [exx, eyy, gxy], with ezz = 0.0 + const double exx = epsilon(0), eyy = epsilon(1), gxy = epsilon(2); + const double tr = exx + eyy; + + sigma(0) = lambda_c*tr + 2.0*mu_c*exx; + sigma(1) = lambda_c*tr + 2.0*mu_c*eyy; + sigma(2) = mu_c * gxy; // tau_xy + } + + return 0; +} + +int LinearElasticGGmax::setTrialStrain(const Vector &strain, const Vector &rate) +{ return setTrialStrain(strain); } + +int LinearElasticGGmax::setTrialStrainIncr(const Vector &strain) +{ + Vector trial = Cepsilon; + trial.addVector(1.0, strain, 1.0); + return setTrialStrain(trial); +} + +int LinearElasticGGmax::setTrialStrainIncr(const Vector &strain, const Vector &rate) +{ return setTrialStrainIncr(strain); } + +const Vector &LinearElasticGGmax::getStrain(void) { return epsilon; } +const Vector &LinearElasticGGmax::getStress(void) { return sigma; } +const Matrix &LinearElasticGGmax::getTangent(void) { return D; } +const Matrix &LinearElasticGGmax::getInitialTangent(void) +{ + // initial tangent: use ggmax=1 + computeTangent(1.0); + return D; +} + +int LinearElasticGGmax::commitState(void) +{ + Cepsilon = epsilon; + return 0; +} + +int LinearElasticGGmax::revertToLastCommit(void) +{ + // Restore trial strain to last committed state + epsilon = Cepsilon; + + // Recompute tangent and stress consistent with restored strain + const double gamma_eq = computeShearStrain(epsilon); + const double gg = computeGGmax(gamma_eq); + computeTangent(gg); + + if (nDim == 3) { + const double exx = epsilon(0), eyy = epsilon(1), ezz = epsilon(2); + const double gxy = epsilon(3), gyz = epsilon(4), gxz = epsilon(5); + const double tr = exx + eyy + ezz; + + sigma(0) = lambda_c*tr + 2.0*mu_c*exx; + sigma(1) = lambda_c*tr + 2.0*mu_c*eyy; + sigma(2) = lambda_c*tr + 2.0*mu_c*ezz; + sigma(3) = mu_c * gxy; + sigma(4) = mu_c * gyz; + sigma(5) = mu_c * gxz; + } else { + const double exx = epsilon(0), eyy = epsilon(1), gxy = epsilon(2); + const double tr = exx + eyy; + + sigma(0) = lambda_c*tr + 2.0*mu_c*exx; + sigma(1) = lambda_c*tr + 2.0*mu_c*eyy; + sigma(2) = mu_c * gxy; + } + + return 0; +} + +int LinearElasticGGmax::revertToStart(void) +{ + epsilon.Zero(); Cepsilon.Zero(); sigma.Zero(); + computeTangent(1.0); + return 0; +} + +NDMaterial* LinearElasticGGmax::getCopy(void) +{ + double second = hasK ? K0 : nu; + LinearElasticGGmax *theCopy; + if (curveType == 0) { + theCopy = new LinearElasticGGmax(this->getTag(), G0, second, rho0, userStrains, userGGmax); + } else { + theCopy = new LinearElasticGGmax(this->getTag(), G0, second, rho0, curveType, param1, param2, param3); + } + theCopy->hasK = hasK; + theCopy->epsilon = epsilon; + theCopy->Cepsilon = Cepsilon; + theCopy->nDim = nDim; + return theCopy; +} + +NDMaterial* LinearElasticGGmax::getCopy(const char *type) +{ + return getCopy(); +} + +const char *LinearElasticGGmax::getType(void) const +{ + return (nDim==2) ? "PlaneStrain" : "ThreeDimensional"; +} + +int LinearElasticGGmax::getOrder(void) const +{ + return (nDim==2) ? 3 : 6; +} + +/* ------------------------- Channel I/O ------------------------------ */ + +int LinearElasticGGmax::sendSelf(int commitTag, Channel &theChannel) +{ + static Vector data(12); + data(0) = this->getTag(); + data(1) = G0; + data(2) = hasK ? K0 : nu; + data(3) = rho0; + data(4) = curveType; + data(5) = param1; + data(6) = param2; + data(7) = param3; + data(8) = nDim; + data(9) = (double)userStrains.size(); + data(10)= hasK ? 1.0 : 0.0; + data(11)= 0.0; + + int res = theChannel.sendVector(this->getDbTag(), commitTag, data); + if (res < 0) return res; + + if (curveType == 0 && !userStrains.empty()) { + Vector s(userStrains.size()), g(userGGmax.size()); + for (size_t i=0;igetDbTag(), commitTag, s)) < 0) return res; + if ((res = theChannel.sendVector(this->getDbTag(), commitTag, g)) < 0) return res; + } + return 0; +} + +int LinearElasticGGmax::recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker) +{ + static Vector data(12); + int res = theChannel.recvVector(this->getDbTag(), commitTag, data); + if (res < 0) return res; + + this->setTag((int)data(0)); + G0 = data(1); + double second = data(2); + rho0 = data(3); + curveType = (int)data(4); + param1 = data(5); param2 = data(6); param3 = data(7); + nDim = (int)data(8); + int nPts = (int)data(9); + hasK = (data(10) > 0.5); + + if (hasK) { K0 = second; nu = 0.0; } + else { nu = second; K0 = 0.0; } + + if (curveType == 0 && nPts > 0) { + Vector s(nPts), g(nPts); + if ((res = theChannel.recvVector(this->getDbTag(), commitTag, s)) < 0) return res; + if ((res = theChannel.recvVector(this->getDbTag(), commitTag, g)) < 0) return res; + userStrains.resize(nPts); userGGmax.resize(nPts); + for (int i=0;igetTag() << endln; + s << " G0: " << G0 << endln; + if (hasK) s << " K0: " << K0 << endln; + else s << " nu: " << nu << endln; + s << " rho: " << rho0 << endln; + s << " curveType: " << curveType << endln; +} + +/* ------------------------ Private helpers -------------------------- */ + +double LinearElasticGGmax::computeShearStrain(const Vector& strain) const +{ + double gamma = 0.0; + + if (nDim == 3) { + // Voigt: [eps11, eps22, eps33, g12, g23, g31] with engineering shear + double eps11 = strain(0); + double eps22 = strain(1); + double eps33 = strain(2); + double eps12 = strain(3) * 0.5; // eng -> tensorial + double eps23 = strain(4) * 0.5; + double eps31 = strain(5) * 0.5; + + double epsm = (eps11 + eps22 + eps33) / 3.0; + double e11 = eps11 - epsm; + double e22 = eps22 - epsm; + double e33 = eps33 - epsm; + + double J2 = 0.5 * (e11*e11 + e22*e22 + e33*e33) + + (eps12*eps12 + eps23*eps23 + eps31*eps31); + + gamma = std::sqrt(2.0 * J2); + } else { + // 2D (plane strain/stress vector: [eps11, eps22, g12]) + double eps11 = strain(0); + double eps22 = strain(1); + double eps12 = strain(2) * 0.5; // eng -> tensorial + + // For pure 2D we use mean over in-plane normals + double epsm = (eps11 + eps22) / 2.0; + double e11 = eps11 - epsm; + double e22 = eps22 - epsm; + + double J2 = 0.5 * (e11*e11 + e22*e22) + eps12*eps12; + gamma = std::sqrt(2.0 * J2); + } + + return std::fabs(gamma); +} + +double LinearElasticGGmax::computeGGmax(double gamma) +{ + gamma = std::abs(gamma); + if (curveType == 0) return interpolateUserCurve(gamma); + if (curveType == 1) return hardinDrnevich(gamma); + if (curveType == 2) return vuceticDobry(gamma); + if (curveType == 3) return darendeli(gamma); + return 1.0; +} + +void LinearElasticGGmax::computeTangent(double gg) +{ + // Degraded shear modulus + double mu = std::max(0.0, G0 * gg); + double lambda; + if (hasK) { + double K = K0; // keep bulk modulus constant + lambda = K - (2.0/3.0)*mu; + } else { + lambda = (2.0*mu*nu) / (1.0 - 2.0*nu); + } + + // Cache values for fast stress computation + mu_c = mu; + lambda_c = lambda; + + // Fill D for getTangent/getInitialTangent + if (nDim == 3) { + D.Zero(); + double mup2 = lambda + 2.0*mu; + D(0,0)=D(1,1)=D(2,2)=mup2; + D(0,1)=D(1,0)=lambda; + D(0,2)=D(2,0)=lambda; + D(1,2)=D(2,1)=lambda; + D(3,3)=mu; D(4,4)=mu; D(5,5)=mu; + } else { + // plane strain: 3x3 [exx, eyy, gxy] + D.Zero(); + double mup2 = lambda + 2.0*mu; + D(0,0)=D(1,1)=mup2; + D(0,1)=D(1,0)=lambda; + D(2,2)=mu; + } +} + +/* -------------------------- Curve models --------------------------- */ + +double LinearElasticGGmax::hardinDrnevich(double gamma) const +{ + // gamma_ref in param1 + double gref = (param1>0.0? param1 : 1e-4); + return 1.0 / (1.0 + gamma / gref); +} + +double LinearElasticGGmax::vuceticDobry(double gamma) const +{ + // Simplified: PI in param1 -> adjust reference strain + double PI = std::max(0.0, param1); + double gref = 1e-4 * std::pow(10.0, -0.014*PI); // crude trend + return 1.0 / (1.0 + gamma / gref); +} + +double LinearElasticGGmax::darendeli(double gamma) const +{ + // Very simplified surrogate based on param1=PI, param2=p', param3=OCR + double PI = std::max(0.0, param1); + double p = (param2>0.0? param2:100.0); + double OCR = (param3>0.0? param3:1.0); + double gref = 1e-4 * std::pow(p/100.0, 0.3) * std::pow(OCR, 0.1) * std::pow(10.0, -0.01*PI); + return 1.0 / (1.0 + gamma / gref); +} + +double LinearElasticGGmax::interpolateUserCurve(double gamma) const +{ + if (userStrains.empty() || userGGmax.empty()) return 1.0; + // assume userStrains strictly increasing (positive gammas) + size_t n = userStrains.size(); + if (gamma <= userStrains.front()) return userGGmax.front(); + if (gamma >= userStrains.back()) return userGGmax.back(); + + // log-log linear interpolation + double lg = std::log10(gamma); + size_t i=1; + while (i userStrains[i]) ++i; + // interpolate between i-1 and i + double x1=std::log10(userStrains[i-1]), x2=std::log10(userStrains[i]); + double y1=std::log10(std::max(1e-12, userGGmax[i-1])), y2=std::log10(std::max(1e-12, userGGmax[i])); + double y = y1 + (y2-y1)*( (lg-x1)/(x2-x1) ); + return std::pow(10.0, y); +} diff --git a/SRC/material/nD/UWmaterials/LinearElasticGGmax.h b/SRC/material/nD/UWmaterials/LinearElasticGGmax.h new file mode 100644 index 0000000000..22c18b0dbc --- /dev/null +++ b/SRC/material/nD/UWmaterials/LinearElasticGGmax.h @@ -0,0 +1,95 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** LinearElasticGGmax: linear elastic nD material with G/Gmax curves ** +** Accepts (G,K) or (G,nu) and degrades only G by G/Gmax(gamma) ** +** ** +** ****************************************************************** */ +#ifndef LinearElasticGGmax_h +#define LinearElasticGGmax_h + +#include +#include +#include +#include + +class LinearElasticGGmax : public NDMaterial +{ +public: + // Factory hook (no friend declaration needed) + + // Predefined curves: curveType in {1=Hardin-Drnevich, 2=Vucetic-Dobry, 3=Darendeli} + LinearElasticGGmax(int tag, double G_in, double K_or_nu, double rho, + int curveType, double p1 = 0.0, double p2 = 0.0, double p3 = 0.0); + + // User curve (curveType==0) + LinearElasticGGmax(int tag, double G_in, double K_or_nu, double rho, + const std::vector& strains, const std::vector& ggmax); + + LinearElasticGGmax(); + ~LinearElasticGGmax(); + + const char *getClassType(void) const override { return "LinearElasticGGmax"; }; + + // Mandatory NDMaterial interface + int setTrialStrain(const Vector &strain) override; + int setTrialStrain(const Vector &strain, const Vector &rate) override; + int setTrialStrainIncr(const Vector &strain) override; + int setTrialStrainIncr(const Vector &strain, const Vector &rate) override; + + const Vector &getStrain(void) override; + const Vector &getStress(void) override; + const Matrix &getTangent(void) override; + const Matrix &getInitialTangent(void) override; + + int commitState(void) override; + int revertToLastCommit(void) override; + int revertToStart(void) override; + NDMaterial *getCopy(void) override; + NDMaterial *getCopy(const char *type) override; + + const char *getType(void) const override; + int getOrder(void) const override; + + int sendSelf(int commitTag, Channel &theChannel) override; + int recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker) override; + + void Print(OPS_Stream &s, int flag = 0) override; + +private: + // Material properties + double G0; // initial shear modulus + double K0; // bulk modulus (valid if hasK==true) + double nu; // Poisson's ratio (valid if hasK==false) + bool hasK; // true if user gave K; false if user gave nu + double rho0; // density (not used in constitutive law here) + double mu_c; // cached shear modulus for current trial state + double lambda_c; // cached first Lamé parameter for current trial state + + // G/Gmax curve definition + int curveType; // 0=user, 1=Hardin-Drnevich, 2=Vucetic-Dobry, 3=Darendeli + double param1, param2, param3; // model params (gamma_ref, PI, p', OCR, etc.) + std::vector userStrains; // engineering gamma values (>0) + std::vector userGGmax; // ratio values in [0,1] + + // State + Vector epsilon; // trial strain (6 for 3D Voigt, 3 for 2D) + Vector Cepsilon; // committed strain + static Vector sigma; // trial stress (resized by ctor) + static Matrix D; // tangent (resized by ctor) + int nDim; // 2 or 3 + + // Helpers + double computeGGmax(double gamma); + double computeShearStrain(const Vector& strain) const; // octahedral-equivalent + void computeTangent(double gg_ratio); + + // Curve models + double hardinDrnevich(double gamma) const; + double vuceticDobry(double gamma) const; + double darendeli(double gamma) const; + double interpolateUserCurve(double gamma) const; +}; + +#endif // LINEAR_ELASTIC_GGMAX_H diff --git a/SRC/material/nD/UWmaterials/Makefile b/SRC/material/nD/UWmaterials/Makefile index 08464240d8..01c3184e28 100644 --- a/SRC/material/nD/UWmaterials/Makefile +++ b/SRC/material/nD/UWmaterials/Makefile @@ -19,7 +19,8 @@ OBJS = BoundingCamClay.o \ PM4Silt.o\ J2CyclicBoundingSurface.o\ J2CyclicBoundingSurface3D.o\ - J2CyclicBoundingSurfacePlaneStrain.o + J2CyclicBoundingSurfacePlaneStrain.o\ + LinearElasticGGmax.o all: $(OBJS) diff --git a/SRC/material/nD/soil/PressureIndependMultiYield.cpp b/SRC/material/nD/soil/PressureIndependMultiYield.cpp index a8d6aaf59d..0d12a92882 100644 --- a/SRC/material/nD/soil/PressureIndependMultiYield.cpp +++ b/SRC/material/nD/soil/PressureIndependMultiYield.cpp @@ -73,9 +73,11 @@ void* OPS_PressureIndependMultiYield() param[5] = 0.0; param[6] = 100.; param[7] = 0.0; - numdata = 5; + numdata = 8; if (OPS_GetDoubleInput(&numdata, ¶m[0]) < 0) { - opserr << "WARNING invalid PressureIndependMultiYield double inputs" << "\n"; + opserr << "WARNING invalid PressureIndependMultiYield double inputs\n"; + opserr << "Be sure to input frictionAng, refPress, and pressDependCoe.\n"; + opserr << "These inputs are now required; recommended 0, 100 kPa, and 0, respectively" << endln; return 0; } @@ -1597,3 +1599,4 @@ int PressureIndependMultiYield:: isCrossingNextSurface(void) } + diff --git a/SRC/material/section/DoubleMembranePlateFiberSection.cpp b/SRC/material/section/DoubleMembranePlateFiberSection.cpp index 974fc790fc..a2dac0c976 100644 --- a/SRC/material/section/DoubleMembranePlateFiberSection.cpp +++ b/SRC/material/section/DoubleMembranePlateFiberSection.cpp @@ -271,8 +271,8 @@ setTrialSectionDeformation( const Vector &strainResultant_from_element) double z ; - strain(3) = root56*strainResultant(6) ; - strain(4) = root56*strainResultant(7) ; + strain(4) = root56*strainResultant(6) ; + strain(3) = root56*strainResultant(7) ; for ( i = 0; i < numFibers; i++ ) { @@ -346,9 +346,9 @@ const Vector& DoubleMembranePlateFiberSection::getStressResultant( ) stressResultant(5) += ( z*stress(2) ) * weight ; //shear - stressResultant(6) += stress(3)*weight ; + stressResultant(6) += stress(4)*weight ; - stressResultant(7) += stress(4)*weight ; + stressResultant(7) += stress(3)*weight ; z = -z; @@ -370,9 +370,9 @@ const Vector& DoubleMembranePlateFiberSection::getStressResultant( ) stressResultant(5) += ( z*stress(2) ) * weight ; //shear - stressResultant(6) += stress(3)*weight ; + stressResultant(6) += stress(4)*weight ; - stressResultant(7) += stress(4)*weight ; + stressResultant(7) += stress(3)*weight ; } //end for i @@ -465,8 +465,8 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(0,3) += -z*dd(0,0) ; tangent(0,4) += -z*dd(0,1) ; tangent(0,5) += -z*dd(0,2) ; - tangent(0,6) += root56*dd(0,3) ; - tangent(0,7) += root56*dd(0,4) ; + tangent(0,6) += root56*dd(0,4) ; + tangent(0,7) += root56*dd(0,3) ; //row 2 //[ d21, d22, d23, -z*d21, -z*d22, -z*d23, d24*root56, d25*root56] @@ -476,8 +476,8 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(1,3) += -z*dd(1,0) ; tangent(1,4) += -z*dd(1,1) ; tangent(1,5) += -z*dd(1,2) ; - tangent(1,6) += root56*dd(1,3) ; - tangent(1,7) += root56*dd(1,4) ; + tangent(1,6) += root56*dd(1,4) ; + tangent(1,7) += root56*dd(1,3) ; //row 3 //[ d31, d32, d33, -z*d31, -z*d32, -z*d33, d34*root56, d35*root56] @@ -487,8 +487,8 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(2,3) += -z*dd(2,0) ; tangent(2,4) += -z*dd(2,1) ; tangent(2,5) += -z*dd(2,2) ; - tangent(2,6) += root56*dd(2,3) ; - tangent(2,7) += root56*dd(2,4) ; + tangent(2,6) += root56*dd(2,4) ; + tangent(2,7) += root56*dd(2,3) ; //row 4 //[ z*d11, z*d12, z*d13, -z^2*d11, -z^2*d12, -z^2*d13, z*d14*root56, z*d15*root56] @@ -498,8 +498,8 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(3,3) += -z*z*dd(0,0) ; tangent(3,4) += -z*z*dd(0,1) ; tangent(3,5) += -z*z*dd(0,2) ; - tangent(3,6) += z*root56*dd(0,3) ; - tangent(3,7) += z*root56*dd(0,4) ; + tangent(3,6) += z*root56*dd(0,4) ; + tangent(3,7) += z*root56*dd(0,3) ; //row 5 //[ z*d21, z*d22, z*d23, -z^2*d21, -z^2*d22, -z^2*d23, z*d24*root56, z*d25*root56] @@ -509,8 +509,8 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(4,3) += -z*z*dd(1,0) ; tangent(4,4) += -z*z*dd(1,1) ; tangent(4,5) += -z*z*dd(1,2) ; - tangent(4,6) += z*root56*dd(1,3) ; - tangent(4,7) += z*root56*dd(1,4) ; + tangent(4,6) += z*root56*dd(1,4) ; + tangent(4,7) += z*root56*dd(1,3) ; //row 6 //[ z*d31, z*d32, z*d33, -z^2*d31, -z^2*d32, -z^2*d33, z*d34*root56, z*d35*root56] @@ -520,30 +520,30 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(5,3) += -z*z*dd(2,0) ; tangent(5,4) += -z*z*dd(2,1) ; tangent(5,5) += -z*z*dd(2,2) ; - tangent(5,6) += z*root56*dd(2,3) ; - tangent(5,7) += z*root56*dd(2,4) ; + tangent(5,6) += z*root56*dd(2,4) ; + tangent(5,7) += z*root56*dd(2,3) ; //row 7 //[ root56*d41, root56*d42, root56*d43, -root56*d41*z, -root56*d42*z, -root56*d43*z, root56^2*d44, root56^2*d45] - tangent(6,0) += root56*dd(3,0) ; - tangent(6,1) += root56*dd(3,1) ; - tangent(6,2) += root56*dd(3,2) ; - tangent(6,3) += -root56*z*dd(3,0) ; - tangent(6,4) += -root56*z*dd(3,1) ; - tangent(6,5) += -root56*z*dd(3,2) ; - tangent(6,6) += root56*root56*dd(3,3) ; - tangent(6,7) += root56*root56*dd(3,4) ; + tangent(6,0) += root56*dd(4,0) ; + tangent(6,1) += root56*dd(4,1) ; + tangent(6,2) += root56*dd(4,2) ; + tangent(6,3) += -root56*z*dd(4,0) ; + tangent(6,4) += -root56*z*dd(4,1) ; + tangent(6,5) += -root56*z*dd(4,2) ; + tangent(6,6) += root56*root56*dd(4,4) ; + tangent(6,7) += root56*root56*dd(4,3) ; //row 8 //[ root56*d51, root56*d52, root56*d53, -root56*d51*z, -root56*d52*z, -root56*d53*z, root56^2*d54, root56^2*d55] - tangent(7,0) += root56*dd(4,0) ; - tangent(7,1) += root56*dd(4,1) ; - tangent(7,2) += root56*dd(4,2) ; - tangent(7,3) += -root56*z*dd(4,0) ; - tangent(7,4) += -root56*z*dd(4,1) ; - tangent(7,5) += -root56*z*dd(4,2) ; - tangent(7,6) += root56*root56*dd(4,3) ; - tangent(7,7) += root56*root56*dd(4,4) ; + tangent(7,0) += root56*dd(3,0) ; + tangent(7,1) += root56*dd(3,1) ; + tangent(7,2) += root56*dd(3,2) ; + tangent(7,3) += -root56*z*dd(3,0) ; + tangent(7,4) += -root56*z*dd(3,1) ; + tangent(7,5) += -root56*z*dd(3,2) ; + tangent(7,6) += root56*root56*dd(3,4) ; + tangent(7,7) += root56*root56*dd(3,3) ; @@ -611,8 +611,8 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(0,3) += -z*dd(0,0) ; tangent(0,4) += -z*dd(0,1) ; tangent(0,5) += -z*dd(0,2) ; - tangent(0,6) += root56*dd(0,3) ; - tangent(0,7) += root56*dd(0,4) ; + tangent(0,6) += root56*dd(0,4) ; + tangent(0,7) += root56*dd(0,3) ; //row 2 //[ d21, d22, d23, -z*d21, -z*d22, -z*d23, d24*root56, d25*root56] @@ -622,8 +622,8 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(1,3) += -z*dd(1,0) ; tangent(1,4) += -z*dd(1,1) ; tangent(1,5) += -z*dd(1,2) ; - tangent(1,6) += root56*dd(1,3) ; - tangent(1,7) += root56*dd(1,4) ; + tangent(1,6) += root56*dd(1,4) ; + tangent(1,7) += root56*dd(1,3) ; //row 3 //[ d31, d32, d33, -z*d31, -z*d32, -z*d33, d34*root56, d35*root56] @@ -633,8 +633,8 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(2,3) += -z*dd(2,0) ; tangent(2,4) += -z*dd(2,1) ; tangent(2,5) += -z*dd(2,2) ; - tangent(2,6) += root56*dd(2,3) ; - tangent(2,7) += root56*dd(2,4) ; + tangent(2,6) += root56*dd(2,4) ; + tangent(2,7) += root56*dd(2,3) ; //row 4 //[ z*d11, z*d12, z*d13, -z^2*d11, -z^2*d12, -z^2*d13, z*d14*root56, z*d15*root56] @@ -644,8 +644,8 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(3,3) += -z*z*dd(0,0) ; tangent(3,4) += -z*z*dd(0,1) ; tangent(3,5) += -z*z*dd(0,2) ; - tangent(3,6) += z*root56*dd(0,3) ; - tangent(3,7) += z*root56*dd(0,4) ; + tangent(3,6) += z*root56*dd(0,4) ; + tangent(3,7) += z*root56*dd(0,3) ; //row 5 //[ z*d21, z*d22, z*d23, -z^2*d21, -z^2*d22, -z^2*d23, z*d24*root56, z*d25*root56] @@ -655,8 +655,8 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(4,3) += -z*z*dd(1,0) ; tangent(4,4) += -z*z*dd(1,1) ; tangent(4,5) += -z*z*dd(1,2) ; - tangent(4,6) += z*root56*dd(1,3) ; - tangent(4,7) += z*root56*dd(1,4) ; + tangent(4,6) += z*root56*dd(1,4) ; + tangent(4,7) += z*root56*dd(1,3) ; //row 6 //[ z*d31, z*d32, z*d33, -z^2*d31, -z^2*d32, -z^2*d33, z*d34*root56, z*d35*root56] @@ -666,30 +666,30 @@ const Matrix& DoubleMembranePlateFiberSection::getSectionTangent( ) tangent(5,3) += -z*z*dd(2,0) ; tangent(5,4) += -z*z*dd(2,1) ; tangent(5,5) += -z*z*dd(2,2) ; - tangent(5,6) += z*root56*dd(2,3) ; - tangent(5,7) += z*root56*dd(2,4) ; + tangent(5,6) += z*root56*dd(2,4) ; + tangent(5,7) += z*root56*dd(2,3) ; //row 7 //[ root56*d41, root56*d42, root56*d43, -root56*d41*z, -root56*d42*z, -root56*d43*z, root56^2*d44, root56^2*d45] - tangent(6,0) += root56*dd(3,0) ; - tangent(6,1) += root56*dd(3,1) ; - tangent(6,2) += root56*dd(3,2) ; - tangent(6,3) += -root56*z*dd(3,0) ; - tangent(6,4) += -root56*z*dd(3,1) ; - tangent(6,5) += -root56*z*dd(3,2) ; - tangent(6,6) += root56*root56*dd(3,3) ; - tangent(6,7) += root56*root56*dd(3,4) ; + tangent(6,0) += root56*dd(4,0) ; + tangent(6,1) += root56*dd(4,1) ; + tangent(6,2) += root56*dd(4,2) ; + tangent(6,3) += -root56*z*dd(4,0) ; + tangent(6,4) += -root56*z*dd(4,1) ; + tangent(6,5) += -root56*z*dd(4,2) ; + tangent(6,6) += root56*root56*dd(4,4) ; + tangent(6,7) += root56*root56*dd(4,3) ; //row 8 //[ root56*d51, root56*d52, root56*d53, -root56*d51*z, -root56*d52*z, -root56*d53*z, root56^2*d54, root56^2*d55] - tangent(7,0) += root56*dd(4,0) ; - tangent(7,1) += root56*dd(4,1) ; - tangent(7,2) += root56*dd(4,2) ; - tangent(7,3) += -root56*z*dd(4,0) ; - tangent(7,4) += -root56*z*dd(4,1) ; - tangent(7,5) += -root56*z*dd(4,2) ; - tangent(7,6) += root56*root56*dd(4,3) ; - tangent(7,7) += root56*root56*dd(4,4) ; + tangent(7,0) += root56*dd(3,0) ; + tangent(7,1) += root56*dd(3,1) ; + tangent(7,2) += root56*dd(3,2) ; + tangent(7,3) += -root56*z*dd(3,0) ; + tangent(7,4) += -root56*z*dd(3,1) ; + tangent(7,5) += -root56*z*dd(3,2) ; + tangent(7,6) += root56*root56*dd(3,4) ; + tangent(7,7) += root56*root56*dd(3,3) ; } //end for i diff --git a/SRC/material/section/LayeredShellFiberSection.cpp b/SRC/material/section/LayeredShellFiberSection.cpp index e8c379e3ef..0ad528605e 100644 --- a/SRC/material/section/LayeredShellFiberSection.cpp +++ b/SRC/material/section/LayeredShellFiberSection.cpp @@ -440,9 +440,9 @@ setTrialSectionDeformation( const Vector &strainResultant_from_element) strain(2) = strainResultant(2) - z*strainResultant(5) ; - strain(3) = strainResultant(6) ; + strain(4) = strainResultant(6) ; - strain(4) = strainResultant(7) ; + strain(3) = strainResultant(7) ; success += theFibers[i]->setTrialStrain( strain ) ; @@ -494,9 +494,9 @@ const Vector& LayeredShellFiberSection::getStressResultant( ) stressResultant(5) += ( z*stress(2) ) * weight ; //shear - stressResultant(6) += stress(3)*weight ; + stressResultant(6) += stress(4)*weight ; - stressResultant(7) += stress(4)*weight ; + stressResultant(7) += stress(3)*weight ; } //end for i @@ -584,8 +584,8 @@ const Matrix& LayeredShellFiberSection::getSectionTangent( ) tangent(0,3) += -z*dd(0,0) ; tangent(0,4) += -z*dd(0,1) ; tangent(0,5) += -z*dd(0,2) ; - tangent(0,6) += dd(0,3) ; - tangent(0,7) += dd(0,4) ; + tangent(0,6) += dd(0,4) ; + tangent(0,7) += dd(0,3) ; //row 2 //[ d21, d22, d23, -z*d21, -z*d22, -z*d23, d24, d25] @@ -595,8 +595,8 @@ const Matrix& LayeredShellFiberSection::getSectionTangent( ) tangent(1,3) += -z*dd(1,0) ; tangent(1,4) += -z*dd(1,1) ; tangent(1,5) += -z*dd(1,2) ; - tangent(1,6) += dd(1,3) ; - tangent(1,7) += dd(1,4) ; + tangent(1,6) += dd(1,4) ; + tangent(1,7) += dd(1,3) ; //row 3 //[ d31, d32, d33, -z*d31, -z*d32, -z*d33, d34, d35] @@ -606,8 +606,8 @@ const Matrix& LayeredShellFiberSection::getSectionTangent( ) tangent(2,3) += -z*dd(2,0) ; tangent(2,4) += -z*dd(2,1) ; tangent(2,5) += -z*dd(2,2) ; - tangent(2,6) += dd(2,3) ; - tangent(2,7) += dd(2,4) ; + tangent(2,6) += dd(2,4) ; + tangent(2,7) += dd(2,3) ; //row 4 //[ z*d11, z*d12, z*d13, -z^2*d11, -z^2*d12, -z^2*d13, z*d14, z*d15] @@ -617,8 +617,8 @@ const Matrix& LayeredShellFiberSection::getSectionTangent( ) tangent(3,3) += -z*z*dd(0,0) ; tangent(3,4) += -z*z*dd(0,1) ; tangent(3,5) += -z*z*dd(0,2) ; - tangent(3,6) += z*dd(0,3) ; - tangent(3,7) += z*dd(0,4) ; + tangent(3,6) += z*dd(0,4) ; + tangent(3,7) += z*dd(0,3) ; //row 5 //[ z*d21, z*d22, z*d23, -z^2*d21, -z^2*d22, -z^2*d23, z*d24, z*d25] @@ -628,8 +628,8 @@ const Matrix& LayeredShellFiberSection::getSectionTangent( ) tangent(4,3) += -z*z*dd(1,0) ; tangent(4,4) += -z*z*dd(1,1) ; tangent(4,5) += -z*z*dd(1,2) ; - tangent(4,6) += z*dd(1,3) ; - tangent(4,7) += z*dd(1,4) ; + tangent(4,6) += z*dd(1,4) ; + tangent(4,7) += z*dd(1,3) ; //row 6 //[ z*d31, z*d32, z*d33, -z^2*d31, -z^2*d32, -z^2*d33, z*d34, z*d35] @@ -639,30 +639,30 @@ const Matrix& LayeredShellFiberSection::getSectionTangent( ) tangent(5,3) += -z*z*dd(2,0) ; tangent(5,4) += -z*z*dd(2,1) ; tangent(5,5) += -z*z*dd(2,2) ; - tangent(5,6) += z*dd(2,3) ; - tangent(5,7) += z*dd(2,4) ; + tangent(5,6) += z*dd(2,4) ; + tangent(5,7) += z*dd(2,3) ; //row 7 //[ d41, d42, d43, -d41*z, -d42*z, -d43*z, d44, d45] - tangent(6,0) += dd(3,0) ; - tangent(6,1) += dd(3,1) ; - tangent(6,2) += dd(3,2) ; - tangent(6,3) += -z*dd(3,0) ; - tangent(6,4) += -z*dd(3,1) ; - tangent(6,5) += -z*dd(3,2) ; - tangent(6,6) += dd(3,3) ; - tangent(6,7) += dd(3,4) ; + tangent(6,0) += dd(4,0) ; + tangent(6,1) += dd(4,1) ; + tangent(6,2) += dd(4,2) ; + tangent(6,3) += -z*dd(4,0) ; + tangent(6,4) += -z*dd(4,1) ; + tangent(6,5) += -z*dd(4,2) ; + tangent(6,6) += dd(4,4) ; + tangent(6,7) += dd(4,3) ; //row 8 //[ d51, d52, d53, -d51*z, -d52*z, -d53*z, d54, d55] - tangent(7,0) += dd(4,0) ; - tangent(7,1) += dd(4,1) ; - tangent(7,2) += dd(4,2) ; - tangent(7,3) += -z*dd(4,0) ; - tangent(7,4) += -z*dd(4,1) ; - tangent(7,5) += -z*dd(4,2) ; - tangent(7,6) += dd(4,3) ; - tangent(7,7) += dd(4,4) ; + tangent(7,0) += dd(3,0) ; + tangent(7,1) += dd(3,1) ; + tangent(7,2) += dd(3,2) ; + tangent(7,3) += -z*dd(3,0) ; + tangent(7,4) += -z*dd(3,1) ; + tangent(7,5) += -z*dd(3,2) ; + tangent(7,6) += dd(3,4) ; + tangent(7,7) += dd(3,3) ; } //end for i diff --git a/SRC/material/section/LayeredShellFiberSectionThermal.cpp b/SRC/material/section/LayeredShellFiberSectionThermal.cpp index 66b6de14af..736b23ac45 100644 --- a/SRC/material/section/LayeredShellFiberSectionThermal.cpp +++ b/SRC/material/section/LayeredShellFiberSectionThermal.cpp @@ -434,9 +434,9 @@ setTrialSectionDeformation( const Vector &strainResultant_from_element) strain(2) = strainResultant(2) - z*strainResultant(5) ; - strain(3) = root56*strainResultant(6) ; + strain(4) = root56*strainResultant(6) ; - strain(4) = root56*strainResultant(7) ; + strain(3) = root56*strainResultant(7) ; success += theFibers[i]->setTrialStrain( strain ) ; @@ -536,9 +536,9 @@ const Vector& LayeredShellFiberSectionThermal::getStressResultant( ) stressResultant(5) += ( z*stress(2) ) * weight ; //shear - stressResultant(6) += stress(3)*weight ; + stressResultant(6) += stress(4)*weight ; - stressResultant(7) += stress(4)*weight ; + stressResultant(7) += stress(3)*weight ; } //end for i @@ -631,8 +631,8 @@ const Matrix& LayeredShellFiberSectionThermal::getSectionTangent( ) tangent(0,3) += -z*dd(0,0) ; tangent(0,4) += -z*dd(0,1) ; tangent(0,5) += -z*dd(0,2) ; - tangent(0,6) += dd(0,3) ; - tangent(0,7) += dd(0,4) ; + tangent(0,6) += dd(0,4) ; + tangent(0,7) += dd(0,3) ; //row 2 //[ d21, d22, d23, -z*d21, -z*d22, -z*d23, d24, d25] @@ -642,8 +642,8 @@ const Matrix& LayeredShellFiberSectionThermal::getSectionTangent( ) tangent(1,3) += -z*dd(1,0) ; tangent(1,4) += -z*dd(1,1) ; tangent(1,5) += -z*dd(1,2) ; - tangent(1,6) += dd(1,3) ; - tangent(1,7) += dd(1,4) ; + tangent(1,6) += dd(1,4) ; + tangent(1,7) += dd(1,3) ; //row 3 //[ d31, d32, d33, -z*d31, -z*d32, -z*d33, d34, d35] @@ -653,8 +653,8 @@ const Matrix& LayeredShellFiberSectionThermal::getSectionTangent( ) tangent(2,3) += -z*dd(2,0) ; tangent(2,4) += -z*dd(2,1) ; tangent(2,5) += -z*dd(2,2) ; - tangent(2,6) += dd(2,3) ; - tangent(2,7) += dd(2,4) ; + tangent(2,6) += dd(2,4) ; + tangent(2,7) += dd(2,3) ; //row 4 //[ z*d11, z*d12, z*d13, -z^2*d11, -z^2*d12, -z^2*d13, z*d14, z*d15] @@ -664,8 +664,8 @@ const Matrix& LayeredShellFiberSectionThermal::getSectionTangent( ) tangent(3,3) += -z*z*dd(0,0) ; tangent(3,4) += -z*z*dd(0,1) ; tangent(3,5) += -z*z*dd(0,2) ; - tangent(3,6) += z*dd(0,3) ; - tangent(3,7) += z*dd(0,4) ; + tangent(3,6) += z*dd(0,4) ; + tangent(3,7) += z*dd(0,3) ; //row 5 //[ z*d21, z*d22, z*d23, -z^2*d21, -z^2*d22, -z^2*d23, z*d24, z*d25] @@ -675,8 +675,8 @@ const Matrix& LayeredShellFiberSectionThermal::getSectionTangent( ) tangent(4,3) += -z*z*dd(1,0) ; tangent(4,4) += -z*z*dd(1,1) ; tangent(4,5) += -z*z*dd(1,2) ; - tangent(4,6) += z*dd(1,3) ; - tangent(4,7) += z*dd(1,4) ; + tangent(4,6) += z*dd(1,4) ; + tangent(4,7) += z*dd(1,3) ; //row 6 //[ z*d31, z*d32, z*d33, -z^2*d31, -z^2*d32, -z^2*d33, z*d34, z*d35] @@ -686,30 +686,30 @@ const Matrix& LayeredShellFiberSectionThermal::getSectionTangent( ) tangent(5,3) += -z*z*dd(2,0) ; tangent(5,4) += -z*z*dd(2,1) ; tangent(5,5) += -z*z*dd(2,2) ; - tangent(5,6) += z*dd(2,3) ; - tangent(5,7) += z*dd(2,4) ; + tangent(5,6) += z*dd(2,4) ; + tangent(5,7) += z*dd(2,3) ; //row 7 //[ d41, d42, d43, -d41*z, -d42*z, -d43*z, d44, d45] - tangent(6,0) += dd(3,0) ; - tangent(6,1) += dd(3,1) ; - tangent(6,2) += dd(3,2) ; - tangent(6,3) += -z*dd(3,0) ; - tangent(6,4) += -z*dd(3,1) ; - tangent(6,5) += -z*dd(3,2) ; - tangent(6,6) += dd(3,3) ; - tangent(6,7) += dd(3,4) ; + tangent(6,0) += dd(4,0) ; + tangent(6,1) += dd(4,1) ; + tangent(6,2) += dd(4,2) ; + tangent(6,3) += -z*dd(4,0) ; + tangent(6,4) += -z*dd(4,1) ; + tangent(6,5) += -z*dd(4,2) ; + tangent(6,6) += dd(4,4) ; + tangent(6,7) += dd(4,3) ; //row 8 //[ d51, d52, d53, -d51*z, -d52*z, -d53*z, d54, d55] - tangent(7,0) += dd(4,0) ; - tangent(7,1) += dd(4,1) ; - tangent(7,2) += dd(4,2) ; - tangent(7,3) += -z*dd(4,0) ; - tangent(7,4) += -z*dd(4,1) ; - tangent(7,5) += -z*dd(4,2) ; - tangent(7,6) += dd(4,3) ; - tangent(7,7) += dd(4,4) ; + tangent(7,0) += dd(3,0) ; + tangent(7,1) += dd(3,1) ; + tangent(7,2) += dd(3,2) ; + tangent(7,3) += -z*dd(3,0) ; + tangent(7,4) += -z*dd(3,1) ; + tangent(7,5) += -z*dd(3,2) ; + tangent(7,6) += dd(3,4) ; + tangent(7,7) += dd(3,3) ; } //end for i diff --git a/SRC/material/section/MembranePlateFiberSection.cpp b/SRC/material/section/MembranePlateFiberSection.cpp index 6dddec5b57..050197abc3 100644 --- a/SRC/material/section/MembranePlateFiberSection.cpp +++ b/SRC/material/section/MembranePlateFiberSection.cpp @@ -274,9 +274,9 @@ setTrialSectionDeformation( const Vector &strainResultant_from_element) strain(2) = strainResultant(2) - z*strainResultant(5) ; - strain(3) = root56*strainResultant(6) ; + strain(4) = root56*strainResultant(6) ; - strain(4) = root56*strainResultant(7) ; + strain(3) = root56*strainResultant(7) ; success += theFibers[i]->setTrialStrain( strain ) ; @@ -329,9 +329,9 @@ const Vector& MembranePlateFiberSection::getStressResultant( ) stressResultant(5) += ( z*stress(2) ) * weight ; //shear - stressResultant(6) += stress(3)*weight ; + stressResultant(6) += stress(4)*weight ; - stressResultant(7) += stress(4)*weight ; + stressResultant(7) += stress(3)*weight ; } //end for i @@ -424,8 +424,8 @@ const Matrix& MembranePlateFiberSection::getSectionTangent( ) tangent(0,3) += -z*dd(0,0) ; tangent(0,4) += -z*dd(0,1) ; tangent(0,5) += -z*dd(0,2) ; - tangent(0,6) += root56*dd(0,3) ; - tangent(0,7) += root56*dd(0,4) ; + tangent(0,6) += root56*dd(0,4) ; + tangent(0,7) += root56*dd(0,3) ; //row 2 //[ d21, d22, d23, -z*d21, -z*d22, -z*d23, d24*root56, d25*root56] @@ -435,8 +435,8 @@ const Matrix& MembranePlateFiberSection::getSectionTangent( ) tangent(1,3) += -z*dd(1,0) ; tangent(1,4) += -z*dd(1,1) ; tangent(1,5) += -z*dd(1,2) ; - tangent(1,6) += root56*dd(1,3) ; - tangent(1,7) += root56*dd(1,4) ; + tangent(1,6) += root56*dd(1,4) ; + tangent(1,7) += root56*dd(1,3) ; //row 3 //[ d31, d32, d33, -z*d31, -z*d32, -z*d33, d34*root56, d35*root56] @@ -446,8 +446,8 @@ const Matrix& MembranePlateFiberSection::getSectionTangent( ) tangent(2,3) += -z*dd(2,0) ; tangent(2,4) += -z*dd(2,1) ; tangent(2,5) += -z*dd(2,2) ; - tangent(2,6) += root56*dd(2,3) ; - tangent(2,7) += root56*dd(2,4) ; + tangent(2,6) += root56*dd(2,4) ; + tangent(2,7) += root56*dd(2,3) ; //row 4 //[ z*d11, z*d12, z*d13, -z^2*d11, -z^2*d12, -z^2*d13, z*d14*root56, z*d15*root56] @@ -457,8 +457,8 @@ const Matrix& MembranePlateFiberSection::getSectionTangent( ) tangent(3,3) += -z*z*dd(0,0) ; tangent(3,4) += -z*z*dd(0,1) ; tangent(3,5) += -z*z*dd(0,2) ; - tangent(3,6) += z*root56*dd(0,3) ; - tangent(3,7) += z*root56*dd(0,4) ; + tangent(3,6) += z*root56*dd(0,4) ; + tangent(3,7) += z*root56*dd(0,3) ; //row 5 //[ z*d21, z*d22, z*d23, -z^2*d21, -z^2*d22, -z^2*d23, z*d24*root56, z*d25*root56] @@ -468,8 +468,8 @@ const Matrix& MembranePlateFiberSection::getSectionTangent( ) tangent(4,3) += -z*z*dd(1,0) ; tangent(4,4) += -z*z*dd(1,1) ; tangent(4,5) += -z*z*dd(1,2) ; - tangent(4,6) += z*root56*dd(1,3) ; - tangent(4,7) += z*root56*dd(1,4) ; + tangent(4,6) += z*root56*dd(1,4) ; + tangent(4,7) += z*root56*dd(1,3) ; //row 6 //[ z*d31, z*d32, z*d33, -z^2*d31, -z^2*d32, -z^2*d33, z*d34*root56, z*d35*root56] @@ -479,30 +479,30 @@ const Matrix& MembranePlateFiberSection::getSectionTangent( ) tangent(5,3) += -z*z*dd(2,0) ; tangent(5,4) += -z*z*dd(2,1) ; tangent(5,5) += -z*z*dd(2,2) ; - tangent(5,6) += z*root56*dd(2,3) ; - tangent(5,7) += z*root56*dd(2,4) ; + tangent(5,6) += z*root56*dd(2,4) ; + tangent(5,7) += z*root56*dd(2,3) ; //row 7 //[ root56*d41, root56*d42, root56*d43, -root56*d41*z, -root56*d42*z, -root56*d43*z, root56^2*d44, root56^2*d45] - tangent(6,0) += root56*dd(3,0) ; - tangent(6,1) += root56*dd(3,1) ; - tangent(6,2) += root56*dd(3,2) ; - tangent(6,3) += -root56*z*dd(3,0) ; - tangent(6,4) += -root56*z*dd(3,1) ; - tangent(6,5) += -root56*z*dd(3,2) ; - tangent(6,6) += root56*root56*dd(3,3) ; - tangent(6,7) += root56*root56*dd(3,4) ; + tangent(6,0) += root56*dd(4,0) ; + tangent(6,1) += root56*dd(4,1) ; + tangent(6,2) += root56*dd(4,2) ; + tangent(6,3) += -root56*z*dd(4,0) ; + tangent(6,4) += -root56*z*dd(4,1) ; + tangent(6,5) += -root56*z*dd(4,2) ; + tangent(6,6) += root56*root56*dd(4,4) ; + tangent(6,7) += root56*root56*dd(4,3) ; //row 8 //[ root56*d51, root56*d52, root56*d53, -root56*d51*z, -root56*d52*z, -root56*d53*z, root56^2*d54, root56^2*d55] - tangent(7,0) += root56*dd(4,0) ; - tangent(7,1) += root56*dd(4,1) ; - tangent(7,2) += root56*dd(4,2) ; - tangent(7,3) += -root56*z*dd(4,0) ; - tangent(7,4) += -root56*z*dd(4,1) ; - tangent(7,5) += -root56*z*dd(4,2) ; - tangent(7,6) += root56*root56*dd(4,3) ; - tangent(7,7) += root56*root56*dd(4,4) ; + tangent(7,0) += root56*dd(3,0) ; + tangent(7,1) += root56*dd(3,1) ; + tangent(7,2) += root56*dd(3,2) ; + tangent(7,3) += -root56*z*dd(3,0) ; + tangent(7,4) += -root56*z*dd(3,1) ; + tangent(7,5) += -root56*z*dd(3,2) ; + tangent(7,6) += root56*root56*dd(3,4) ; + tangent(7,7) += root56*root56*dd(3,3) ; } //end for i diff --git a/SRC/material/section/MembranePlateFiberSectionThermal.cpp b/SRC/material/section/MembranePlateFiberSectionThermal.cpp index 0cf348cd5e..60147c06e2 100644 --- a/SRC/material/section/MembranePlateFiberSectionThermal.cpp +++ b/SRC/material/section/MembranePlateFiberSectionThermal.cpp @@ -302,9 +302,9 @@ setTrialSectionDeformation( const Vector &strainResultant_from_element) strain(2) = strainResultant(2) - z*strainResultant(5) ; - strain(3) = root56*strainResultant(6) ; + strain(4) = root56*strainResultant(6) ; - strain(4) = root56*strainResultant(7) ; + strain(3) = root56*strainResultant(7) ; //J.Jiang add to see strain double strain0, strain1,strain2, strain3, strain4; strain0=strain(0); @@ -367,9 +367,9 @@ const Vector& MembranePlateFiberSectionThermal::getStressResultant( ) stressResultant(5) += ( z*stress(2) ) * weight ; //shear - stressResultant(6) += stress(3)*weight ; + stressResultant(6) += stress(4)*weight ; - stressResultant(7) += stress(4)*weight ; + stressResultant(7) += stress(3)*weight ; } //end for i @@ -551,8 +551,8 @@ const Matrix& MembranePlateFiberSectionThermal::getSectionTangent( ) tangent(0,3) += -z*dd(0,0) ; tangent(0,4) += -z*dd(0,1) ; tangent(0,5) += -z*dd(0,2) ; - tangent(0,6) += root56*dd(0,3) ; - tangent(0,7) += root56*dd(0,4) ; + tangent(0,6) += root56*dd(0,4) ; + tangent(0,7) += root56*dd(0,3) ; //row 2 //[ d21, d22, d23, -z*d21, -z*d22, -z*d23, d24*root56, d25*root56] @@ -562,8 +562,8 @@ const Matrix& MembranePlateFiberSectionThermal::getSectionTangent( ) tangent(1,3) += -z*dd(1,0) ; tangent(1,4) += -z*dd(1,1) ; tangent(1,5) += -z*dd(1,2) ; - tangent(1,6) += root56*dd(1,3) ; - tangent(1,7) += root56*dd(1,4) ; + tangent(1,6) += root56*dd(1,4) ; + tangent(1,7) += root56*dd(1,3) ; //row 3 //[ d31, d32, d33, -z*d31, -z*d32, -z*d33, d34*root56, d35*root56] @@ -573,8 +573,8 @@ const Matrix& MembranePlateFiberSectionThermal::getSectionTangent( ) tangent(2,3) += -z*dd(2,0) ; tangent(2,4) += -z*dd(2,1) ; tangent(2,5) += -z*dd(2,2) ; - tangent(2,6) += root56*dd(2,3) ; - tangent(2,7) += root56*dd(2,4) ; + tangent(2,6) += root56*dd(2,4) ; + tangent(2,7) += root56*dd(2,3) ; //row 4 //[ z*d11, z*d12, z*d13, -z^2*d11, -z^2*d12, -z^2*d13, z*d14*root56, z*d15*root56] @@ -584,8 +584,8 @@ const Matrix& MembranePlateFiberSectionThermal::getSectionTangent( ) tangent(3,3) += -z*z*dd(0,0) ; tangent(3,4) += -z*z*dd(0,1) ; tangent(3,5) += -z*z*dd(0,2) ; - tangent(3,6) += z*root56*dd(0,3) ; - tangent(3,7) += z*root56*dd(0,4) ; + tangent(3,6) += z*root56*dd(0,4) ; + tangent(3,7) += z*root56*dd(0,3) ; //row 5 //[ z*d21, z*d22, z*d23, -z^2*d21, -z^2*d22, -z^2*d23, z*d24*root56, z*d25*root56] @@ -595,8 +595,8 @@ const Matrix& MembranePlateFiberSectionThermal::getSectionTangent( ) tangent(4,3) += -z*z*dd(1,0) ; tangent(4,4) += -z*z*dd(1,1) ; tangent(4,5) += -z*z*dd(1,2) ; - tangent(4,6) += z*root56*dd(1,3) ; - tangent(4,7) += z*root56*dd(1,4) ; + tangent(4,6) += z*root56*dd(1,4) ; + tangent(4,7) += z*root56*dd(1,3) ; //row 6 //[ z*d31, z*d32, z*d33, -z^2*d31, -z^2*d32, -z^2*d33, z*d34*root56, z*d35*root56] @@ -606,30 +606,30 @@ const Matrix& MembranePlateFiberSectionThermal::getSectionTangent( ) tangent(5,3) += -z*z*dd(2,0) ; tangent(5,4) += -z*z*dd(2,1) ; tangent(5,5) += -z*z*dd(2,2) ; - tangent(5,6) += z*root56*dd(2,3) ; - tangent(5,7) += z*root56*dd(2,4) ; + tangent(5,6) += z*root56*dd(2,4) ; + tangent(5,7) += z*root56*dd(2,3) ; //row 7 //[ root56*d41, root56*d42, root56*d43, -root56*d41*z, -root56*d42*z, -root56*d43*z, root56^2*d44, root56^2*d45] - tangent(6,0) += root56*dd(3,0) ; - tangent(6,1) += root56*dd(3,1) ; - tangent(6,2) += root56*dd(3,2) ; - tangent(6,3) += -root56*z*dd(3,0) ; - tangent(6,4) += -root56*z*dd(3,1) ; - tangent(6,5) += -root56*z*dd(3,2) ; - tangent(6,6) += root56*root56*dd(3,3) ; - tangent(6,7) += root56*root56*dd(3,4) ; + tangent(6,0) += root56*dd(4,0) ; + tangent(6,1) += root56*dd(4,1) ; + tangent(6,2) += root56*dd(4,2) ; + tangent(6,3) += -root56*z*dd(4,0) ; + tangent(6,4) += -root56*z*dd(4,1) ; + tangent(6,5) += -root56*z*dd(4,2) ; + tangent(6,6) += root56*root56*dd(4,4) ; + tangent(6,7) += root56*root56*dd(4,3) ; //row 8 //[ root56*d51, root56*d52, root56*d53, -root56*d51*z, -root56*d52*z, -root56*d53*z, root56^2*d54, root56^2*d55] - tangent(7,0) += root56*dd(4,0) ; - tangent(7,1) += root56*dd(4,1) ; - tangent(7,2) += root56*dd(4,2) ; - tangent(7,3) += -root56*z*dd(4,0) ; - tangent(7,4) += -root56*z*dd(4,1) ; - tangent(7,5) += -root56*z*dd(4,2) ; - tangent(7,6) += root56*root56*dd(4,3) ; - tangent(7,7) += root56*root56*dd(4,4) ; + tangent(7,0) += root56*dd(3,0) ; + tangent(7,1) += root56*dd(3,1) ; + tangent(7,2) += root56*dd(3,2) ; + tangent(7,3) += -root56*z*dd(3,0) ; + tangent(7,4) += -root56*z*dd(3,1) ; + tangent(7,5) += -root56*z*dd(3,2) ; + tangent(7,6) += root56*root56*dd(3,4) ; + tangent(7,7) += root56*root56*dd(3,3) ; } //end for i diff --git a/SRC/material/uniaxial/APDFMD.cpp b/SRC/material/uniaxial/APDFMD.cpp index 9362be541a..3d6ddcf50d 100644 --- a/SRC/material/uniaxial/APDFMD.cpp +++ b/SRC/material/uniaxial/APDFMD.cpp @@ -1,3 +1,9 @@ +/** Developed by: ** +** Linlin Xie (xielinlin@bucea.edu.cn) ** +** Cantian Yang (yangcantian@bucea.edu.cn) ** +** Bingyan Liu (1373158715@163.com) ** +** ****************************************************************** */ + #include #include "APDFMD.h" #include @@ -12,7 +18,7 @@ void * OPS_APDFMD(void) { if (numAPDFMD == 0) { - opserr << "APDFMD unaxial material - Written by BUCEA 2024; \n"; + opserr << "APDFMD unaxial material; \n"; numAPDFMD++; } diff --git a/SRC/material/uniaxial/APDMD.cpp b/SRC/material/uniaxial/APDMD.cpp index 981d9d2506..92d248e01f 100644 --- a/SRC/material/uniaxial/APDMD.cpp +++ b/SRC/material/uniaxial/APDMD.cpp @@ -1,3 +1,9 @@ +/** Developed by: ** +** Linlin Xie (xielinlin@bucea.edu.cn) ** +** Cantian Yang (yangcantian@bucea.edu.cn) ** +** Bingyan Liu (1373158715@163.com) ** +** ****************************************************************** */ + #include #include "APDMD.h" #include @@ -12,7 +18,7 @@ void * OPS_APDMD(void) { if (numAPDMD == 0) { - opserr << "APDMD unaxial material - Written by BUCEA 2024; \n"; + opserr << "APDMD unaxial material; \n"; numAPDMD++; } diff --git a/SRC/material/uniaxial/APDVFD.cpp b/SRC/material/uniaxial/APDVFD.cpp index 448ecd4061..b66450e36b 100644 --- a/SRC/material/uniaxial/APDVFD.cpp +++ b/SRC/material/uniaxial/APDVFD.cpp @@ -1,21 +1,7 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** +/** Developed by: ** +** Linlin Xie (xielinlin@bucea.edu.cn) ** +** Cantian Yang (yangcantian@bucea.edu.cn) ** +** Haoxiang Wang (buceawhx@163.com) ** ** ****************************************************************** */ @@ -42,7 +28,7 @@ OPS_APDVFD(void) { if (numAPDVFD == 0) { numAPDVFD++; - opserr << "APDVFD Model by BUCEA\n"; + opserr << "APDVFD Model\n"; } opserr << "Due to known issues and unreliable results, this material has been" << endln; diff --git a/SRC/material/uniaxial/ASDConcrete1DMaterial.cpp b/SRC/material/uniaxial/ASDConcrete1DMaterial.cpp index 393aa68c50..ee5d9e29d4 100644 --- a/SRC/material/uniaxial/ASDConcrete1DMaterial.cpp +++ b/SRC/material/uniaxial/ASDConcrete1DMaterial.cpp @@ -1324,11 +1324,16 @@ int ASDConcrete1DMaterial::recvSelf(int commitTag, Channel& theChannel, FEM_Obje int ASDConcrete1DMaterial::setParameter(const char** argv, int argc, Parameter& param) { - // 1000 - elasticity & mass + + // 1000 - elasticity & mass & length if (strcmp(argv[0], "E") == 0) { param.setValue(E); return param.addObject(1000, this); } + if (strcmp(argv[0], "lch_ref") == 0) { + param.setValue(lch_ref); + return param.addObject(1001, this); + } // 2000 - time if (strcmp(argv[0], "dTime") == 0) { @@ -1365,6 +1370,11 @@ int ASDConcrete1DMaterial::updateParameter(int parameterID, Information& info) case 1000: E = info.theDouble; return 0; + case 1001: + lch_ref = info.theDouble; + auto_regularize = true; + regularization_done = false; + return 0; // 2000 - time case 2000: diff --git a/SRC/material/uniaxial/ASDSteel1DMaterial.cpp b/SRC/material/uniaxial/ASDSteel1DMaterial.cpp new file mode 100644 index 0000000000..9995859742 --- /dev/null +++ b/SRC/material/uniaxial/ASDSteel1DMaterial.cpp @@ -0,0 +1,2842 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +// $Revision: 1.0 $ +// $Date: 2025-01-03 11:29:01 $ +// $Source: /usr/local/cvs/OpenSees/SRC/material/uniaxial/ASDSteel1DMaterial.cpp,v $ + +// Alessia Casalucci, Massimo Petracca, Guido Camata - ASDEA Software, Italy +// +// A unified and efficient plastic-damage material model for steel bars including fracture, bond-slip, and buckling via multiscale homogenization +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +//#define ASD_STEEL1D__VERBOSE + +#ifdef ASD_STEEL1D__VERBOSE +#define asd_print_full(X) opserr << __func__ << " (Line " << __LINE__ << "): " << X << "\n" +#define asd_print(X) opserr << X << "\n" +#else +#define asd_print_full(X) +#define asd_print(X) +#endif // ASD_STEEL1D__VERBOSE + +// anonymous namespace for utilities +namespace { + + + enum ErrorCodes { + EC_Generic = -1, + EC_IMPLEX_Error_Control = -10 + }; + + inline double sign(double x) { return x == 0.0 ? 0.0 : (x > 0.0 ? 1.0 : -1.0); } + + /** + A simple 2D vector + */ + class V2D + { + public: + double x = 0.0; + double y = 0.0; + public: + V2D() = default; + V2D(double _x, double _y) : x(_x), y(_y) {} + inline double normalize() { + double n = x * x + y * y; + if (n > 0.0) { + n = std::sqrt(n); + x /= n; + y /= n; + } + return n; + } + inline double operator()(int i) const { + if (i == 0) return x; + return y; + } + }; + inline V2D operator + (const V2D& a, const V2D& b) { + return V2D(a.x + b.x, a.y + b.y); + } + inline V2D operator - (const V2D& a, const V2D& b) { + return V2D(a.x - b.x, a.y - b.y); + } + inline V2D operator * (double a, const V2D& b) { + return V2D(a * b.x, a * b.y); + } + inline V2D operator * (const V2D& b, double a) { + return a * b; + } + + /** + A simple 2D basis matrix + */ + class M2D + { + public: + V2D dx; + V2D dy; + public: + M2D() = default; + M2D(const V2D& x, const V2D& y) : dx(x), dy(y) {} + inline double operator()(int i, int j) const { + if (i == 0) return dx(j); + return dy(j); + } + }; + + /** + A quaternion optimized for the 2D case + */ + class Q2D + { + public: + double w = 0.0; + double z = 0.0; + public: + Q2D() = default; + Q2D(double _w, double _z) : w(_w), z(_z) {} + public: + inline Q2D conjugate()const { return Q2D(w, -z); } + inline double toRotationVector()const { + double ww = w; + double zz = z; + if (w < 0.0) { + ww = -ww; + zz = -zz; + } + double vNorm = std::sqrt(zz * zz); + if (vNorm == 0.0) return 0.0; + double mult = vNorm < ww ? (2.0 / vNorm * std::asin(vNorm)) : (2.0 / vNorm * std::acos(ww)); + return zz * mult; + } + inline V2D rotateVector(const V2D& a) const { + V2D b(-2.0 * z * a.y, 2.0 * z * a.x); + V2D c(-z * b.y, z * b.x); + return a + b * w + c; + } + inline void normalize() { + double n = w * w + z * z; + if (n > 0.0) { + n = std::sqrt(n); + w /= n; + z /= n; + } + } + static Q2D identity() { + return Q2D(1.0, 0.0); + } + static Q2D fromRotationVector(double axis) { + double n = std::abs(axis); + if (n == 0.0) + return Q2D::identity(); + if (n != 1.0) + axis /= n; + double halfAngle = n * 0.5; + double q0 = std::cos(halfAngle); + double s = std::sin(halfAngle); + Q2D result(q0, axis * s); + result.normalize(); + return result; + } + static Q2D fromRotationMatrix(const M2D& m) { + double tr = m.dx.x + m.dy.y + 1.0; + if ((tr > m.dx.x) && (tr > m.dy.y) && (tr > 1.0)) { + double S = std::sqrt(tr + 1.0) * 2.0; + Q2D Q(0.25 * S, (m.dy.x - m.dx.y) / S); + Q.normalize(); + return Q; + } + else { + double S = std::sqrt(1.0 + 1.0 - m.dx.x - m.dy.y) * 2.0; + Q2D Q((m.dy.x - m.dx.y) / S, 0.25 * S); + Q.normalize(); + return Q; + } + } + }; + inline Q2D operator * (const Q2D& a, const Q2D& b) { + return Q2D(a.w * b.w - a.z * b.z, a.w * b.z + a.z * b.w); + } + + /** + Global storage to avoid many dynamic allocation/deallocations. + */ + class Globals + { + private: + Globals() = default; + Globals(const Globals&) = delete; + Globals& operator = (const Globals&) = delete; + + public: + static Globals& instance() { + static Globals _instance; + return _instance; + } + + public: + + // for section + Vector section_stress = Vector(3); + Vector section_strain = Vector(3); + Matrix section_tangent = Matrix(3, 3); + + // for element + Vector element_RHS = Vector(6); + Vector element_RHS_local = Vector(6); + Matrix element_LHS = Matrix(6, 6); + Matrix element_LHS_local = Matrix(6, 6); + Matrix element_T = Matrix(6, 6); + Vector element_U = Vector(6); + Vector element_U_commit = Vector(6); + Vector element_U_local = Vector(6); + Vector element_U_local_commit = Vector(6); + Matrix element_B = Matrix(3, 6); + Matrix element_TtK = Matrix(6, 6); + Matrix element_BtC = Matrix(6, 3); + Vector element_dU = Vector(6); + + // for RVE + Vector rve_dU = Vector(7); + Vector rve_R = Vector(7); + Matrix rve_K = Matrix(7, 7); + Vector rve_Kcr = Vector(7); + Vector rve_Krc = Vector(7); + Vector rve_Kinv_Kcr = Vector(7); + Vector rve_dU_el = Vector(10); + Vector rve_R_el = Vector(10); + Matrix rve_K_el = Matrix(10, 10); + Vector rve_Kcr_el = Vector(10); + Vector rve_Krc_el = Vector(10); + Vector rve_Kinv_Kcr_el = Vector(10); + double rve_Krr = 0.0; + double rve_Kred = 0.0; + // node positions (to be set at each setTrialStrain) + std::array rve_nodes = { V2D(0.0, 0.0), V2D(0.0, 0.0), V2D(0.0, 0.0), V2D(0.0, 0.0) }; + inline void setRVENodes(double lch) { + double dy = lch / 3.0; + for (int i = 0; i < 4; ++i) { + auto& ip = rve_nodes[i]; + ip.y = dy * static_cast(i); // from bottom to top, bottom at 0,0 + ip.x = ip.y * 1.0e-3; // add imperfection + } + } + std::array rve_nodes_el = { V2D(0.0, 0.0), V2D(0.0, 0.0), V2D(0.0, 0.0), V2D(0.0, 0.0), V2D(0.0, 0.0) }; + inline void setRVENodes_el(double lch, double length_el) { + double dy = lch / 3.0; + double y_el = (length_el - lch); + for (int i = 1; i < 5; ++i) { + auto& ip = rve_nodes_el[i]; + ip.y = dy * static_cast(i-1) + y_el; // from bottom to top, bottom at 0,0 + ip.x = ip.y * 1.0e-3; // add imperfection + } + rve_nodes_el[0].y = 0.0; + rve_nodes_el[0].x = 0.0; + } + }; + + /** + Basic steel component. + */ + class SteelComponent + { + public: + using param_t = ASDSteel1DMaterial::InputParameters; + SteelComponent() = default; + int serializationDataSize() const; + void serialize(Vector& data, int& pos); + void deserialize(Vector& data, int& pos); + inline int commitState() { + // store the previously committed variables for next move from n to n - 1 + lambda_commit_old = lambda_commit; + // state variables + epl_commit = epl; + alpha1_commit = alpha1; + alpha2_commit = alpha2; + lambda_commit = lambda; + strain_commit = strain; + stress_commit = stress; + // done + return 0; + } + inline void revertToLastCommit() { + // state variables + epl = epl_commit; + alpha1 = alpha1_commit; + alpha2 = alpha2_commit; + lambda = lambda_commit; + strain = strain_commit; + stress = stress_commit; + } + inline void revertToStart() { + // state variables + epl = 0.0; + epl_commit = 0.0; + alpha1 = 0.0; + alpha1_commit = 0.0; + alpha2 = 0.0; + alpha2_commit = 0.0; + lambda = 0.0; + lambda_commit = 0.0; + lambda_commit_old = 0.0; + sg_commit = 0.0; + // strain, stress and tangent + strain = 0.0; + strain_commit = 0.0; + stress = 0.0; + stress_commit = 0.0; + } + inline int compute(const param_t& params, bool do_implex, double time_factor, double _strain, double& sigma, double& tangent) { + int retval = 0; + // settings + constexpr int MAX_ITER = 1000; + constexpr double F_REL_TOL = 1.0e-6; + constexpr double L_ABS_TOL = 1.0e-8; + // base steel response + alpha1 = alpha1_commit; + alpha2 = alpha2_commit; + lambda = lambda_commit; + epl = epl_commit; + // elastic predictor + strain = _strain; + double dstrain = strain - strain_commit; + sigma = stress_commit + params.E * dstrain; + tangent = params.E; + // plastic utilities + double sg = 0.0; // plastic flow direction + auto lam_rel_stress = [this, &sigma]() -> double { + return sigma - alpha1 - alpha2; + }; + auto lam_yield_function = [¶ms, &lam_rel_stress]() -> double { + return std::abs(lam_rel_stress()) - params.sy; + }; + auto lam_yield_derivative = [this, &lam_rel_stress, ¶ms](double dlambda) -> double { + // plastic flow direction + double sg = sign(lam_rel_stress()); + // d stress / d lambda + double dsigma = -params.E * sg; + // d backstress / d lambda + double dalpha1 = params.H1 * sg - params.gamma1 * alpha1; + double dalpha2 = params.H2 * sg - params.gamma2 * alpha2; + return sg * (dsigma - dalpha1 - dalpha2); + }; + auto lam_yield_update = [this, &sigma, &lam_rel_stress, ¶ms](double dlambda, double delta_lambda) { + // plastic flow direction + double sg = sign(lam_rel_stress()); + // update stress + sigma -= sg * dlambda * params.E; + // update backstress + alpha1 = sg * params.H1 / params.gamma1 - (sg * params.H1 / params.gamma1 - alpha1_commit) * std::exp(-params.gamma1 * delta_lambda); + alpha2 = sg * params.H2 / params.gamma2 - (sg * params.H2 / params.gamma2 - alpha2_commit) * std::exp(-params.gamma2 * delta_lambda); + }; + // plastic corrector + if (params.implex && do_implex) { + // extrapolate plastic flow direction + sg = sg_commit; + // extrapolate lambda + // xn + time_factor * (xn - xnn); + double delta_lambda = time_factor * (lambda_commit - lambda_commit_old); + lambda = lambda_commit + delta_lambda; + // update plastic strain + if (sg > 0.0) + epl = epl_commit + sg * delta_lambda; + // update stress + sigma -= sg * delta_lambda * params.E; + // update backstress + alpha1 = sg * params.H1 / params.gamma1 - (sg * params.H1 / params.gamma1 - alpha1_commit) * std::exp(-params.gamma1 * delta_lambda); + alpha2 = sg * params.H2 / params.gamma2 - (sg * params.H2 / params.gamma2 - alpha2_commit) * std::exp(-params.gamma2 * delta_lambda); + } + else { + // standard implicit evaluation of lambda + double F = lam_yield_function(); + if (F > 0.0) { + double delta_lambda = 0.0; + double dlambda = 0.0; + bool converged = false; + for (int niter = 0; niter < MAX_ITER; ++niter) { + // form tangent + double dF = lam_yield_derivative(dlambda); + if (dF == 0.0) break; + // solve for dlambda + dlambda = -F / dF; + delta_lambda += dlambda; + // update plastic multiplier increment and sigma + lam_yield_update(dlambda, delta_lambda); + // update residual + F = lam_yield_function(); + // check convergence + if (std::abs(F) < F_REL_TOL * params.sy && std::abs(dlambda) < L_ABS_TOL) { + converged = true; + sg = sign(lam_rel_stress()); + // update plastic multiplier + lambda += delta_lambda; + // update plastic strain + if (sg > 0.0) + epl += sg * delta_lambda; + // compute tangent + double PE = + params.gamma1 * (params.H1 / params.gamma1 - sg * alpha1) + + params.gamma2 * (params.H2 / params.gamma2 - sg * alpha2); + tangent = params.K_alpha*((params.E * PE) / (params.E + PE))+(1-params.K_alpha)*params.E; //tangent correction (K_alpha =1 -> computed tangent, K_alpha=0 -> tangent=E) + break; + } + } + if (!converged) { + asd_print("dlambda !converged"); + retval = -1; + } + } + } + // accept solution + stress = sigma; + // save real plastic flow direction, if mp.implex and !do_implex -> called from commit + if (params.implex && !do_implex) { + // save it in implex mode during implicit phase + sg_commit = sg; + } + // done + return retval; + } + + public: + // state variables - backstresses + double alpha1 = 0.0; + double alpha1_commit = 0.0; + double alpha2 = 0.0; + double alpha2_commit = 0.0; + // positive plastic strain (for fracture) + double epl = 0.0; + double epl_commit = 0.0; + // state variables - plastic multiplier + double lambda = 0.0; + double lambda_commit = 0.0; + double lambda_commit_old = 0.0; // for implex + double sg_commit = 0.0; // plastic flow dir for implex + // strain, stress and tangent + double strain = 0.0; + double strain_commit = 0.0; + double stress = 0.0; + double stress_commit = 0.0; + // methods + static constexpr int NDATA = 14; + }; + int SteelComponent::serializationDataSize() const + { + return NDATA; //= 14 + } + + void SteelComponent::serialize(Vector& data, int& pos) + { + data(pos++) = epl; + data(pos++) = epl_commit; + data(pos++) = alpha1; + data(pos++) = alpha1_commit; + data(pos++) = alpha2; + data(pos++) = alpha2_commit; + data(pos++) = lambda; + data(pos++) = lambda_commit; + data(pos++) = lambda_commit_old; + data(pos++) = sg_commit; + data(pos++) = strain; + data(pos++) = strain_commit; + data(pos++) = stress; + data(pos++) = stress_commit; + } + + void SteelComponent::deserialize(Vector& data, int& pos) + { + epl = data(pos++); + epl_commit = data(pos++); + alpha1 = data(pos++); + alpha1_commit = data(pos++); + alpha2 = data(pos++); + alpha2_commit = data(pos++); + lambda = data(pos++); + lambda_commit = data(pos++); + lambda_commit_old = data(pos++); + sg_commit = data(pos++); + strain = data(pos++); + strain_commit = data(pos++); + stress = data(pos++); + stress_commit = data(pos++); + } + /* + Series component. + */ + class SeriesComponent + { + public: + double lch_anchor = 0.0; + SteelComponent steel_material; + UniaxialMaterial* slip_material = nullptr; + int serializationDataSize() const; + void serialize(Vector& data, int& pos, int commitTag, Channel& theChannel); + void deserialize(Vector& data, int& pos, int commitTag, Channel& theChannel, FEM_ObjectBroker& theBroker); + void serialize_slip(int commitTag, Channel& theChannel); + void deserialize_slip(int commitTag, Channel& theChannel, FEM_ObjectBroker& theBroker); + + public: + using param_t = ASDSteel1DMaterial::InputParameters; + inline void initialize_lch_anchor(const param_t& params) { + if (lch_anchor == 0.0) { + lch_anchor = lch_anchor_compute(params); + if (slip_material) { + if (params.auto_regularization) { + // if the slip material supports the lch_ref parameter, let's set it to the anchorage length + Parameter lch_param(0, 0, 0, 0); + const char* the_args[] = { "lch_ref" }; + if (slip_material->setParameter(the_args, 1, lch_param) != -1) { + lch_param.update(lch_anchor); + } + } + } + } + } + SeriesComponent() = default; + SeriesComponent(const SeriesComponent& c) + : steel_material(c.steel_material) + , slip_material(nullptr) + { + setSlipMaterial(c.slip_material); + } + ~SeriesComponent() { + if (slip_material) + delete slip_material; + } + + inline int commitState() { + // store the previously committed variables for next move from n to n - 1 + + // state variables + + int retval = 0; + + retval = steel_material.commitState(); + + if (slip_material) + retval = slip_material->commitState(); + + // done + return retval; + } + inline void revertToLastCommit() { + // state variables + steel_material.revertToLastCommit(); + + if (slip_material) + slip_material->revertToLastCommit(); + + } + inline void revertToStart() { + // state variables + steel_material.revertToStart(); + + if (slip_material) + slip_material->revertToStart(); + + } + inline double lch_anchor_compute(const param_t& params) { + //lch_anchor estimation + + // compute the gradient + double max_slip = params.radius * 100.0; + double tol = params.sy * 1.0e-6; + auto compute_gradient = [&](double slip) { + double epsilon = max_slip * 1.0e-8; + slip_material->setTrialStrain(slip); + slip_material->commitState(); + double stress_0 = slip_material->getStress(); + slip_material->revertToStart(); + slip_material->setTrialStrain(slip + epsilon); + slip_material->commitState(); + double stress_1 = slip_material->getStress(); + slip_material->revertToStart(); + double K = (stress_1 - stress_0) / epsilon; + if (std::abs(K) < tol) + K = 0.0; + return K; + }; + + double X0 = 0.0; + double Y0 = compute_gradient(X0); + double S0 = sign(Y0); + double X1 = max_slip; + double Y1 = compute_gradient(X1); + double S1 = sign(Y1); + double XM = (X1 + X0)/2.0; + bool found_peak = false; + for (int i = 0; i < 20; i++) { + double YM = compute_gradient(XM); + double SM = sign(YM); + if (S0 != SM) { + X1 = XM; + Y1 = YM; + S1 = SM; + found_peak = true; + } + else if (SM != S1) { + X0 = XM; + Y0 = YM; + S0 = SM; + found_peak = true; + } + else { + opserr << "Failed " << S0 << ", " << SM << ", " << S1 << "\n"; + break; + } + XM = (X1 + X0) / 2.0; + } + + double tau_max = 0.0; + double lch_anchor = 0.0; + if (found_peak) { + slip_material->setTrialStrain(XM); + slip_material->commitState(); + tau_max = slip_material->getStress(); + slip_material->revertToStart(); + + lch_anchor = (params.sy * params.radius) / (2.0 * tau_max); + } + else { + opserr << "No peak found — using default lch_anchor\n"; + lch_anchor = 80.0 * params.radius; + } + return lch_anchor; + } + inline int compute(const param_t& params, bool do_implex, double time_factor, double _strain, double& sigma, double& tangent) { + if (slip_material) { + + initialize_lch_anchor(params); + + // compute series response + constexpr int MAX_ITER = 100; + constexpr double TOL = 1e-6; + double scale_factor = 1.0; + // if in RVE for buckling, only 1 element has the slip material (1/3 of the rve length) + if (params.buckling) { + if (params.lch_element > params.length) { + scale_factor = params.length / (3.0 * params.lch_element); + } + else { + scale_factor = 1.0 / 3.0; + } + } + + _strain *= scale_factor; + + // initial guess for the slip strain + double lch_ele = 2.0 * params.lch_element; // it was divided in constructor for RVE symmetry + double strain_slip = slip_material->getStrain() / lch_anchor; + double strain_steel = _strain - strain_slip; + + // iterative procedure to impose the iso-stress condition + double sigma_steel; + double tangent_steel; + double Ktol = 1.0e-12 * params.E; + double Rtol = TOL * params.sy; + double Stol = TOL; + for (int iter = 0; iter < MAX_ITER; ++iter) { + int Tsteel = steel_material.compute(params, do_implex, time_factor, strain_steel, sigma_steel, tangent_steel); + int Tslip = slip_material->setTrialStrain(strain_slip * lch_anchor); + double sigma_slip = slip_material->getStress() * 2.0 * lch_anchor/ params.radius; + double tangent_slip = slip_material->getTangent() * 2.0 * lch_anchor *lch_anchor / params.radius; + double residual = sigma_slip - sigma_steel; + double residual_derivative = tangent_steel + tangent_slip; + if (std::abs(residual_derivative) < Ktol) { + residual_derivative = params.E + slip_material->getInitialTangent() * 2.0 * lch_anchor * lch_anchor / params.radius; + } + double strain_increment = - residual / residual_derivative; + strain_slip += strain_increment; + strain_steel = _strain - strain_slip; + + if (std::abs(residual) < Rtol || std::abs(strain_increment) < Stol) { + sigma = sigma_steel; + if (std::abs(tangent_steel) < Ktol) tangent_steel = Ktol; + if (std::abs(tangent_slip) < Ktol) tangent_slip = Ktol; + tangent = scale_factor * 1.0 / (1.0 / tangent_steel + 1.0 / tangent_slip); + asd_print("iter: " << iter); + return 0; + } + } + asd_print_full("series failed"); + return -1; + } + else { + return steel_material.compute(params, do_implex, time_factor, _strain, sigma, tangent); + } + } + + inline void setSlipMaterial(UniaxialMaterial* prototype) { + if (slip_material) { + delete slip_material; + slip_material = nullptr; + } + if (prototype) { + slip_material = prototype->getCopy(); + asd_print("setting slip material: " << slip_material->getClassType()); + } + } + + }; + int SeriesComponent::serializationDataSize() const + { + return 3 + steel_material.serializationDataSize(); + } + + void SeriesComponent::serialize(Vector& data, int& pos, int commitTag, Channel& theChannel) + { + steel_material.serialize(data, pos); + if (slip_material) { + data(pos++) = static_cast(slip_material->getClassTag()); + int mat_db_tag = slip_material->getDbTag(); + if (mat_db_tag == 0) { + mat_db_tag = theChannel.getDbTag(); + if (mat_db_tag != 0) + slip_material->setDbTag(mat_db_tag); + } + data(pos++) = static_cast(mat_db_tag); + data(pos++) = lch_anchor; + } + else { + data(pos++) = -1.0; // classTag + data(pos++) = -1.0; // dbTag + data(pos++) = -1.0; //lch_anchor + } + } + + void SeriesComponent::deserialize(Vector& data, int& pos, int commitTag, Channel& theChannel, FEM_ObjectBroker& theBroker) { + steel_material.deserialize(data, pos); + if (slip_material) { + delete slip_material; + slip_material = nullptr; + } + int classTag = static_cast(data(pos++)); + int mat_db_tag = static_cast(data(pos++)); + if (classTag >= 0) { + UniaxialMaterial* new_slip_material = theBroker.getNewUniaxialMaterial(classTag); + if (!new_slip_material) { + opserr << "SeriesComponent::deserialize - failed to get new UniaxialMaterial from broker\n"; + return; + } + new_slip_material->setDbTag(mat_db_tag); + slip_material = new_slip_material; + } + lch_anchor = data(pos++); + + } + + void SeriesComponent::serialize_slip(int commitTag, Channel& theChannel) + { + if (slip_material) { + int send_result = slip_material->sendSelf(commitTag, theChannel); + if (send_result < 0) { + opserr << "SeriesComponent:: serialize - failed to send slip material \n"; + } + } + } + + void SeriesComponent::deserialize_slip(int commitTag, Channel& theChannel, FEM_ObjectBroker& theBroker) { + + if (slip_material) { + if (slip_material->recvSelf(commitTag, theChannel, theBroker) < 0) { + opserr << "SeriesComponent::deserialize - failed to receive slip material\n"; + delete slip_material; + slip_material = nullptr; + return; + } + } + } + + /** + Section component. + */ + template + class SectionComponent + { + private: + SectionComponent() = delete; + public: + inline int serializationDataSize() const { return 0; } + inline void serialize(Vector& data, int& pos) {} + inline void deserialize(Vector& data, int& pos) {} + }; + + /** + Section component with 1 fiber. + */ + template<> + class SectionComponent<1> + { + public: + SeriesComponent series; + + public: + SectionComponent() = default; + + inline int commitState() { + return series.commitState(); + } + inline void revertToLastCommit() { + series.revertToLastCommit(); + } + inline void revertToStart() { + series.revertToStart(); + } + inline int compute( + const ASDSteel1DMaterial::InputParameters& params, const Vector& strain, + bool do_implex, double time_factor, + Vector& stress, Matrix& tangent) { + /** + A section with 1 fiber is used for the central element. In this RVE model the + central element has always zero curvature. However, with only 1 fiber the bending + stiffness will be zero, so we use closed-form evaluation of the bending stiffness. + Note also that M = EI*curvature for newton iterations! + */ + double constexpr poiss = 0.3; // built-in poisson ratio + double constexpr kshear = 0.9; // built-in shear correction factor for circular sections + // area + double area = M_PI * params.radius * params.radius; + // compute elastic shear response + double G = params.E / (2.0 * (1.0 + poiss)); + double GAk = G * area * kshear; + tangent(2, 2) = GAk; + stress(2) = GAk * strain(2); + // compute elastic M response (will be zero upon convergence for this model) + double I = M_PI * std::pow(params.radius, 4) / 4.0; + double EI = params.E * I; + stress(1) = EI * strain(1); + tangent(1, 1) = EI; + // nonlinear P reponse + double fiber_stress; + double fiber_tangent; + int retval; + retval = series.compute(params, do_implex, time_factor, strain(0), fiber_stress, fiber_tangent); + + double fiber_force = fiber_stress * area; + stress(0) = fiber_force; + tangent(0, 0) = fiber_tangent * area; + // zero terms + tangent(0, 1) = tangent(1, 0) = tangent(0, 2) = tangent(2, 0) = tangent(1, 2) = tangent(2, 1) = 0.0; + // done + return retval; + } + inline void setSlipMaterial(UniaxialMaterial* prototype) + { + series.setSlipMaterial(prototype); + } + + inline int serializationDataSize() const { return series.steel_material.serializationDataSize(); } + inline void serialize(Vector& data, int& pos) { series.steel_material.serialize(data, pos); } + inline void deserialize(Vector& data, int& pos) { series.steel_material.deserialize(data, pos); } + }; + + /** + Section component with 3 fibers. + */ + template<> + class SectionComponent<3> + { + public: + std::array fibers; + static constexpr std::array positions = { -1.0 / 2.0, 0.0, 1.0 / 2.0 }; + static constexpr std::array weights = { 1.0 / 4.0, 1.0 / 2.0, 1.0 / 4.0 }; + + public: + SectionComponent() = default; + inline int commitState() { + int retval = 0; + for (auto& item : fibers) { + int fiber_retval = item.commitState(); + if (fiber_retval != 0) + retval = fiber_retval; + } + return retval; + } + inline void revertToLastCommit() { + for (auto& item : fibers) item.revertToLastCommit(); + } + inline void revertToStart() { + for (auto& item : fibers) item.revertToStart(); + } + inline int compute( + const ASDSteel1DMaterial::InputParameters& params, const Vector& strain, + bool do_implex, double time_factor, + Vector& stress, Matrix& tangent) { + /** + A section with 3 fibers. + */ + double constexpr poiss = 0.3; // built-in poisson ratio + double constexpr kshear = 0.9; // built-in shear correction factor for circular sections + // area + double area = M_PI * params.radius * params.radius; + // zero P-M components for integration + stress.Zero(); + tangent.Zero(); + // compute elastic shear response + double G = params.E / (2.0 * (1.0 + poiss)); + double GAk = G * area * kshear; + tangent(2, 2) = GAk; + stress(2) = GAk * strain(2); + // integrate nonlinear P-M response + for (int i = 0; i < fibers.size(); ++i) { + double fiber_pos = positions[i] * params.radius; + double fiber_area = weights[i] * area; + double fiber_strain = strain(0) - strain(1) * fiber_pos; + double fiber_stress; + double fiber_tangent; + int retval = fibers[i].compute(params, do_implex, time_factor, fiber_strain, fiber_stress, fiber_tangent); + if (retval != 0) + return retval; + double fiber_force = fiber_stress * fiber_area; + stress(0) += fiber_force; + stress(1) -= fiber_force * fiber_pos; + + double EtA = fiber_tangent * fiber_area; + double ya = fiber_pos * EtA; + tangent(0, 0) += EtA; + tangent(0, 1) -= ya; + tangent(1, 0) -= ya; + tangent(1, 1) += ya * fiber_pos; + } + // done + return 0; + } + inline int serializationDataSize() const { + return fibers[0].serializationDataSize() + + fibers[1].serializationDataSize() + + fibers[2].serializationDataSize(); + } + inline void serialize(Vector& data, int& pos) { + for (int i = 0; i < fibers.size(); ++i) { + fibers[i].serialize(data, pos); + } + } + inline void deserialize(Vector& data, int& pos) { + for (int i = 0; i < fibers.size(); ++i) { + fibers[i].deserialize(data, pos); + } + } + }; + + /** + Element Traits: + - 4 nodes - 3 elements RVE + - total number of DOFs = 12 + - free DOFs = 7 + - bottom node - Ux = 0, Uy = macro_strain*L, Rz = 0 + - top node - Uy = 0, Rz = 0 + + logic: + for each dof in DOFs: + if dof < 7 + U_dof = URVE(dof) + else if dof == 8: + U_dof = RY + else + U_dof = 0.0 + + */ + + constexpr int EType_Bot = 1; + constexpr int EType_Mid = 2; + constexpr int EType_Top = 3; + constexpr int EType_El = 0; + template + class ETypeTraits + { + }; + template<> + class ETypeTraits + { + public: + static constexpr std::array DOFs = {8,7,9, 0,1,2 }; + static constexpr int N1 = 1; + static constexpr int N2 = 2; + }; + template<> + class ETypeTraits + { + public: + static constexpr std::array DOFs = { 0,1,2, 3,4,5 }; + static constexpr int N1 = 2; + static constexpr int N2 = 3; + }; + template<> + class ETypeTraits + { + public: + static constexpr std::array DOFs = { 3,4,5, 6,10,11 }; + static constexpr int N1 = 3; + static constexpr int N2 = 4; + }; + template<> + class ETypeTraits + { + public: + static constexpr std::array DOFs = { 12,13,14, 8,7,9 }; + static constexpr int N1 = 0; + static constexpr int N2 = 1; + }; + template + inline void getElementDisplacementVector(const ASDSteel1DMaterial::InputParameters& params, bool elastic_correction, const Vector& G, Vector& L) { + // G = global vector, size = 8 -> full = 12, semi-full 8 (7 free + 1 Uy imposed) + // L = local vector , size = 6 + if (elastic_correction && params.auto_regularization) { + for (int i = 0; i < 6; ++i) { + int gdof = ETypeTraits::DOFs[i]; + if (gdof < 10 ) { + L(i) = G(gdof); + + } + else if (gdof == 13) { + L(i) = G(10); + } + else { + L(i) = 0.0; + } + } + } + else { + for (int i = 0; i < 6; ++i) { + int gdof = ETypeTraits::DOFs[i]; + L(i) = gdof < 8 ? G(gdof) : 0.0; + } + } + } + template + inline void assembleRHS(const ASDSteel1DMaterial::InputParameters& params, bool elastic_correction, const Vector& L, Vector& G) { + // G = global vector, size = 7 (-> full = 12, semi-full 8 (7 free + 1 Uy imposed) only free) + // L = local vector , size = 6 + if (elastic_correction && params.auto_regularization) { + for (int i = 0; i < 6; ++i) { + int gdof = ETypeTraits::DOFs[i]; + if (gdof < 10) { + G(gdof) += L(i); + } + } + } + else { + for (int i = 0; i < 6; ++i) { + int gdof = ETypeTraits::DOFs[i]; + if (gdof < 7) { + G(gdof) += L(i); + } + } + } + } + template + inline void assembleLHS(const ASDSteel1DMaterial::InputParameters& params, bool elastic_correction, const Matrix& M, Matrix& G) { + // G = global matrix, size = 7x7 -> full = 12x12, semi-full 8 (7 free + 1 Uy imposed) + // L = local vector , size = 6 + // M = local matrix , size = 6x6 + if (elastic_correction && params.auto_regularization) { + for (int i = 0; i < 6; ++i) { + int idof = ETypeTraits::DOFs[i]; + if (idof < 10) { + for (int j = 0; j < 6; ++j) { + int jdof = ETypeTraits::DOFs[j]; + if (jdof < 10) { + G(idof, jdof) += M(i, j); + } + } + } + } + } + else { + for (int i = 0; i < 6; ++i) { + int idof = ETypeTraits::DOFs[i]; + if (idof < 7) { + for (int j = 0; j < 6; ++j) { + int jdof = ETypeTraits::DOFs[j]; + if (jdof < 7) { + G(idof, jdof) += M(i, j); + } + } + } + } + } + + } + template + inline void getRetainedComponents(const ASDSteel1DMaterial::InputParameters& params,bool elastic_correction, const Matrix& M, double& Krr, Vector& Kcr, Vector& Krc) { + if (elastic_correction && params.auto_regularization) { + for (int i = 0; i < 6; ++i) { + int idof = ETypeTraits::DOFs[i]; + for (int j = 0; j < 6; ++j) { + int jdof = ETypeTraits::DOFs[j]; + if (idof == 13) { + if (jdof == 13) { + Krr = M(i, j); + } + else if (jdof < 10) { //it is used to assemble krc and kcr for the bottom element -> jdof will be always < 3 + Krc(jdof) = M(i, j); + } + } + else if (jdof == 13 && idof < 10) { + Kcr(idof) = M(j, i); + } + } + } + } + else { + for (int i = 0; i < 6; ++i) { + int idof = ETypeTraits::DOFs[i]; + for (int j = 0; j < 6; ++j) { + int jdof = ETypeTraits::DOFs[j]; + if (idof == 7) { + if (jdof == 7) { + Krr = M(i, j); + } + else if (jdof < 7) { //it is used to assemble krc and kcr for the bottom element -> jdof will be always < 3 + Krc(jdof) = M(i, j); + } + } + else if (jdof == 7 && idof < 7) { + Kcr(idof) = M(j, i); + } + } + } + } + } + + inline M2D computeLocalFrameInternal(const V2D& X1, const V2D& X2, Q2D& Qi, V2D& C) { + C = (X1 + X2) * 0.5; + V2D dx = X2 - X1; + double L = dx.normalize(); + V2D dy(-dx.y, dx.x); + M2D Ri(dx, dy); + Qi = Q2D::fromRotationMatrix(Ri); + return Ri; + } + + inline void computeLocalFrame(const V2D& X1, const V2D& X2, Q2D& Qi, V2D& C) { + computeLocalFrameInternal(X1, X2, Qi, C); + } + inline void computeLocalFrame(const V2D& X1, const V2D& X2, Q2D& Qi, V2D& C, Matrix& T) { + M2D Ri = computeLocalFrameInternal(X1, X2, Qi, C); + //T matrix : considering P_t @ R + for (int i = 0; i < 2;++i) { + for (int j = 0; j < 2;++j) { + T(i, j) = T(i + 3, j + 3) = Ri(i, j) / 2.0; + T(i, j + 3) = T(i + 3, j) = -Ri(i, j) / 2.0; + } + } + T(2,2) = T(5,5) = 1.0; + } + inline void computeLocalFrameLinearKin(const V2D& X1, const V2D& X2, Q2D& Qi, V2D& C, Matrix& T) { + M2D Ri = computeLocalFrameInternal(X1, X2, Qi, C); + //T matrix : R + for (int i = 0; i < 2;++i) { + for (int j = 0; j < 2;++j) { + T(i, j) = T(i + 3, j + 3) = Ri(i, j); + T(i, j + 3) = T(i + 3, j) = 0.0; + } + } + T(2, 2) = T(5, 5) = 1.0; + } + + inline void computeBmatrix(const V2D& X1, const V2D& X2, double& L,Matrix& B) { + V2D dx = X2 - X1; + L = dx.normalize(); + B(0,0) = B(1,2) = B(2,1) = -1.0 / L; + B(0,3) = B(1,5) = B(2,4) = 1.0 / L; + B(2,2) = B(2,5) = -1.0 / 2.0; + } + + class RVEStateVariables + { + public: + Vector UG = Vector(8); + Vector UG_commit = Vector(8); + Vector UG_el = Vector(11); + Vector UG_el_commit = Vector(11); + + int serializationDataSize() const; + void serialize(Vector& data, int& pos); + void deserialize(Vector& data, int& pos); + }; + int RVEStateVariables::serializationDataSize() const + { + return 38; + } + + void RVEStateVariables::serialize(Vector& data, int& pos) + { + for (int i = 0; i < 8; ++i) data(pos++) = UG[i]; + for (int i = 0; i < 8; ++i) data(pos++) = UG_commit[i]; + for (int i = 0; i < 11; ++i) data(pos++) = UG_el[i]; + for (int i = 0; i < 11; ++i) data(pos++) = UG_el_commit[i]; + } + void RVEStateVariables::deserialize(Vector& data, int& pos) + { + for (int i = 0; i < 8; ++i) UG[i] = data(pos++); + for (int i = 0; i < 8; ++i) UG_commit[i] = data(pos++); + for (int i = 0; i < 11; ++i) UG_el[i] = data(pos++); + for (int i = 0; i < 11; ++i) UG_el_commit[i] = data(pos++); + } + + /** + Element component. + */ + template + class ElementComponent + { + public: + SectionComponent section; + Vector UL_commit = Vector(6); + std::array qn = { Q2D::identity(), Q2D::identity()}; + std::array qn_commit = { Q2D::identity(), Q2D::identity() }; + V2D rn = V2D(0.0, 0.0); + V2D rn_commit = V2D(0.0, 0.0); + + int serializationDataSize() const; + void serialize(Vector& data, int& pos); + void deserialize(Vector& data, int& pos); + + + ElementComponent() = default; + + inline int compute(bool elastic_correction, const RVEStateVariables& rve, const ASDSteel1DMaterial::InputParameters& params, bool do_implex, double time_factor ) { + + // get global variables + auto& globals = Globals::instance(); + auto& U = globals.element_U; + auto& U_commit = globals.element_U_commit; + auto& UL = globals.element_U_local; + auto& dU = globals.element_dU; + auto& B = globals.element_B; + auto& T = globals.element_T; + auto& RHS = globals.element_RHS; + auto& RHSL = globals.element_RHS_local; + auto& LHS = globals.element_LHS; + auto& LHSL = globals.element_LHS_local; + auto& BtC = globals.element_BtC; + auto& TtK = globals.element_TtK; + auto& stress_s = globals.section_stress; + auto& strain_s = globals.section_strain; + auto& tangent_s = globals.section_tangent; + auto& rve_nodes = globals.rve_nodes; + auto& rve_nodes_el = globals.rve_nodes_el; + + // determine node numbering (changes for elastic correction) + int inode; + int jnode; + if (elastic_correction && params.auto_regularization) { + inode = ETypeTraits::N1; + jnode = ETypeTraits::N2; + } + else { + inode = ETypeTraits::N1-1; + jnode = ETypeTraits::N2-1; + } + + // obtain global displacement vectors (size changes for elastic correction) + if (elastic_correction && params.auto_regularization) { + getElementDisplacementVector(params, elastic_correction, rve.UG_el, U); + getElementDisplacementVector(params, elastic_correction, rve.UG_el_commit, U_commit); + } + else { + getElementDisplacementVector(params, elastic_correction, rve.UG, U); + getElementDisplacementVector(params, elastic_correction, rve.UG_commit, U_commit); + } + + + // undeformed nodes + V2D node_i; + V2D node_j; + if (elastic_correction && params.auto_regularization) { + node_i = rve_nodes_el[inode]; + node_j = rve_nodes_el[jnode]; + } + else { + node_i = rve_nodes[inode]; + node_j = rve_nodes[jnode]; + } + + // current orientation and center + Q2D Q; + V2D C; + if (EType == EType_El) { + + // use linear kinematics + computeLocalFrameLinearKin(node_i, node_j, Q, C, T); // undeformed nodes + UL.addMatrixVector(0.0, T, U, 1.0); + } + else { + + // use nonlinear (corotational) kinematics + + if (!do_implex) { + + // computed deformed node position + V2D deformed_node_i = node_i + V2D(U(0), U(1)); + V2D deformed_node_j = node_j + V2D(U(3), U(4)); + + // compute local frame in current configuration + computeLocalFrame(deformed_node_i, deformed_node_j, Q, C, T); + + // compute also local frame in the undeformed configuration + Q2D Q0; + V2D C0; + computeLocalFrame(node_i, node_j, Q0, C0); + + V2D rn_current = V2D(U(2), U(5)); // rotation at current iteration + V2D dtheta = rn_current - rn; // iterative correction + rn = rn_current; // save current for next iteration + for (int i = 0; i < 2; ++i) { + qn[i] = Q2D::fromRotationVector(dtheta(i)) * qn[i]; // increment quaterion from previous iteration + } + + //position vectors in local reference frame + V2D rf_node1_position = Q0.rotateVector(node_i - C0); + V2D rf_node2_position = Q0.rotateVector(node_j - C0); + + //deformed position vectors in local current frame + V2D cf_node1_deformed = Q.rotateVector(deformed_node_i - C); + V2D cf_node2_deformed = Q.rotateVector(deformed_node_j - C); + + // translational part of deformational local displacements + UL(0) = cf_node1_deformed.x - rf_node1_position.x; + UL(1) = cf_node1_deformed.y - rf_node1_position.y; + UL(3) = cf_node2_deformed.x - rf_node2_position.x; + UL(4) = cf_node2_deformed.y - rf_node2_position.y; + + // rotational part of deformational local rotation + UL(2) = (Q * qn[0] * Q0.conjugate()).toRotationVector(); + UL(5) = (Q * qn[1] * Q0.conjugate()).toRotationVector(); + } + else { + + // computed deformed node position with committed displacement + V2D deformed_node_i_old = node_i + V2D(U_commit(0), U_commit(1)); + V2D deformed_node_j_old = node_j + V2D(U_commit(3), U_commit(4)); + + // compute local frame in deformed committed configuration + computeLocalFrame(deformed_node_i_old, deformed_node_j_old, Q, C, T); + + // transform only the incremental part with this explicit approximation + dU = U; + dU.addVector(1.0, U_commit, -1.0); + UL = UL_commit; + UL.addMatrixVector(1.0, T, dU, 1.0); + } + + } + + // strain-displacement matrix in local frame + double L = 0.0; + computeBmatrix(node_i, node_j, L, B); //rve nodes + + // section strain = B*U + strain_s.addMatrixVector(0.0, B, UL, 1.0); + int retval; + + retval = section.compute(params, strain_s, do_implex, time_factor, stress_s, tangent_s); + + + if (retval != 0) { + asd_print_full("section !converged"); + return retval; + } + + // RHS + RHSL.addMatrixTransposeVector(0.0, B, stress_s, L); + RHS.addMatrixTransposeVector(0.0, T, RHSL, 1.0); + + // LHS + BtC.addMatrixTransposeProduct(0.0, B, tangent_s, L); + LHSL.addMatrixProduct(0.0, BtC, B, 1.0); + TtK.addMatrixTransposeProduct(0.0, T, LHSL, 1.0); + LHS.addMatrixProduct(0.0, TtK, T, 1.0); + + // SEMI-COMMIT + if (params.implex && !do_implex) { + UL_commit = UL; + } + + return 0; + } + inline int commitState() { + qn_commit = qn; + rn_commit = rn; + return section.commitState(); + } + inline void revertToLastCommit() { + qn = qn_commit; + rn = rn_commit; + section.revertToLastCommit(); + } + inline void revertToStart() { + qn = { Q2D::identity(), Q2D::identity() }; + qn_commit = { Q2D::identity(), Q2D::identity() }; + rn = V2D(0.0, 0.0); + rn_commit = V2D(0.0, 0.0); + UL_commit.Zero(); + section.revertToStart(); + } + + }; + template + inline int ElementComponent::serializationDataSize() const{ + int size = 18 + section.serializationDataSize(); + return size; + } + + template + inline void ElementComponent::serialize(Vector& data, int& pos) { + for (int i = 0; i < 6; ++i) data(pos++) = UL_commit(i); + for (int i = 0; i < 2; ++i) data(pos++) = qn[i].toRotationVector(); + for (int i = 0; i < 2; ++i) data(pos++) = qn_commit[i].toRotationVector(); + data(pos++) = rn.x; + data(pos++) = rn.y; + data(pos++) = rn_commit.x; + data(pos++) = rn_commit.y; + section.serialize(data, pos); + } + + template + inline void ElementComponent::deserialize(Vector& data, int& pos) { + for (int i = 0; i < 6; ++i) UL_commit(i) = data(pos++); + for (int i = 0; i < 2; ++i) qn[i] = Q2D::fromRotationVector(data(pos++)); + for (int i = 0; i < 2; ++i) qn_commit[i] = Q2D::fromRotationVector(data(pos++)); + rn.x = data(pos++); + rn.y = data(pos++); + rn_commit.x = data(pos++); + rn_commit.y = data(pos++); + section.deserialize(data, pos); + } + + template + inline int rve_process_element(bool elastic_correction, ElementComponent& ele, const RVEStateVariables& rve, const ASDSteel1DMaterial::InputParameters& params, bool do_implex, double time_factor) { + int retval = ele.compute(elastic_correction, rve, params, do_implex, time_factor); + if (retval != 0) { + asd_print_full("ele !converged"); + return retval; + } + auto& globals = Globals::instance(); + if (elastic_correction && params.auto_regularization) { + assembleRHS(params, elastic_correction, globals.element_RHS, globals.rve_R_el); + assembleLHS(params, elastic_correction, globals.element_LHS, globals.rve_K_el); + } + else { + + assembleRHS(params, elastic_correction, globals.element_RHS, globals.rve_R); + assembleLHS(params, elastic_correction, globals.element_LHS, globals.rve_K); + } + return 0; + } + + class RVEModel + { + public: + RVEStateVariables sv; + ElementComponent<3, EType_Bot> e1; + ElementComponent<1, EType_Mid> e2; + ElementComponent<3, EType_Top> e3; + ElementComponent<1, EType_El> e0; // nonlinear section (1 fiber), but linear kinematics + int serializationDataSize() const; + void serialize(Vector& data, int& pos); + void deserialize(Vector& data, int& pos); + RVEModel() = default; + + inline void setSlipMaterial(UniaxialMaterial* prototype) { + e2.section.setSlipMaterial(prototype); + } + + inline int compute(bool elastic_correction, const ASDSteel1DMaterial::InputParameters& params, double U, bool do_implex, double time_factor, double& N, double& tangent) { + + // output + int retval = -1; + + // start from previous commited state (not in implex commit) + if (!(params.implex && !do_implex)) { + revertToLastCommit(); + } + + // globals + double tolR = params.tolR * params.sy; + double tolU = params.tolU * params.length; + auto& globals = Globals::instance(); + + // utility for assembly + // note: do it in reverse order, so that we can access the element RHS for element Bottom to get reaction + auto lam_assemble = [this, elastic_correction, &globals, ¶ms, &do_implex, &time_factor]() -> int { + // zero R and K for element integration + globals.rve_R.Zero(); + globals.rve_K.Zero(); + globals.rve_R_el.Zero(); + globals.rve_K_el.Zero(); + if (elastic_correction && params.auto_regularization) { + if (rve_process_element< 3, EType_Top>(elastic_correction, e3, sv, params, do_implex, time_factor) != 0) return -1; + if (rve_process_element< 1, EType_Mid>(elastic_correction, e2, sv, params, do_implex, time_factor) != 0) return -1; + if (rve_process_element< 3, EType_Bot>(elastic_correction, e1, sv, params, do_implex, time_factor) != 0) return -1; + if (rve_process_element< 1, EType_El>(elastic_correction, e0, sv, params, do_implex, time_factor) != 0) return -1; + } + else { + if (rve_process_element< 3, EType_Top>(elastic_correction, e3, sv, params, do_implex, time_factor) != 0) return -1; + if (rve_process_element< 1, EType_Mid>(elastic_correction, e2, sv, params, do_implex, time_factor) != 0) return -1; + if (rve_process_element< 3, EType_Bot>(elastic_correction, e1, sv, params, do_implex, time_factor) != 0) return -1; + double I = M_PI * std::pow(params.radius, 4) / 4.0; + double EI = params.E * I; + double fact = 0.04 * params.length / (params.radius * 5.0); + double penalty = 12.0 * EI * fact / std::pow(2.0*params.length, 3.0); + double KReg; + if (!params.auto_regularization) { + KReg = 0.0; + } + else { + KReg = std::max(0.0, (params.length / params.lch_element - 1)) * penalty; + } + globals.rve_K(6, 6) = globals.rve_K(6, 6) + KReg; + globals.rve_R(6) = globals.rve_R(6) + KReg * sv.UG(6); + } + return 0; + }; + + // impose BC + if (elastic_correction && params.auto_regularization) { + sv.UG_el(10) = U; + } + else { + sv.UG(7) = U; + } + + // first residual + if (lam_assemble() != 0) { + asd_print_full("1lam assemble !=0"); + return -1; + } + + double Rnorm = -1.0; + double Unorm = -1.0; + + //for implicit correction convergence + static std::array U_iterative = { Vector(7), Vector(7), Vector(7), Vector(7), Vector(7), Vector(7), Vector(7), Vector(7), Vector(7), Vector(7)}; + static std::array U_iterative_el = { Vector(10), Vector(10), Vector(10), Vector(10), Vector(10), Vector(10), Vector(10), Vector(10), Vector(10), Vector(10) }; + static std::array Rnorm_iterative = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; + + // newton loop for this step + for (int iter = 0; iter < params.max_iter; ++iter) { + + // solve + if (elastic_correction && params.auto_regularization) { + if (globals.rve_K_el.Solve(globals.rve_R_el, globals.rve_dU_el) != 0) { + asd_print_full("Solve failed"); + break; + } + + // update free DOFs + for (int i = 0; i < 10; ++i) { + sv.UG_el(i) -= globals.rve_dU_el(i); + } + + // assemble + if (lam_assemble() != 0) { + asd_print_full("lam assemble !=0"); + break; + } + + // convergence test + + Rnorm = globals.rve_R_el.Norm(); + Unorm = globals.rve_dU_el.Norm(); + asd_print("iter: " << iter << "R: " << Rnorm << ", U: " << Unorm); + + //for implicit correction convergence (max 10 iterations) + if (params.implex && !do_implex) { + U_iterative_el[iter] = sv.UG_el; + Rnorm_iterative[iter] = Rnorm; + if (iter >= 9) { + auto minRiter = std::min_element(Rnorm_iterative.begin(), Rnorm_iterative.end()); + double minRnorm = *minRiter; + if (!std::isfinite(minRnorm)) { + Rnorm = std::numeric_limits::max(); + } + Rnorm = minRnorm; + asd_print("minRnorm" << minRnorm); + int pos_min = std::distance(Rnorm_iterative.begin(), minRiter); + sv.UG_el = U_iterative_el[pos_min]; + lam_assemble(); + retval = 0; + break; + } + } + + if (Rnorm < tolR || Unorm < tolU) { + retval = 0; + break; + } + } + else { + if (globals.rve_K.Solve(globals.rve_R, globals.rve_dU) != 0) { + asd_print_full("Solve failed"); + break; + } + + // update free DOFs + for (int i = 0; i < 7; ++i) { + sv.UG(i) -= globals.rve_dU(i); + } + + // assemble + if (lam_assemble() != 0) { + asd_print_full("lam assemble !=0"); + break; + } + + // convergence test + + Rnorm = globals.rve_R.Norm(); + Unorm = globals.rve_dU.Norm(); + asd_print("iter: " << iter << "R: " << Rnorm << ", U: " << Unorm); + + //for implicit correction convergence (max 10 iterations) + if (params.implex && !do_implex) { + U_iterative[iter] = sv.UG; + Rnorm_iterative[iter] = Rnorm; + if (iter >= 9) { + auto minRiter = std::min_element(Rnorm_iterative.begin(), Rnorm_iterative.end()); + double minRnorm = *minRiter; + if (!std::isfinite(minRnorm)) { + Rnorm = std::numeric_limits::max(); + } + Rnorm = minRnorm; + asd_print("minRnorm" << minRnorm); + int pos_min = std::distance(Rnorm_iterative.begin(), minRiter); + sv.UG = U_iterative[pos_min]; + lam_assemble(); + retval = 0; + break; + } + } + + if (Rnorm < tolR || Unorm < tolU) { + retval = 0; + break; + } + + } + + } + + if (retval != 0) { + asd_print_full("rve !converged"); + } + double Krc_dot_Kinv_Kcr = 0.0; + // do it outside, element Bottom is the last one + if (elastic_correction && params.auto_regularization) { + getRetainedComponents(params, elastic_correction, globals.element_LHS, globals.rve_Krr, globals.rve_Kcr_el, globals.rve_Krc_el); + globals.rve_K_el.Solve(globals.rve_Kcr_el, globals.rve_Kinv_Kcr_el); + Krc_dot_Kinv_Kcr = globals.rve_Krc_el ^ globals.rve_Kinv_Kcr_el; + } + else { + + getRetainedComponents(params, elastic_correction, globals.element_LHS, globals.rve_Krr, globals.rve_Kcr, globals.rve_Krc); + globals.rve_K.Solve(globals.rve_Kcr, globals.rve_Kinv_Kcr); + Krc_dot_Kinv_Kcr = globals.rve_Krc ^ globals.rve_Kinv_Kcr; + } + // get N from element_RHS (note: RHS = Fext-Fint) + N = globals.element_RHS(1); + // perform static condensation + // Kred = Krr - (Krc * inv(Kcc)*Kcr) + + + globals.rve_Kred = globals.rve_Krr - Krc_dot_Kinv_Kcr; + tangent = globals.rve_Kred; + return retval; + } + inline int commitState() { + + int retval = 0; + + sv.UG_commit = sv.UG; + sv.UG_el_commit = sv.UG_el; + int el_retval; + el_retval = e1.commitState(); + if (el_retval != 0) retval = el_retval; + el_retval = e2.commitState(); + if (el_retval != 0) retval = el_retval; + el_retval = e3.commitState(); + if (el_retval != 0) retval = el_retval; + el_retval = e0.commitState(); + if (el_retval != 0) retval = el_retval; + + return retval; + } + inline void revertToLastCommit() { + sv.UG = sv.UG_commit; + sv.UG_el = sv.UG_el_commit; + e0.revertToLastCommit(); + e1.revertToLastCommit(); + e2.revertToLastCommit(); + e3.revertToLastCommit(); + } + inline void revertToStart() { + sv.UG.Zero(); + sv.UG_commit.Zero(); + sv.UG_el.Zero(); + sv.UG_el_commit.Zero(); + e0.revertToStart(); + e1.revertToStart(); + e2.revertToStart(); + e3.revertToStart(); + } + + }; + int RVEModel::serializationDataSize() const { + return sv.serializationDataSize() + + e1.serializationDataSize() + + e2.serializationDataSize() + + e3.serializationDataSize() + + e0.serializationDataSize(); + } + void RVEModel::serialize(Vector& data, int& pos) { + sv.serialize(data, pos); + e1.serialize(data, pos); + e2.serialize(data, pos); + e3.serialize(data, pos); + e0.serialize(data, pos); + } + void RVEModel::deserialize(Vector& data, int& pos) { + sv.deserialize(data, pos); + e1.deserialize(data, pos); + e2.deserialize(data, pos); + e3.deserialize(data, pos); + e0.deserialize(data, pos); + } + class GlobalParameters { + private: + double max_error = 0.0; + double avg_error = 0.0; + int avg_counter = 0; + private: + GlobalParameters() = default; + GlobalParameters(const GlobalParameters&) = delete; + GlobalParameters& operator = (const GlobalParameters&) = delete; + public: + static GlobalParameters& instance() { + static GlobalParameters _instance; + return _instance; + } + inline double getMaxError() const { + return max_error; + } + inline void setMaxError(double x) { + max_error = x; + } + inline double getAverageError() { + if (avg_counter > 0) { + avg_error /= static_cast(avg_counter); + avg_counter = 0; + } + return avg_error; + } + inline void accumulateAverageError(double x) { + avg_error += x; + ++avg_counter; + } + inline void setAverageError(double x) { + avg_error = x; + avg_counter = 0; + } + }; + +} + +/** + PIMPL pattern + */ +class ASDSteel1DMaterialPIMPL +{ +public: + ASDSteel1DMaterialPIMPL() = default; + ASDSteel1DMaterialPIMPL(const ASDSteel1DMaterialPIMPL&) = default; + inline void setSlipMaterial(UniaxialMaterial* prototype) { + rve_m.setSlipMaterial(prototype); + } +public: + SeriesComponent steel_comp; + RVEModel rve_m; +}; + +void* OPS_ASDSteel1DMaterial() +{ + // some kudos + static bool first_done = false; + if (!first_done) { + opserr << "Using ASDSteel1D - Developed by: Alessia Casalucci, Massimo Petracca, Guido Camata, ASDEA Software Technology\n"; + first_done = true; + } + static const char* msg = "uniaxialMaterial ASDSteel1D $tag $E $sy $su $eu <-implex> <-implexControl $implexErrorTolerance $implexTimeReductionLimit> <-auto_regularization> <-buckling $lch < $r>> <-fracture <$r>> <-slip $matTag <$r>> <-K_alpha $K_alpha> <-max_iter $max_iter> <-tolU $tolU> <-tolR $tolR>"; + + // check arguments + int numArgs = OPS_GetNumRemainingInputArgs(); + if (numArgs < 5) { + opserr << + "uniaxialMaterial ASDSteel1D Error: Few arguments (< 5).\n" << msg << "\n"; + return nullptr; + } + + // numData + int numData = 1; + + // data + int tag; + double E = 0.0; + double sy = 0.0; + double su = 0.0; + double eu = 0.0; + double lch = 0.0; + double r = 0.0; // default to 0.0, means not provided + bool implex = false; + bool implex_control = false; + double implex_error_tolerance = 0.05; + double implex_time_redution_limit = 0.01; + bool auto_regularization = false; + bool buckling = false; + bool fracture = false; + bool slip = false; + double K_alpha = 0.5; + double max_iter= 100; + double tolU = 1.0e-6; + double tolR = 1.0e-6; + bool have_K_alpha = false; + bool have_max_iter = false; + bool have_tolU = false; + bool have_tolR = false; + UniaxialMaterial* matSlip = nullptr; + + + // get tag + if (OPS_GetInt(&numData, &tag) != 0) { + opserr << "UniaxialMaterial ASDSteel1D Error: invalid 'tag'.\n"; + return nullptr; + } + + // get steel base arguments + auto lam_get_dparam = [&numData](double* val, const char* valname) -> bool { + if (OPS_GetDouble(&numData, val) != 0) { + opserr << "UniaxialMaterial ASDSteel1D Error: invalid '" << valname << "'.\n" << msg << "\n"; + return false; + } + if (*val <= 0.0) { + opserr << "UniaxialMaterial ASDSteel1D Error: invalid value for '" << valname << "' (" << *val << "). It should be strictly positive.\n" << msg << "\n"; + return false; + } + return true; + }; + if (!lam_get_dparam(&E, "E")) return nullptr; + if (!lam_get_dparam(&sy, "sy")) return nullptr; + if (!lam_get_dparam(&su, "su")) return nullptr; + if (!lam_get_dparam(&eu, "eu")) return nullptr; + auto lam_optional_double = [&numData](const char* variable, double& value) -> bool { + if (OPS_GetNumRemainingInputArgs() > 0) { + if (OPS_GetDouble(&numData, &value) < 0) { + opserr << "UniaxialMaterial ASDSteel1D Error: failed to get '" << variable << "'.\n"; + return false; + } + } + else { + opserr << "UniaxialMaterial ASDSteel1D Error: '" << variable << "' requested but not provided.\n"; + return false; + } + return true; + }; + + // parse optional arguments + int trials = 0; + while (OPS_GetNumRemainingInputArgs() > 0) { + const char* value = OPS_GetString(); + if (strcmp(value, "-implex") == 0) { + implex = true; + } + if (strcmp(value, "-implexControl") == 0) { + implex_control = true; + if (OPS_GetNumRemainingInputArgs() < 2) { + opserr << "nDMaterial ASDConcrete1D Error: '-implexControl' given without the next 2 arguments $implexErrorTolerance $implexTimeReductionLimit.\n"; + return nullptr; + } + if (!lam_optional_double("implexErrorTolerance", implex_error_tolerance)) + return nullptr; + if (!lam_optional_double("implexTimeReductionLimit", implex_time_redution_limit)) + return nullptr; + } + if (strcmp(value, "-auto_regularization") == 0) { + auto_regularization = true; + } + if (strcmp(value, "-buckling") == 0) { + buckling = true; + // lch is mandatory + if (OPS_GetNumRemainingInputArgs() < 1) { + opserr << "UniaxialMaterial ASDSteel1D: '-buckling' requires at least '$lch'\n"; + return nullptr; + } + if(!lam_optional_double("lch", lch)) return nullptr; + // radius is optional (can be defined either here or in -slip) + if (OPS_GetNumRemainingInputArgs() > 0) { + double trial_radius; + auto old_num_rem = OPS_GetNumRemainingInputArgs(); + if (OPS_GetDouble(&numData, &trial_radius) < 0) { + // radius not provided, go back + auto new_num_rem = OPS_GetNumRemainingInputArgs(); + if (new_num_rem < old_num_rem) + OPS_ResetCurrentInputArg(-1); + } + else { + // radius give, do checks + if (trial_radius != r && r != 0.0) { + opserr << "UniaxialMaterial ASDSteel1D: radius provied in -buckling (" << trial_radius << ") does not match the one provided in -slip or -fracture (" << r << "). Please use it only once.\n"; + return nullptr; + } + if (trial_radius <= 0.0) { + opserr << "UniaxialMaterial ASDSteel1D: radius provied in -buckling should be strictly positive.\n"; + return nullptr; + } + r = trial_radius; + } + } + } + if (strcmp(value, "-fracture") == 0) { + fracture = true; + if (OPS_GetNumRemainingInputArgs() > 0) { + double trial_radius; + auto old_num_rem = OPS_GetNumRemainingInputArgs(); + if (OPS_GetDouble(&numData, &trial_radius) < 0) { + // radius not provided, go back + auto new_num_rem = OPS_GetNumRemainingInputArgs(); + if (new_num_rem < old_num_rem) + OPS_ResetCurrentInputArg(-1); + } + else { + // radius give, do checks + if (trial_radius != r && r != 0.0) { + opserr << "UniaxialMaterial ASDSteel1D: radius provied in -fracture (" << trial_radius << ") does not match the one provided in -slip or -buckling (" << r << "). Please use it only once.\n"; + return nullptr; + } + if (trial_radius <= 0.0) { + opserr << "UniaxialMaterial ASDSteel1D: radius provied in -fracture should be strictly positive.\n"; + return nullptr; + } + r = trial_radius; + } + } + } + if (strcmp(value, "-slip") == 0) { + slip = true; + if (OPS_GetNumRemainingInputArgs() < 1) { + opserr << "UniaxialMaterial ASDSteel1D: '-slip' requires '$matTag'.\n"; + return nullptr; + } + // get slip material + int matTag; + if (OPS_GetInt(&numData, &matTag) != 0) { + opserr << "UniaxialMaterial ASDSteel1D: cannot get slip material tag\n"; + return nullptr; + } + // Retrieve the UniaxialMaterial* + matSlip = OPS_getUniaxialMaterial(matTag); + if (matSlip == nullptr) { + opserr << "ASDSteel1D Error: No existing UniaxialMaterial with tag " << matTag << " for -slip option.\n"; + return nullptr; + } + + // radius is optional (can be defined either here or in -buckling) + if (OPS_GetNumRemainingInputArgs() > 0) { + double trial_radius; + auto old_num_rem = OPS_GetNumRemainingInputArgs(); + if (OPS_GetDouble(&numData, &trial_radius) < 0) { + // radius not provided, go back + auto new_num_rem = OPS_GetNumRemainingInputArgs(); + if (new_num_rem < old_num_rem) + OPS_ResetCurrentInputArg(-1); + } + else { + // radius give, do checks + if (trial_radius != r && r != 0.0) { + opserr << "UniaxialMaterial ASDSteel1D: radius provied in -slip (" << trial_radius << ") does not match the one provided in -buckling or -fracture (" << r << "). Please use it only once.\n"; + return nullptr; + } + if (trial_radius <= 0.0) { + opserr << "UniaxialMaterial ASDSteel1D: radius provied in -slip should be strictly positive.\n"; + return nullptr; + } + r = trial_radius; + } + } + } + if (strcmp(value, "-K_alpha") == 0) { + if (!lam_optional_double("K_alpha", K_alpha)) + return nullptr; + have_K_alpha = true; + } + if (strcmp(value, "-max_iter") == 0) { + if (!lam_optional_double("max_iter", max_iter)) + return nullptr; + have_max_iter = true; + } + if (strcmp(value, "-tolU") == 0) { + if (!lam_optional_double("tolU", tolU)) + return nullptr; + have_tolU = true; + } + if (strcmp(value, "-tolR") == 0) { + if (!lam_optional_double("tolR", tolR)) + return nullptr; + have_tolR = true; + } + } + + // checks + if (sy >= su) { + opserr << "1DMaterial ASDSteel1D Error: invalid value for 'su' (" << su << "). It should be larger than sy (" << sy << ").\n" << msg << "\n"; + return nullptr; + } + if (E == 0) { + opserr << "1DMaterial ASDSteel1D Error: invalid value for 'E' (" << E << "). It should be non-zero.\n" << msg << "\n"; + return nullptr; + } + + // obtain chaboche params from E, sy, su, eu + // we want to use 2 hardening functions as per chaboche model. + // so that the initial slope is close to E and the the stress apporaches su at eu + //double dy = su - sy; + //double H1 = E / 1000.0 / eu * dy / 40.0/1000.0; + //double gamma1 = H1 / dy; + //double H2 = H1 * 50; + //double gamma2 = gamma1 * 50; + //double alpha = 0.9; + double sy_norm = sy / E; + double su_norm = su / E; + double dy_norm = su_norm - sy_norm; + + double n = 400.0; + double m = 50.0; + + double H1_norm = (1.0 / n) / eu; + double gamma1_norm = H1_norm / dy_norm; + double H1 = H1_norm * E; + double gamma1 = gamma1_norm ; + + double H2 = H1 * m; + double gamma2 = gamma1 * m; + double alpha = 0.9; + ASDSteel1DMaterial::InputParameters params; + params.E = E; + params.sy = sy; + params.eu = eu; + params.H1 = H1 * alpha; + params.gamma1 = gamma1; + params.H2 = H2 * (1.0 - alpha); + params.gamma2 = gamma2; + params.implex = implex; + params.implex_control = implex_control; + params.implex_error_tolerance = implex_error_tolerance; + params.implex_time_redution_limit = implex_time_redution_limit; + params.auto_regularization = auto_regularization; + params.buckling = buckling; + params.fracture = fracture; + params.slip = slip; + params.length = buckling ? lch / 2.0 : 1.0; // consider half distance, the RVE uses symmetry + params.radius = r; + params.K_alpha = K_alpha; + params.max_iter = max_iter; + params.tolU = tolU; + params.tolR = tolR; + params.lch_element = params.length; + // create the material + UniaxialMaterial* instance = new ASDSteel1DMaterial( + // tag + tag, params, matSlip); + // base steel args + //E, sy, H1*alpha, gamma1, H2*(1.0-alpha), gamma2 + // others.. + //); + if (instance == nullptr) { + opserr << "UniaxialMaterial ASDSteel1D Error: failed to allocate a new material.\n"; + return nullptr; + } + + return instance; +} + +ASDSteel1DMaterial::ASDSteel1DMaterial( + int _tag, + const ASDSteel1DMaterial::InputParameters& _params, + UniaxialMaterial* slip_material) + : UniaxialMaterial(_tag, MAT_TAG_ASDSteel1DMaterial) + , params(_params) + , pdata(new ASDSteel1DMaterialPIMPL()) +{ + // set the slip material if defined for the RVE... + pdata->setSlipMaterial(slip_material); + // ... and for the base material + pdata->steel_comp.setSlipMaterial(slip_material); + // intialize C as C0 + C = getInitialTangent(); +} + +ASDSteel1DMaterial::ASDSteel1DMaterial() + : UniaxialMaterial(0, MAT_TAG_ASDSteel1DMaterial) + , pdata(new ASDSteel1DMaterialPIMPL()) +{ +} + +ASDSteel1DMaterial::ASDSteel1DMaterial(const ASDSteel1DMaterial& other) + : UniaxialMaterial(other.getTag(), MAT_TAG_ASDSteel1DMaterial) + , params(other.params) + , dtime_n(other.dtime_n) + , dtime_n_commit(other.dtime_n_commit) + , commit_done(other.commit_done) + , strain(other.strain) + , strain_commit(other.strain_commit) + , stress(other.stress) + , stress_commit(other.stress_commit) + , C(other.C) + , stress_rve(other.stress_rve) + , stress_rve_commit(other.stress_rve_commit) + , C_rve(other.C_rve) + , energy(other.energy) + , pdata(other.pdata ? new ASDSteel1DMaterialPIMPL(*other.pdata) : nullptr) +{ +} + +ASDSteel1DMaterial::~ASDSteel1DMaterial() +{ + if(pdata) delete pdata; +} + +int ASDSteel1DMaterial::setTrialStrain(double v, double r) +{ + params.lch_element = ops_TheActiveElement ? ops_TheActiveElement->getCharacteristicLength()/2 : params.length; + // save dT + if (!dtime_is_user_defined) { + dtime_n = ops_Dt; + if (!commit_done) { + dtime_0 = dtime_n; + dtime_n_commit = dtime_n; + } + } + // time factor for explicit extrapolation + double time_factor = 1.0; + if (params.implex && (dtime_n_commit > 0.0)) + time_factor = dtime_n / dtime_n_commit; + + // save macro strain + strain = v; + // homogenize micro response (stress/tangent) + + asd_print("MAT set trial (" << (int)params.implex << ")"); + int retval; + + double epl = 0.0; + if (params.buckling) { // se buckling farlo con l'energia ottenuta da rve (incremento spostamento * incremento forze (u - u commit)*(residuo-residuo commit) e normalizzarlo con una frazione della lunghezza* sigmay * Area + //regularization for element length lower than physical length (weighted average) + + if (params.implex) { + if (params.implex_control) { + double area = M_PI * params.radius * params.radius; + bool elastic_correction = params.lch_element > params.length; + // implicit solution + double retval = homogenize(false); + if (retval != 0) return retval; + + Vector U_impl = elastic_correction && params.auto_regularization ? pdata->rve_m.sv.UG_el : pdata->rve_m.sv.UG; + double N_impl = N_rve_last; + double sigma_impl = N_impl / stress; + + pdata->rve_m.revertToLastCommit(); + + // explicit solution + retval = homogenize(true); + if (retval != 0) return retval; + + Vector U_expl = elastic_correction && params.auto_regularization ? pdata->rve_m.sv.UG_el : pdata->rve_m.sv.UG; + double N_expl = N_rve_last; + double sigma_expl = N_expl / stress; + + Vector dU_err = U_expl - U_impl; + + // L2 Norm + double norm_dU = dU_err.Norm(); + double implex_error_u = norm_dU / params.radius; + double implex_error_N = (sigma_expl - sigma_impl) / params.sy; + implex_error = std::max(implex_error_u, implex_error_N); + if (implex_error > params.implex_error_tolerance) { + if (dtime_n >= params.implex_time_redution_limit * dtime_0) { + retval = EC_IMPLEX_Error_Control; + } + } + } + else { + retval = homogenize(true); + } + } + else { + retval = homogenize(false); + } + C = C_rve; + stress = stress_rve; + epl = pdata->rve_m.e2.section.series.steel_material.epl; + + + } + else { + //computation of sigma and tangent of steel + pdata->steel_comp.revertToLastCommit(); + + if (params.implex) { + if (params.implex_control) { + double sigma_macro = 0.0; + double tangent_macro = 0.0; + // implicit solution + int retval = pdata->steel_comp.compute(params, false, 1.0, strain, sigma_macro, tangent_macro); + double sigma_impl = sigma_macro; + pdata->steel_comp.revertToLastCommit(); + // explicit solution + retval = pdata->steel_comp.compute(params, true, time_factor, strain, stress, C); + double sigma_expl = stress; + + implex_error = std::abs(sigma_expl - sigma_impl) / params.sy; //semplifica + if (implex_error > params.implex_error_tolerance) { + if (dtime_n >= params.implex_time_redution_limit * dtime_0) { + retval = EC_IMPLEX_Error_Control; + } + } + } + else { + retval = pdata->steel_comp.compute(params, true, time_factor, strain, stress, C); + } + } + + else { + retval = pdata->steel_comp.compute(params, params.implex, time_factor, strain, stress, C); + } + epl = pdata->steel_comp.steel_material.epl; + } + if (params.fracture) { + double d = 0.0; + double eupl = params.eu - params.sy / params.E; + if (epl > eupl) { + double epl_max; + if (!params.auto_regularization) { + epl_max = eupl + eupl; + } + else { + epl_max = eupl + eupl * (16.0 * params.radius) / (2.0 * params.lch_element); + } + double G = (epl_max-eupl) * params.sy/4.0; + double sigma_damaged = std::max(1.0e-4 * params.sy, params.sy * exp(-params.sy * (epl-eupl) / G)); + d = 1.0 - sigma_damaged / params.sy; + } + //apply damage on stress e C + stress *= (1.0 - d); + C *= (1.0 - d); //tangent for implex, secant for implicit + } + + // done + return retval; +} + +double ASDSteel1DMaterial::getStress(void) +{ + return stress; +} + +double ASDSteel1DMaterial::getTangent(void) +{ + return C; +} + +double ASDSteel1DMaterial::getInitialTangent(void) +{ + return params.E; +} + +double ASDSteel1DMaterial::getStrain(void) +{ + return strain; +} + +int ASDSteel1DMaterial::commitState(void) +{ + // implicit stage + if (params.implex) { + if (params.buckling) { + asd_print("MAT commit (" << (int)false << ")"); + double area = M_PI * params.radius * params.radius; + bool elastic_correction = params.lch_element > params.length; + Vector U_expl = elastic_correction && params.auto_regularization ? pdata->rve_m.sv.UG_el : pdata->rve_m.sv.UG; + double N_expl = N_rve_last; + double sigma_expl = N_expl / stress; + + // implicit solution + double retval = homogenize(false); + + Vector U_impl = elastic_correction && params.auto_regularization ? pdata->rve_m.sv.UG_el : pdata->rve_m.sv.UG; + double N_impl = N_rve_last; + double sigma_impl = N_impl / stress; + + Vector dU_err = U_expl - U_impl; + + // Norm + double norm_dU = dU_err.Norm(); + double implex_error_u = norm_dU / params.radius; + double implex_error_N = (sigma_expl - sigma_impl) / params.sy; + implex_error = std::max(implex_error_u, implex_error_N); + GlobalParameters::instance().setMaxError(std::max(implex_error, GlobalParameters::instance().getMaxError())); + GlobalParameters::instance().accumulateAverageError(implex_error); + if (retval < 0) return retval; + } + else { + double sigma_expl = stress; + double sigma_macro = 0.0; + double tangent_macro = 0.0; + int retval = pdata->steel_comp.compute(params, false, 1.0, strain, sigma_macro, tangent_macro); + double sigma_impl = sigma_macro; + implex_error = std::abs(sigma_expl - sigma_impl) / params.sy; + GlobalParameters::instance().setMaxError(std::max(implex_error, GlobalParameters::instance().getMaxError())); + GlobalParameters::instance().accumulateAverageError(implex_error); + if (retval < 0) return retval; + } + + } + + // compute energy + energy += 0.5 * (stress_commit + stress) * (strain - strain_commit); + + // forward to all components + pdata->rve_m.commitState(); + pdata->steel_comp.commitState(); + + // state variables + strain_commit = strain; + stress_commit = stress; + + // implex + dtime_n_commit = dtime_n; + commit_done = true; + + // done + return 0; +} + +int ASDSteel1DMaterial::revertToLastCommit(void) +{ + // forward to all components + pdata->rve_m.revertToLastCommit(); + pdata->steel_comp.revertToLastCommit(); + + // state variables + strain = strain_commit; + stress = stress_commit; + stress_rve = stress_rve_commit; + + // implex + dtime_n = dtime_n_commit; + + // done + return 0; +} + +int ASDSteel1DMaterial::revertToStart(void) +{ + // forward to all components + pdata->rve_m.revertToStart(); + pdata->steel_comp.revertToStart(); + + // strain, stress and tangent + strain = 0.0; + strain_commit = 0.0; + stress = 0.0; + stress_commit = 0.0; + stress_rve = 0.0; + stress_rve_commit = 0.0; + C = getInitialTangent(); + C_rve = getInitialTangent(); + + // implex + dtime_n = 0.0; + dtime_n_commit = 0.0; + dtime_0 = 0.0; + dtime_is_user_defined = false; + // IMPL-EX error + implex_error = 0.0; + // Commit flag + commit_done = false; + + // output variables + energy = 0.0; + + // done + return 0; +} + + +UniaxialMaterial* ASDSteel1DMaterial::getCopy(void) +{ + // we can safely use the default copy-constructor + return new ASDSteel1DMaterial(*this); +} + +void ASDSteel1DMaterial::Print(OPS_Stream& s, int elastic_correction) +{ + s << "ASDSteel1D Material, tag: " << this->getTag() << "\n"; +} + +int ASDSteel1DMaterial::sendSelf(int commitTag, Channel &theChannel) +{ + //// aux + int counter; + + //// send DBL data + counter = 0; + + // variable DBL data size + + int nv_dbl = 13 + + params.NDATA + + pdata->rve_m.serializationDataSize() + + pdata->steel_comp.serializationDataSize() + + pdata->rve_m.e2.section.series.serializationDataSize(); + + + + Vector ddata(nv_dbl); + + // this data + ddata(counter++) = static_cast(getTag()); + ddata(counter++) = dtime_n; + ddata(counter++) = dtime_n_commit; + ddata(counter++) = dtime_0; + ddata(counter++) = static_cast(dtime_is_user_defined); + ddata(counter++) = implex_error; + ddata(counter++) = static_cast(commit_done); + ddata(counter++) = strain; + ddata(counter++) = strain_commit; + ddata(counter++) = stress; + ddata(counter++) = stress_commit; + ddata(counter++) = C; + ddata(counter++) = stress_rve; + ddata(counter++) = stress_rve_commit; + ddata(counter++) = C_rve; + ddata(counter++) = energy; + // params + ddata(counter++) = params.E; + ddata(counter++) = params.sy; + ddata(counter++) = params.eu; + ddata(counter++) = params.H1; + ddata(counter++) = params.H2; + ddata(counter++) = params.gamma1; + ddata(counter++) = params.gamma2; + ddata(counter++) = static_cast(params.implex); + ddata(counter++) = static_cast(params.implex_control); + ddata(counter++) = params.implex_error_tolerance; + ddata(counter++) = params.implex_time_redution_limit; + ddata(counter++) = static_cast(params.auto_regularization); + ddata(counter++) = static_cast(params.buckling); + ddata(counter++) = static_cast(params.fracture); + ddata(counter++) = static_cast(params.slip); + ddata(counter++) = params.radius; + ddata(counter++) = params.length; + ddata(counter++) = params.lch_element; + ddata(counter++) = params.K_alpha; + ddata(counter++) = params.max_iter; + ddata(counter++) = params.tolU; + ddata(counter++) = params.tolR; + // rve + pdata->rve_m.serialize(ddata, counter); + // steel base (no buckling) + pdata->steel_comp.serialize(ddata, counter, commitTag, theChannel); + // slip + pdata->rve_m.e2.section.series.serialize(ddata, counter, commitTag, theChannel); + + + + if (theChannel.sendVector(getDbTag(), commitTag, ddata) < 0) { + opserr << "ASDSteel1DMaterial::sendSelf() - failed to send DBL data\n"; + return -1; + } + + pdata->steel_comp.serialize_slip(commitTag, theChannel); + pdata->rve_m.e2.section.series.serialize_slip(commitTag, theChannel); + + + // done + return 0; +} + +int ASDSteel1DMaterial::recvSelf(int commitTag, Channel& theChannel, FEM_ObjectBroker& theBroker) +{ + // aux + int counter; + + // variable DBL data size + int nv_dbl = 13 + + params.NDATA + + pdata->rve_m.serializationDataSize() + + pdata->steel_comp.serializationDataSize() + + pdata->rve_m.e2.section.series.serializationDataSize(); + + // pdata->rve_m.e0.section.series.serializationDataSize() + pdata->rve_m.e2.section.series.serializationDataSize() + pdata->steel_comp.serializationDataSize(); + Vector ddata(nv_dbl); + + // recv DBL data + //Vector ddata(InputParameters::NDATA + 1 * StateVariablesSteel::NDATA + 10); + if (theChannel.recvVector(getDbTag(), commitTag, ddata) < 0) { + opserr << "ASDSteel1DMaterial::recvSelf() - failed to receive DBL data\n"; + return -1; + } + + counter = 0; + + // this data + setTag(ddata(counter++)); + dtime_n = ddata(counter++); + dtime_n_commit = ddata(counter++); + dtime_0 = ddata(counter++); + dtime_is_user_defined = static_cast(ddata(counter++)); + implex_error = ddata(counter++); + commit_done = static_cast(ddata(counter++)); + strain = ddata(counter++); + strain_commit = ddata(counter++); + stress = ddata(counter++); + stress_commit = ddata(counter++); + C = ddata(counter++); + stress_rve_commit = ddata(counter++); + stress_rve = ddata(counter++); + C_rve = ddata(counter++); + energy = ddata(counter++); + + //params + params.E = ddata(counter++); + params.sy = ddata(counter++); + params.eu = ddata(counter++); + params.H1 = ddata(counter++); + params.H2 = ddata(counter++); + params.gamma1 = ddata(counter++); + params.gamma2 = ddata(counter++); + params.implex = static_cast(ddata(counter++)); + params.implex_control = static_cast(ddata(counter++)); + params.implex_error_tolerance = ddata(counter++); + params.implex_time_redution_limit = ddata(counter++); + params.auto_regularization = static_cast(ddata(counter++)); + params.buckling = static_cast(ddata(counter++)); + params.fracture = static_cast(ddata(counter++)); + params.slip = static_cast(ddata(counter++)); + params.radius = ddata(counter++); + params.length = ddata(counter++); + params.lch_element = ddata(counter++); + params.K_alpha = ddata(counter++); + params.max_iter = ddata(counter++); + params.tolU = ddata(counter++); + params.tolR = ddata(counter++); + // rve + pdata->rve_m.deserialize(ddata, counter); + // steel base (in case of no buckling) + pdata->steel_comp.deserialize(ddata, counter, commitTag, theChannel, theBroker); + pdata->steel_comp.deserialize_slip(commitTag, theChannel, theBroker); + // slip + pdata->rve_m.e2.section.series.deserialize(ddata, counter, commitTag, theChannel, theBroker); + pdata->rve_m.e2.section.series.deserialize_slip(commitTag, theChannel, theBroker); + + // done + return 0; +} + +int ASDSteel1DMaterial::setParameter(const char** argv, int argc, Parameter& param) +{ + + // 1000 - time + if (strcmp(argv[0], "dTime") == 0) { + param.setValue(dtime_n); + return param.addObject(2000, this); + } + if (strcmp(argv[0], "dTimeCommit") == 0) { + param.setValue(dtime_n_commit); + return param.addObject(2001, this); + } + if (strcmp(argv[0], "dTimeInitial") == 0) { + param.setValue(dtime_0); + return param.addObject(2002, this); + } + + // default + return -1; +} + +int ASDSteel1DMaterial::updateParameter(int parameterID, Information& info) +{ + switch (parameterID) { + + // 2000 - time + case 2000: + dtime_n = info.theDouble; + dtime_is_user_defined = true; + return 0; + case 2001: + dtime_n_commit = info.theDouble; + dtime_is_user_defined = true; + return 0; + case 2002: + dtime_0 = info.theDouble; + dtime_is_user_defined = true; + return 0; + + // default + default: + return -1; + } +} + +Response* ASDSteel1DMaterial::setResponse(const char** argv, int argc, OPS_Stream& output) +{ + // utils + auto make_resp = [&output, this](int rid, const Vector& v, const std::vector* labels = nullptr) -> MaterialResponse* { + output.tag("UniaxialMaterialOutput"); + output.attr("matType", getClassType()); + output.attr("matTag", getTag()); + if (labels) { + for (const auto& item : (*labels)) + output.tag("ResponseType", item.c_str()); + } + MaterialResponse* resp = new MaterialResponse(this, rid, v); + output.endTag(); + return resp; + }; + + // labels + static std::vector lb_buckling_ratio = { "BI" }; + static std::vector lb_damage = { "D" }; + static std::vector lb_eqpl_strain = { "PLE" }; + static std::vector lb_slip_resp = { "Slip", "Tau" }; + static std::vector lb_time = { "dTime", "dTimeCommit", "dTimeInitial" }; + static std::vector lb_implex_error = { "Error" }; + + + + // check specific responses + if (argc > 0) { + if (strcmp(argv[0], "BI") == 0 || strcmp(argv[0], "BucklingIndicator") == 0) { + return make_resp(1001, getBucklingIndicator(), &lb_buckling_ratio); + } + if (strcmp(argv[0], "D") == 0 || strcmp(argv[0], "Damage") == 0) { + return make_resp(1002, getDamage(), &lb_damage); + } + if (strcmp(argv[0], "PLE") == 0 || strcmp(argv[0], "EquivalentPlasticStrain") == 0) { + return make_resp(1003, getEqPlStrain(), &lb_eqpl_strain); + } + if (strcmp(argv[0], "SlipResponse") == 0){ + return make_resp(1004, getSlipResponse(), &lb_slip_resp); + } + if (strcmp(argv[0], "time") == 0 || strcmp(argv[0], "Time") == 0) { + return make_resp(1005, getTimeIncrements(), &lb_time); + } + if (strcmp(argv[0], "implexError") == 0 || strcmp(argv[0], "ImplexError") == 0) { + return make_resp(1006, getImplexError(), &lb_implex_error); + } + } + + // otherwise return base-class response + return UniaxialMaterial::setResponse(argv, argc, output); +} + +int ASDSteel1DMaterial::getResponse(int responseID, Information& matInformation) +{ + // all outputs are 1D + //static Vector out1(1); + + switch (responseID) { + // 1000 - base steel output + case 1001: + return matInformation.setVector(getBucklingIndicator()); + // 1002 - damage + case 1002: + return matInformation.setVector(getDamage()); + case 1003: + return matInformation.setVector(getEqPlStrain()); + case 1004: + return matInformation.setVector(getSlipResponse()); + // 1005 - internal time + case 1005: return matInformation.setVector(getTimeIncrements()); + case 1006: return matInformation.setVector(getImplexError()); + default: + break; + } + return UniaxialMaterial::getResponse(responseID, matInformation); +} + +double ASDSteel1DMaterial::getEnergy(void) +{ + return energy; +} + +const Vector& ASDSteel1DMaterial::getBucklingIndicator() const +{ + static Vector d(1); + d.Zero(); + d(0) = pdata->rve_m.sv.UG(6); + return d; +} + +const Vector& ASDSteel1DMaterial::getDamage() const +{ + static Vector d(1); + d.Zero(); + if (params.fracture) { + double eupl = params.eu - params.sy / params.E; + double epl = params.buckling ? pdata->rve_m.e2.section.series.steel_material.epl : pdata->steel_comp.steel_material.epl; + if (epl > eupl) { + double epl_max; + if (!params.auto_regularization) { + epl_max = eupl + eupl; + } + else { + epl_max = eupl + eupl * (16.0 * params.radius) / (2.0 * params.lch_element); + } + double G = (epl_max - eupl) * params.sy / 4.0; + double sigma_damaged = std::max(1.0e-4 * params.sy, params.sy * exp(-params.sy * (epl - eupl) / G)); + d(0) = 1.0 - sigma_damaged / params.sy; + } + } + return d; +} + +const Vector& ASDSteel1DMaterial::getEqPlStrain() const +{ + static Vector d(1); + d.Zero(); + d(0) = params.buckling ? pdata->rve_m.e2.section.series.steel_material.epl : pdata->steel_comp.steel_material.epl; + return d; +} + +const Vector& ASDSteel1DMaterial::getSlipResponse() const +{ + static Vector d(2); + d.Zero(); + if (params.slip) { + if (params.buckling) { + d(0) = pdata->rve_m.e2.section.series.slip_material->getStrain(); + d(1) = pdata->rve_m.e2.section.series.slip_material->getStress(); + } + else { + d(0) = pdata->steel_comp.slip_material->getStrain(); + d(1) = pdata->steel_comp.slip_material->getStress(); + } + } + return d; +} + +const Vector& ASDSteel1DMaterial::getTimeIncrements() const +{ + static Vector d(3); + d(0) = dtime_n; + d(1) = dtime_n_commit; + d(2) = dtime_0; + return d; +} + +const Vector& ASDSteel1DMaterial::getImplexError() const +{ + static Vector d(1); + d(0) = implex_error; + return d; +} + +int ASDSteel1DMaterial::homogenize(bool do_implex) +{ + // return value + int retval = 0; + + // check for elastic correction + bool elastic_correction = params.lch_element > params.length; + + auto& globals = Globals::instance(); + if (elastic_correction && params.auto_regularization) { + globals.setRVENodes_el(params.length,params.lch_element); + } + else { + globals.setRVENodes(params.length); + } + + // time factor for explicit extrapolation + double time_factor = 1.0; + if (params.implex && do_implex && (dtime_n_commit > 0.0)) + time_factor = dtime_n / dtime_n_commit; + + // from macro strain to micro strain + double macro_strain = strain; + double Uy; + if (elastic_correction && params.auto_regularization) { + Uy = -macro_strain * params.lch_element; + } + else { + Uy = -macro_strain * params.length; + } + double N = 0.0; + double T = 0.0; + double area = 0.0; + retval = pdata->rve_m.compute(elastic_correction, params, Uy, do_implex, time_factor, N, T); + + if (retval != 0) { + return retval; + } + N_rve_last = N; + // from micro stress/tangent to macro stress/tangent + area = M_PI * params.radius * params.radius; + + stress_rve = -N/area; + if (elastic_correction && params.auto_regularization) { + C_rve = T * params.lch_element / area; + } + else { + C_rve = T * params.length / area; + } + + + // done + return retval; +} + + + + diff --git a/SRC/material/uniaxial/ASDSteel1DMaterial.h b/SRC/material/uniaxial/ASDSteel1DMaterial.h new file mode 100644 index 0000000000..f477cbd193 --- /dev/null +++ b/SRC/material/uniaxial/ASDSteel1DMaterial.h @@ -0,0 +1,163 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +// $Revision: 1.0 $ +// $Date: 2025-01-03 11:29:01 $ +// $Source: /usr/local/cvs/OpenSees/SRC/material/uniaxial/ASDSteel1DMaterial.cpp,v $ + +// Alessia Casalucci, Massimo Petracca, Guido Camata - ASDEA Software, Italy +// +// A unified and efficient plastic-damage material model for steel bars including fracture, bond-slip, and buckling via multiscale homogenization +// + +#ifndef ASDSteel1DMaterial_h +#define ASDSteel1DMaterial_h + +#include +#include +#include +#include +#include +#include +#include + +class ASDSteel1DMaterialPIMPL; + +class ASDSteel1DMaterial : public UniaxialMaterial +{ +public: + class InputParameters { + public: + // Young's modulus + double E = 0.0; + // Yield stress + double sy = 0.0; + // ultimate strain for damage initialization + double eu = 0.0; + // Chaboche kinematic hardening parameters + double H1 = 0.0; + double H2 = 0.0; + double gamma1 = 0.0; + double gamma2 = 0.0; + // misc + bool implex = false; + bool implex_control = false; + double implex_error_tolerance = 0.0; + double implex_time_redution_limit = 0.0; + bool auto_regularization = true; + bool buckling = false; + bool fracture = false; + bool slip = false; + // buckling + double radius = 0.0; + double length = 0.0; + double lch_element = 0.0; + + //convergence + double K_alpha = 0.0; + double max_iter = 0.0; + double tolU = 0.0; + double tolR = 0.0; + // counter + static constexpr int NDATA = 19; + }; + +public: + // life-cycle + ASDSteel1DMaterial( + int _tag, + const InputParameters& _params, + UniaxialMaterial* slip_material); + ASDSteel1DMaterial(); + ASDSteel1DMaterial(const ASDSteel1DMaterial& other); + ~ASDSteel1DMaterial(); + + // info + const char* getClassType(void) const { return "ASDSteel1DMaterial"; } + + // set strain + int setTrialStrain(double v, double r = 0.0); + + // get state + double getStrain(void); + double getStress(void); + double getTangent(void); + double getInitialTangent(void); + + // handle state + int commitState(void); + int revertToLastCommit(void); + int revertToStart(void); + + // copy and others... + UniaxialMaterial* getCopy(void); + void Print(OPS_Stream& s, int flag = 0); + + // send/recv self + int sendSelf(int commitTag, Channel& theChannel); + int recvSelf(int commitTag, Channel& theChannel, FEM_ObjectBroker& theBroker); + + // parameters and responses + int setParameter(const char** argv, int argc, Parameter& param); + int updateParameter(int parameterID, Information& info); + Response* setResponse(const char** argv, int argc, OPS_Stream& output); + int getResponse(int responseID, Information& matInformation); + double getEnergy(void); + +private: + int homogenize(bool do_implex); + const Vector& getBucklingIndicator() const; + const Vector& getDamage() const; + const Vector& getEqPlStrain() const; + const Vector& getSlipResponse() const; + const Vector& getSteelResponse() const; + const Vector& getTimeIncrements() const; + const Vector& getImplexError() const; + + + private: + // common input parameters + InputParameters params; + // state variables - implex + double dtime_n = 0.0; + double dtime_n_commit = 0.0; + double dtime_0 = 0.0; + bool dtime_is_user_defined = false; + bool commit_done = false; + double implex_error = 0.0; + // strain, stress and tangent (homogenized) + double strain = 0.0; + double strain_commit = 0.0; + double stress = 0.0; + double stress_commit = 0.0; + double C = 0.0; + double stress_rve = 0.0; + double stress_rve_commit = 0.0; + double C_rve = 0.0; + double N_rve_last = 0.0; + + // other variables for output purposes + double energy = 0.0; + + // private implementation + ASDSteel1DMaterialPIMPL* pdata = nullptr; +}; + +#endif diff --git a/SRC/material/uniaxial/CMakeLists.txt b/SRC/material/uniaxial/CMakeLists.txt index ac1be9fe26..1cce125760 100644 --- a/SRC/material/uniaxial/CMakeLists.txt +++ b/SRC/material/uniaxial/CMakeLists.txt @@ -73,6 +73,7 @@ target_sources(OPS_Material PRIVATE ASD_SMA_3K.cpp ASDConcrete1DMaterial.cpp + ASDSteel1DMaterial.cpp BackboneMaterial.cpp BarSlipMaterial.cpp BilinearOilDamper.cpp @@ -102,6 +103,7 @@ target_sources(OPS_Material ConfinedConcrete01.cpp ContinuumUniaxial.cpp CreepMaterial.cpp + CreepShrinkageACI209.cpp CubicSpline.cpp DamperMaterial.cpp DegradingPinchedBW.cpp @@ -200,6 +202,7 @@ target_sources(OPS_Material PUBLIC ASD_SMA_3K.h ASDConcrete1DMaterial.h + ASDSteel1DMaterial.h BackboneMaterial.h BarSlipMaterial.h BilinearOilDamper.h @@ -229,6 +232,7 @@ target_sources(OPS_Material ConfinedConcrete01.h ContinuumUniaxial.h CreepMaterial.h + CreepShrinkageACI209.h CubicSpline.h DamperMaterial.h DegradingPinchedBW.h diff --git a/SRC/material/uniaxial/Concrete07.cpp b/SRC/material/uniaxial/Concrete07.cpp index eb4864beec..cb077f9d1f 100644 --- a/SRC/material/uniaxial/Concrete07.cpp +++ b/SRC/material/uniaxial/Concrete07.cpp @@ -75,6 +75,10 @@ void* OPS_Concrete07() Concrete07::Concrete07 (int tag, double FPC, double EPSC0, double EC, double FPT, double EPST0, double XCRP, double XCRN, double R) :UniaxialMaterial(tag, MAT_TAG_Concrete07), fpc(FPC), epsc0(EPSC0), Ec(EC), fpt(FPT), epst0(EPST0), xcrp(XCRP), xcrn(XCRN), r(R) { + // Ensure negative signs + fpc = -fabs(fpc); + epsc0 = -fabs(epsc0); + // Calculate the variables that are needed to define the envelopw nn = (Ec*epsc0)/fpc; np = (Ec*epst0)/fpt; diff --git a/SRC/material/uniaxial/CreepShrinkageACI209.cpp b/SRC/material/uniaxial/CreepShrinkageACI209.cpp new file mode 100644 index 0000000000..cacc5bdcea --- /dev/null +++ b/SRC/material/uniaxial/CreepShrinkageACI209.cpp @@ -0,0 +1,712 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + + //---------------------------------------------------------------------------------------------------------------------------- + // Developed by: + // Javad Esmaeelpour (jesmaeel@tennessee.edu) + // Mark D. Denavit (mdenavit@utk.edu) + // Michael H. Scott (michael.scott@oregonstate.edu) + // + // Based on TDConcrete implementations by: + // Adam M. Knaack (adam.knaack@schaefer-inc.com) + // Schaefer-Inc, Cincinnati, Ohio, USA + // Nikola D. Tosic (ntosic@imk.grf.bg.ac.rs) + // Department for Materials and Structure, Faculty of Civil Engineering, University of Belgrade, Serbia + // Yahya C. Kurama (ykurama@nd.edu) + // Department of Civil and Environmental Engineering and Earth Sciences, College of Engineering, University of Notre Dame, Notre Dame, Indiana, USA + //---------------------------------------------------------------------------------------------------------------------------- + + //---------------------------------------------------------------------------------------------------------------------------- + // Description: This file contains the source code of CreepShrinkageACI209. + // CreepShrinkageACI209 is a wrapper that imposes creep and shrinkage evoluation equations + // to any uniaxialMaterial. + //---------------------------------------------------------------------------------------------------------------------------- + +#include +#include +#include +#include + + +#include "CreepShrinkageACI209.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static int numCreepShrinkageACI209 = 0; + +void * +OPS_CreepShrinkageACI209() { + if (numCreepShrinkageACI209 == 0) { + numCreepShrinkageACI209 = 1; + } + + UniaxialMaterial *theMaterial = 0; + + int iData; + int numData; + int numArgs; + + numArgs = OPS_GetNumRemainingInputArgs(); + + if (numArgs == 13) { + double dData[12]; + + numData = 1; + if (OPS_GetIntInput(&numData, &iData) != 0) { + opserr << "WARNING: invalid uniaxialMaterial CreepShrinkageACI209 tag\n"; + return 0; + } + + numData = 12; + if (OPS_GetDoubleInput(&numData, dData) != 0) { + opserr << "WARNING: invalid material property definition\n"; + return 0; + } + + theMaterial = new CreepShrinkageACI209(iData,dData[0],dData[1],dData[2],dData[3],dData[4],dData[5],dData[6],dData[7],dData[8],dData[9],dData[10],dData[11]); + if (theMaterial == 0) { + opserr << "WARNING: could not create uniaxialMaterial of type CreepShrinkageACI209 \n"; + return 0; + } + + return theMaterial; + } + if (numArgs == 10) { + double dData[14]; + + numData = 1; + if (OPS_GetIntInput(&numData, &iData) != 0) { + opserr << "WARNING: invalid uniaxialMaterial CreepShrinkageACI209 tag\n"; + return 0; + } + + int wrappedMatl; + if (OPS_GetIntInput(&numData, &wrappedMatl) != 0) { + opserr << "WARNING: invalid uniaxialMaterial CreepShrinkageACI209 wrapped material tag\n"; + return 0; + } + + UniaxialMaterial *matl = OPS_getUniaxialMaterial(wrappedMatl); + if (matl == 0) { + opserr << "WARNING: CreepShrinkageACI209 - unable to find material with tag " << wrappedMatl << endln; + return 0; + } + + numData = 8; + if (OPS_GetDoubleInput(&numData, &dData[6]) != 0) { + opserr << "WARNING: invalid material property definition\n"; + return 0; + } + + theMaterial = new CreepShrinkageACI209(iData,*matl,dData[6],dData[7],dData[8],dData[9],dData[10],dData[11],dData[12],dData[13]); + if (theMaterial == 0) { + opserr << "WARNING: could not create uniaxialMaterial of type CreepShrinkageACI209 \n"; + return 0; + } + + return theMaterial; + } + + return 0; +} + +CreepShrinkageACI209::CreepShrinkageACI209(int tag, double _fc, double _fcu, double _epscu, double _Ec, double _age, double _epsshu, double _epssha, double _tcr, double _epscru, double _epscra, double _epscrd, double _tcast): + UniaxialMaterial(tag, MAT_TAG_CreepShrinkageACI209), wrappedMaterial(0), + Ec(_Ec), age(_age), epsshu(_epsshu), epssha(_epssha), tcr(_tcr), epscru(_epscru), epscra(_epscra), epscrd(_epscrd), tcast(_tcast), maxSize(startSize), + DSIG_i(0), TIME_i(0), committedCreepStress(0.0) +{ + wrappedMaterial = new Concrete02IS(0,Ec,-fabs(_fc),2*(-fabs(_fc))/Ec,_fcu,_epscu); + + epsshu = -fabs(epsshu); + epscru = fabs(epscru); + + this->revertToStart(); + this->expandArrays(); + DSIG_i[0] = 0.0; + TIME_i[0] = getCurrentTime(); +} + +void +CreepShrinkageACI209::expandArrays() +{ + + if (DSIG_i == 0) + DSIG_i = new double[maxSize]; + + if (TIME_i == 0) + TIME_i = new double[maxSize]; + + if (historyPointCount+1 >= maxSize) { + maxSize += growSize; + + double *c = new double[maxSize]; + double *e = new double[maxSize]; + for (int i = 0; i <= historyPointCount; i++) { + c[i] = DSIG_i[i]; + e[i] = TIME_i[i]; + } + + if (DSIG_i != 0) + delete [] DSIG_i; + if (TIME_i != 0) + delete [] TIME_i; + DSIG_i = c; + TIME_i = e; + } +} + +CreepShrinkageACI209::CreepShrinkageACI209(int tag, UniaxialMaterial &matl, double _age, double _epsshu, double _epssha, double _tcr, double _epscru, double _epscra, double _epscrd, double _tcast): + UniaxialMaterial(tag, MAT_TAG_CreepShrinkageACI209), wrappedMaterial(0), + age(_age), epsshu(_epsshu), epssha(_epssha), tcr(_tcr), epscru(_epscru), epscra(_epscra), epscrd(_epscrd), tcast(_tcast), maxSize(startSize), + DSIG_i(0), TIME_i(0), committedCreepStress(0.0) +{ + wrappedMaterial = matl.getCopy(); + if (wrappedMaterial == 0) { + opserr << "CreepShrinkageACI209::CreepShrinkageACI209 - failed to get copy of material" << endln; + exit(-1); + } + + Ec = wrappedMaterial->getInitialTangent(); + + epsshu = -fabs(epsshu); + epscru = fabs(epscru); + + this->revertToStart(); + + this->expandArrays(); + DSIG_i[0] = 0.0; + TIME_i[0] = getCurrentTime(); +} + +CreepShrinkageACI209::CreepShrinkageACI209(void): + UniaxialMaterial(0, MAT_TAG_CreepShrinkageACI209), wrappedMaterial(0), maxSize(startSize), + DSIG_i(0), TIME_i(0), committedCreepStress(0.0) +{ +} + +CreepShrinkageACI209::~CreepShrinkageACI209(void) +{ + if (wrappedMaterial != 0) + delete wrappedMaterial; + if (DSIG_i != 0) + delete [] DSIG_i; + if (TIME_i != 0) + delete [] TIME_i; +} + +UniaxialMaterial* CreepShrinkageACI209::getCopy(void) +{ + CreepShrinkageACI209 *theCopy = new CreepShrinkageACI209(this->getTag(), *wrappedMaterial, + age, epsshu, epssha, tcr, epscru, epscra, epscrd, tcast); + + // Copy state variables + theCopy->trialStress = trialStress; + theCopy->trialTangent = trialTangent; + theCopy->trialTotalStrain = trialTotalStrain; + theCopy->trialCreepStrain = trialCreepStrain; + theCopy->trialShrinkageStrain = trialShrinkageStrain; + theCopy->trialMechanicalStrain = trialMechanicalStrain; + + theCopy->committedStress = committedStress; + theCopy->committedTangent = committedTangent; + theCopy->committedCreepStrain = committedCreepStrain; + theCopy->committedCreepStress = committedCreepStress; + theCopy->committedShrinkageStrain = committedShrinkageStrain; + theCopy->committedMechanicalStrain = committedMechanicalStrain; + theCopy->committedTotalStrain = committedTotalStrain; + + theCopy->iterationInStep = iterationInStep; + theCopy->historyPointCount = historyPointCount; + + // Ensure array capacity and copy history + theCopy->maxSize = maxSize; + theCopy->DSIG_i = new double[maxSize]; + theCopy->TIME_i = new double[maxSize]; + + for (int i = 0; i <= historyPointCount; i++) { + theCopy->DSIG_i[i] = DSIG_i[i]; + theCopy->TIME_i[i] = TIME_i[i]; + } + + return theCopy; +} + +double +CreepShrinkageACI209::getInitialTangent(void) +{ + return wrappedMaterial->getInitialTangent(); +} + +double +CreepShrinkageACI209::getCurrentTime(void) +{ + double currentTime = 0.0; + Domain * theDomain = ops_TheActiveDomain; + if (theDomain != 0) { + currentTime = theDomain->getCurrentTime(); + } + return currentTime; +} + +double +CreepShrinkageACI209::setCreepStrain(double time) +{ + double creep = 0.0, phi = 0.0; + const double denom_tcr = 1.25 * pow(tcr, -0.118); + double tmtp = 0.0; + double a; + double f2; + double f3; + + for (int i = 1; i <= historyPointCount; ++i) { + tmtp = time - TIME_i[i]; + if (tmtp <= 0.0) continue; // Guard against negative time. + + a = pow(tmtp, epscra); + f2 = (epscru * a) / (epscrd + a); + f3 = (1.25 * pow(TIME_i[i] - tcast, -0.118)) / denom_tcr; + phi = f2 * f3; + + creep += phi * DSIG_i[i] / Ec; + } + return creep; +} + +double +CreepShrinkageACI209::setShrink(double time) +{ + double tD = age; + double shrink = 0.0; + if (time-(tD) < 0) { + shrink = 0.0; + } else { + shrink = (time-(tD)) / (epssha + (time - (tD))) * epsshu; + } + return shrink; +} + +int +CreepShrinkageACI209::setTrialStrain(double strain, double strainRate) +{ + double t = getCurrentTime(); + + + // Enforce non-negative time only when creep is enabled. + if (ops_Creep == 1 && t < 0.0) { + opserr << "CreepShrinkageACI209::setTrialStrain - Negative time (" << t + << ") not allowed when creep is active.\n"; + return -1; + } + + trialTotalStrain = strain; + + if (ops_Creep == 1) { + if (fabs(t-TIME_i[historyPointCount]) <= 0.0001) { + trialCreepStrain = committedCreepStrain; + trialShrinkageStrain = committedShrinkageStrain; + } else { + if (iterationInStep < 1) { + trialCreepStrain = setCreepStrain(t); + trialShrinkageStrain = setShrink(t); + } + } + } else { + trialCreepStrain = committedCreepStrain; + trialShrinkageStrain = committedShrinkageStrain; + } + + trialMechanicalStrain = trialTotalStrain - trialCreepStrain - trialShrinkageStrain; + wrappedMaterial->setTrialStrain(trialMechanicalStrain, strainRate); + trialStress = wrappedMaterial->getStress(); + trialTangent = wrappedMaterial->getTangent(); + + iterationInStep ++; + return 0; +} + +double +CreepShrinkageACI209::getStrain(void) +{ + return trialTotalStrain; +} + +double +CreepShrinkageACI209::getStress(void) +{ + return trialStress; +} + +double +CreepShrinkageACI209::getTangent(void) +{ + return trialTangent; +} + + +int CreepShrinkageACI209::commitState(void) +{ + iterationInStep = 0; + + if (ops_Creep == 1 && fabs(trialStress - committedCreepStress) > 1e-12) { + double dSig = trialStress - committedCreepStress; + this->expandArrays(); + historyPointCount++; + DSIG_i[historyPointCount] = dSig; + TIME_i[historyPointCount] = getCurrentTime(); + + committedCreepStress = trialStress; + } + + committedTangent = trialTangent; + committedStress = trialStress; + committedTotalStrain = trialTotalStrain; + committedShrinkageStrain = trialShrinkageStrain; + committedCreepStrain = trialCreepStrain; + committedMechanicalStrain = trialMechanicalStrain; + + wrappedMaterial->commitState(); + return 0; +} + + +int + CreepShrinkageACI209::revertToLastCommit(void) +{ + // Restore trial state to last committed state + trialTotalStrain = committedTotalStrain; + trialShrinkageStrain = committedShrinkageStrain; + trialCreepStrain = committedCreepStrain; + trialMechanicalStrain = committedMechanicalStrain; + + trialTangent = committedTangent; + trialStress = committedStress; + + wrappedMaterial->revertToLastCommit(); + + return 0; +} + +int +CreepShrinkageACI209::revertToStart(void) +{ + + committedTangent = Ec; + committedStress = 0.0; + trialStress = 0.0; + committedCreepStress = 0.0; + trialTangent = Ec; + + + historyPointCount = 0; + + + trialTotalStrain = 0.0; + committedTotalStrain = 0.0; + trialCreepStrain = 0.0; + trialShrinkageStrain = 0.0; + trialMechanicalStrain = 0.0; + committedCreepStrain = 0.0; + committedShrinkageStrain = 0.0; + committedMechanicalStrain = 0.0; + + iterationInStep = 0; + + if (wrappedMaterial) + wrappedMaterial->revertToStart(); + + return 0; +} + +int +CreepShrinkageACI209::sendSelf(int commitTag, Channel &theChannel) +{ + int res = 0; + int dbTag = this->getDbTag(); + static ID classTags(4); + + classTags(0) = wrappedMaterial->getClassTag(); + int matDbTag = wrappedMaterial->getDbTag(); + if (matDbTag == 0) { + matDbTag = theChannel.getDbTag(); + if (matDbTag != 0) + wrappedMaterial->setDbTag(matDbTag); + } + classTags(1) = matDbTag; + classTags(2) = this->getTag(); + classTags(3) = maxSize; + + res = theChannel.sendID(dbTag, commitTag, classTags); + if (res < 0) { + opserr << "CreepShrinkageACI209::sendSelf -- could not send ID" << endln; + return res; + } + + Vector data(27 + maxSize*2); + int i = 0; + data(i++) = tcr; + data(i++) = Ec; + data(i++) = age; + data(i++) = epsshu; + data(i++) = epssha; + data(i++) = epscra; + data(i++) = epscru; + data(i++) = epscrd; + data(i++) = tcast; + + data(i++) = committedStress; + data(i++) = committedTangent; + data(i++) = committedCreepStress; + + data(i++) = historyPointCount; + data(i++) = trialCreepStrain; + data(i++) = trialShrinkageStrain; + data(i++) = trialMechanicalStrain; + data(i++) = committedMechanicalStrain; + data(i++) = committedCreepStrain; + data(i++) = committedShrinkageStrain; + data(i++) = trialTotalStrain; + data(i++) = committedTotalStrain; + data(i++) = iterationInStep; + + for (int j = 0; j < maxSize; j++, i++) + data(i) = DSIG_i[j]; + for (int j = 0; j < maxSize; j++, i++) + data(i) = TIME_i[j]; + + res = theChannel.sendVector(this->getDbTag(), commitTag, data); + if (res < 0) { + opserr << "CreepShrinkageACI209::sendSelf - failed to send Vector" << endln; + return res; + } + + res = wrappedMaterial->sendSelf(commitTag, theChannel); + if (res < 0) { + opserr << "CreepShrinkageACI209::sendSelf -- could not send UniaxialMaterial" << endln; + return res; + } + + return res; +} + +int +CreepShrinkageACI209::recvSelf(int commitTag, Channel &theChannel, + FEM_ObjectBroker &theBroker) +{ + int res = 0; + static ID idata(4); + int dbTag = this->getDbTag(); + + res = theChannel.recvID(dbTag, commitTag, idata); + if (res < 0) { + opserr << "CreepShrinkageACI209::recvSelf() - failed to receive data\n"; + return res; + } + + this->setTag(idata(2)); + maxSize = idata(3); + + Vector data(27 + maxSize*2); + + if (theChannel.recvVector(this->getDbTag(), commitTag, data) < 0) { + opserr << "CreepShrinkageACI209::recvSelf() - failed to recvSelf\n"; + return -1; + } + + int i = 0; + tcr = data(i++); + Ec = data(i++); + age = data(i++); + epsshu = data(i++); + epssha = data(i++); + epscra = data(i++); + epscru = data(i++); + epscrd = data(i++); + tcast = data(i++); + + committedStress = data(i++); + committedTangent = data(i++); + committedCreepStress = data(i++); + + historyPointCount = data(i++); + trialCreepStrain = data(i++); + trialShrinkageStrain = data(i++); + trialMechanicalStrain = data(i++); + committedMechanicalStrain = data(i++); + committedCreepStrain = data(i++); + committedShrinkageStrain = data(i++); + trialTotalStrain = data(i++); + committedTotalStrain = data(i++); + iterationInStep = data(i++); + + if (DSIG_i != 0) delete [] DSIG_i; + DSIG_i = new double [maxSize]; + if (TIME_i != 0) delete [] TIME_i; + TIME_i = new double [maxSize]; + + for (int j = 0; j < maxSize; j++, i++) + DSIG_i[j] = data(i); + for (int j = 0; j < maxSize; j++, i++) + TIME_i[j] = data(i); + + trialTangent = committedTangent; + trialStress = committedStress; + + int matClassTag = idata(0); + + if (wrappedMaterial == 0) { + wrappedMaterial = theBroker.getNewUniaxialMaterial(matClassTag); + if (wrappedMaterial == 0) { + opserr << "CreepShrinkageACI209::recvSelf -- could not get a UniaxialMaterial" << endln; + return -1; + } + } + + dbTag = idata(1); + if (wrappedMaterial->getClassTag() != matClassTag) { + delete wrappedMaterial; + wrappedMaterial = theBroker.getNewUniaxialMaterial(matClassTag); + if (wrappedMaterial == 0) { + opserr << "CreepShrinkageACI209::recvSelf -- could not get a UniaxialMaterial" << endln; + return -1; + } + } + + wrappedMaterial->setDbTag(dbTag); + res = wrappedMaterial->recvSelf(commitTag, theChannel, theBroker); + if (res < 0) { + opserr << "CreepShrinkageACI209::recvSelf -- count not receive Uniaxialmaterial" << endln; + return res; + } + + return res; +} + +void +CreepShrinkageACI209::Print(OPS_Stream &s, int flag) +{ + s << "CreepShrinkageACI209:(strain, stress, tangent) " << trialTotalStrain << " " << trialStress << " " << trialTangent << endln; +} + + +int +CreepShrinkageACI209::getVariable(const char *varName, Information &theInfo) +{ + return -1; +} + +Response* CreepShrinkageACI209::setResponse(const char **argv, int argc, + OPS_Stream &theOutput) +{ + Response *theResponse = 0; + + theOutput.tag("UniaxialMaterialOutput"); + theOutput.attr("matType", this->getClassType()); + theOutput.attr("matTag", this->getTag()); + + if (strcmp(argv[0],"stress") == 0) { + theOutput.tag("ResponseType", "sigma11"); + theResponse = new MaterialResponse(this, 1, this->getStress()); + } else if (strcmp(argv[0],"tangent") == 0) { + theOutput.tag("ResponseType", "C11"); + theResponse = new MaterialResponse(this, 2, this->getTangent()); + } else if (strcmp(argv[0],"strain") == 0) { + theOutput.tag("ResponseType", "eps11"); + theResponse = new MaterialResponse(this, 3, this->getStrain()); + } else if ((strcmp(argv[0],"stressStrain") == 0) || (strcmp(argv[0],"stressANDstrain") == 0)) { + theOutput.tag("ResponseType", "sig11"); + theOutput.tag("ResponseType", "eps11"); + theResponse = new MaterialResponse(this, 4, Vector(2)); + } else if (strcmp(argv[0],"CreepStressStrainTangent")==0) { + theOutput.tag("ResponseType", "sig11"); + theOutput.tag("ResponseType", "eps11"); + theOutput.tag("ResponseType", "C11"); + theOutput.tag("ResponseType", "CreepStrain"); + theOutput.tag("ResponseType", "MechStrain"); + theOutput.tag("ResponseType", "ShrinkStrain"); + theResponse = new MaterialResponse(this, 6, Vector(6)); + } else if (strcmp(argv[0],"stressStrainTangent") == 0) { + theOutput.tag("ResponseType", "sig11"); + theOutput.tag("ResponseType", "eps11"); + theOutput.tag("ResponseType", "C11"); + theResponse = new MaterialResponse(this, 5, Vector(3)); + } + + theOutput.endTag(); + return theResponse; +} + +int +CreepShrinkageACI209::getResponse(int responseID, Information &matInfo) +{ + static Vector stressStrain(2); + static Vector stressStrainTangent(3); + static Vector CreepStressStrainTangent(6); + + switch (responseID) { + case 1: + matInfo.setDouble(trialStress); + return 0; + + case 2: + matInfo.setDouble(trialTangent); + return 0; + + case 3: + matInfo.setDouble(trialTotalStrain); + return 0; + + case 4: + stressStrain(0) = trialStress; + stressStrain(1) = trialTotalStrain; + matInfo.setVector(stressStrain); + return 0; + + case 5: + stressStrainTangent(0) = trialStress; + stressStrainTangent(1) = trialTotalStrain; + stressStrainTangent(2) = trialTangent; + matInfo.setVector(stressStrainTangent); + return 0; + + case 6: + CreepStressStrainTangent(0) = trialStress; + CreepStressStrainTangent(1) = trialTotalStrain; + CreepStressStrainTangent(2) = trialTangent; + CreepStressStrainTangent(3) = trialCreepStrain; + CreepStressStrainTangent(4) = trialMechanicalStrain; + CreepStressStrainTangent(5) = trialShrinkageStrain; + matInfo.setVector(CreepStressStrainTangent); + return 0; + + default: + return -1; + } +} \ No newline at end of file diff --git a/SRC/material/uniaxial/CreepShrinkageACI209.h b/SRC/material/uniaxial/CreepShrinkageACI209.h new file mode 100644 index 0000000000..0c01e0dd1e --- /dev/null +++ b/SRC/material/uniaxial/CreepShrinkageACI209.h @@ -0,0 +1,134 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + + //---------------------------------------------------------------------------------------------------------------------------- + // Developed by: + // Javad Esmaeelpour (jesmaeel@tennessee.edu) + // Mark D. Denavit (mdenavit@utk.edu) + // Michael H. Scott (michael.scott@oregonstate.edu) + // + // Based on TDConcrete implementations by: + // Adam M. Knaack (adam.knaack@schaefer-inc.com) + // Schaefer-Inc, Cincinnati, Ohio, USA + // Nikola D. Tosic (ntosic@imk.grf.bg.ac.rs) + // Department for Materials and Structure, Faculty of Civil Engineering, University of Belgrade, Serbia + // Yahya C. Kurama (ykurama@nd.edu) + // Department of Civil and Environmental Engineering and Earth Sciences, College of Engineering, University of Notre Dame, Notre Dame, Indiana, USA + //---------------------------------------------------------------------------------------------------------------------------- + + //---------------------------------------------------------------------------------------------------------------------------- + // Description: This file contains the source code of CreepShrinkageACI209. + // CreepShrinkageACI209 is a wrapper that imposes creep and shrinkage evoluation equations + // to any uniaxialMaterial. + //---------------------------------------------------------------------------------------------------------------------------- + +#ifndef CreepShrinkageACI209_h +#define CreepShrinkageACI209_h + +#include +#include + +class CreepShrinkageACI209 : public UniaxialMaterial +{ +public: + // -- Core UniaxialMaterial Interface + CreepShrinkageACI209(int tag, double _fc, double _fcu, double _epscu, double _Ec, double _age, double _epsshu, double _epssha, double _tcr, double _epscru, double _epscra, double _epscrd, double _tcast); + CreepShrinkageACI209(int tag, UniaxialMaterial &matl, double _age, double _epsshu, double _epssha, double _tcr, double _epscru, double _epscra, double _epscrd, double _tcast); + CreepShrinkageACI209(void); + virtual ~CreepShrinkageACI209(); + + const char *getClassType(void) const {return "CreepShrinkageACI209";}; + double getInitialTangent(void); + UniaxialMaterial *getCopy(void); + + int setTrialStrain(double strain, double strainRate = 0.0); + double getStrain(void); + double getStress(void); + double getTangent(void); + + int commitState(void); + int revertToLastCommit(void); + int revertToStart(void); + + int sendSelf(int commitTag, Channel &theChannel); + int recvSelf(int commitTag, Channel &theChannel, + FEM_ObjectBroker &theBroker); + + void Print(OPS_Stream &s, int flag =0); + + int getVariable(const char *variable, Information &); + + // -- Functions for Recorders + Response *setResponse(const char **argv, int argc,OPS_Stream &theOutput); + int getResponse(int responseID, Information &matInfo); + +protected: + +private: + // -- Private Functions (Implementation Details) + double setCreepStrain(double time); // creep strain at global time + double getCurrentTime(void); // Current analysis time from the active OpenSees Domain. + double setShrink(double time); // Shrinkage strain at global time + void expandArrays(void); // Ensures capacity for the stress/time history arrays. + + + // -- Member Variables + UniaxialMaterial *wrappedMaterial; + + // matpar : Concrete FIXED PROPERTIES + + double tcr; // Tcr, creep age at loading used for phiu + double Ec; // Concrete modulus at loading + double age; // tD, analysis time when drying starts + double epsshu; // (eps_sh)u, ultimate shrinkage strain (ACI 209R Eq. 2-7) + double epssha; // f, shrinkage time-shape parameter (ACI 209R Eq. 2-7) + double epscra; // psi, creep time-shape parameter (ACI 209R Eq. 2-6) + double epscru; // phiu, ultimate creep coefficient (ACI 209R Eq. 2-6) + double epscrd; // d, creep time-shape parameter (ACI 209R Eq. 2-6) + double tcast; // Casting time in global analysis clock + + + double trialStress; // Current trial stress from wrapped material + double trialTangent; // Current trial tangent from wrapped material + double trialTotalStrain; // Total applied strain (input) + double trialCreepStrain; // Computed creep strain component + double trialShrinkageStrain; // Computed shrinkage strain component + double trialMechanicalStrain; // Mechanical strain sent to wrapped material + + double committedStress; // Last committed stress + double committedTangent; // Last committed tangent + double committedCreepStress; // Last committed creep stress + double committedCreepStrain; // Last committed creep strain + double committedShrinkageStrain; // Last committed shrinkage strain + double committedMechanicalStrain; // Last committed mechanical strain + double committedTotalStrain; // Last committed total strain + + int historyPointCount; // Number of points in stress-time history + int iterationInStep; // Iteration counter to avoid recomputing within same step + + enum{startSize=500, growSize=200}; + int maxSize; // Current allocated size of history arrays + + double *DSIG_i; // Stress increment history array [historyPointCount] + double *TIME_i; // Time history array [historyPointCount] +}; + + +#endif \ No newline at end of file diff --git a/SRC/material/uniaxial/HystereticSMMaterial.cpp b/SRC/material/uniaxial/HystereticSMMaterial.cpp index ee14873632..61cffbdeeb 100644 --- a/SRC/material/uniaxial/HystereticSMMaterial.cpp +++ b/SRC/material/uniaxial/HystereticSMMaterial.cpp @@ -324,8 +324,9 @@ OPS_HystereticSMMaterial(void) Vector thepinchArray(&pinchArray[0], (int)pinchArray.size()); Vector thedamageArray(&damageArray[0], (int)damageArray.size()); Vector thedegEnvArray(°EnvArray[0], (int)degEnvArray.size()); - Vector theLSforce(&forceLimitStates[0], (int)forceLimitStates.size()); - Vector theLSdefo(&defoLimitStates[0], (int)defoLimitStates.size()); + // Not dereferencing optionally empty forceLimitStates and/or defoLimitStates + Vector theLSforce = forceLimitStates.size() > 0 ? Vector(&forceLimitStates[0], (int)forceLimitStates.size()) : Vector(); + Vector theLSdefo = defoLimitStates.size() > 0 ? Vector(&defoLimitStates[0], (int)defoLimitStates.size()) : Vector(); double tmp = 0; if (YXorder == -1) { diff --git a/SRC/material/uniaxial/InitStressMaterial.cpp b/SRC/material/uniaxial/InitStressMaterial.cpp index 643b0d7d14..0511aed829 100644 --- a/SRC/material/uniaxial/InitStressMaterial.cpp +++ b/SRC/material/uniaxial/InitStressMaterial.cpp @@ -82,7 +82,7 @@ int InitStressMaterial::findInitialStrain(void) { // determine the initial strain - double tol = 1e-12; + double tol = (sigInit == 0.0) ? 1e-12 : fabs(sigInit)*1e-12; double dSig = sigInit; double tStrain = 0.0, tStress = 0.0; int count = 0; diff --git a/SRC/material/uniaxial/Makefile b/SRC/material/uniaxial/Makefile index 9b58a4d1a2..10c95f59ad 100644 --- a/SRC/material/uniaxial/Makefile +++ b/SRC/material/uniaxial/Makefile @@ -38,6 +38,7 @@ OBJS = UniaxialMaterial.o \ HardeningMaterial2.o \ ASD_SMA_3K.o \ ASDConcrete1DMaterial.o \ + ASDSteel1DMaterial.o \ Concrete01.o \ Concrete02Thermal.o \ Steel02Thermal.o \ @@ -164,6 +165,7 @@ OBJS = UniaxialMaterial.o \ FlagShapeMaterial.o \ GMG_CyclicReinforcedConcrete.o \ CreepMaterial.o \ + CreepShrinkageACI209.o \ APDFMD.o \ APDMD.o \ APDVFD.o \ diff --git a/SRC/material/uniaxial/PenaltyMaterial.cpp b/SRC/material/uniaxial/PenaltyMaterial.cpp index 492d9f9362..2859c3571f 100644 --- a/SRC/material/uniaxial/PenaltyMaterial.cpp +++ b/SRC/material/uniaxial/PenaltyMaterial.cpp @@ -163,6 +163,15 @@ PenaltyMaterial::getTangent(void) return 0.0; } +double +PenaltyMaterial::getInitialTangent(void) +{ + if (theMaterial) + return theMaterial->getInitialTangent() + penalty; + else + return 0.0; +} + double PenaltyMaterial::getDampTangent(void) { diff --git a/SRC/material/uniaxial/PenaltyMaterial.h b/SRC/material/uniaxial/PenaltyMaterial.h index 712a61fdf4..3256f780cf 100644 --- a/SRC/material/uniaxial/PenaltyMaterial.h +++ b/SRC/material/uniaxial/PenaltyMaterial.h @@ -50,7 +50,7 @@ class PenaltyMaterial : public UniaxialMaterial double getStress(void); double getTangent(void); double getDampTangent(void); - double getInitialTangent(void) {return theMaterial->getInitialTangent();} + double getInitialTangent(void); int commitState(void); int revertToLastCommit(void); diff --git a/SRC/material/uniaxial/TclModelBuilderUniaxialMaterialCommand.cpp b/SRC/material/uniaxial/TclModelBuilderUniaxialMaterialCommand.cpp index 613008ba09..ce4cae0f3d 100644 --- a/SRC/material/uniaxial/TclModelBuilderUniaxialMaterialCommand.cpp +++ b/SRC/material/uniaxial/TclModelBuilderUniaxialMaterialCommand.cpp @@ -151,6 +151,7 @@ extern void *OPS_ElasticMaterialThermal(void); //L.Jiang[SIF] //extern void *OPS_PlateBearingConnectionThermal(void); extern void* OPS_ASD_SMA_3K(void); // Luca Aceto extern void* OPS_ASDConcrete1DMaterial(void); +extern void* OPS_ASDSteel1DMaterial(void); extern void *OPS_BWBN(void); extern void *OPS_IMKPeakOriented(void); extern void *OPS_IMKBilin(void); @@ -2021,6 +2022,14 @@ TclModelBuilderUniaxialMaterialCommand (ClientData clientData, Tcl_Interp *inter return TCL_ERROR; } + if (strcmp(argv[1], "ASDSteel1D") == 0) { + void *theMat = OPS_ASDSteel1DMaterial(); + if (theMat != 0) + theMaterial = (UniaxialMaterial *)theMat; + else + return TCL_ERROR; + } + if (strcmp(argv[1],"SelfCentering") == 0) { void *theMat = OPS_SelfCenteringMaterial(); if (theMat != 0) diff --git a/SRC/matrix/AxisAngle.h b/SRC/matrix/AxisAngle.h new file mode 100644 index 0000000000..daa19832f4 --- /dev/null +++ b/SRC/matrix/AxisAngle.h @@ -0,0 +1,96 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +#pragma once +#include "Vector3D.h" +#include "VectorND.h" +#include "MatrixND.h" +#include "Matrix3D.h" +#include "GroupSO3.h" + +namespace { + +class AxisAngle { +public: + Vector3D vector; + double angle, eta, mu; + + AxisAngle() + : vector{}, + angle(0.0), + eta(0.0), + mu(0.0) + { + } + + explicit + AxisAngle(const Matrix3D& R) + : AxisAngle(LogSO3(R)) + { + } + + explicit + AxisAngle(const Vector3D& v) + : angle(v.norm()), + vector(v) + { + Utility::dLogConst(angle, eta, mu); + } + + inline Matrix3D + dLog() const + { + // + // d_R LogSO3(v) = Eye3 - 0.5*Sv + eta*Sv*Sv; + // + Matrix3D dH = Eye3; + dH.addSpin(vector, -0.5); + dH.addSpinSquare(vector, eta); + return dH; + } + + inline Vector3D + dLog(const Vector3D&p) const + { + // + // d_R LogSO3(v) = Eye3 - 0.5*Sv + eta*Sv*Sv; + // + Vector3D u = p; + u -= vector.cross(p)*0.5; + u += eta*vector.cross(vector.cross(p)); + return u; + } + + inline Matrix3D + ddLog(const Vector3D& p) const + { + // + // -0.5*Hat(v) + eta*(Eye3*th.dot(v) + th.bun(v) - 2.*v.bun(th)) + mu*St2*v.bun(th); + // + const Vector3D& v = this->vector; + + Matrix3D St2 = Hat(vector); + St2 = St2*St2; + Matrix3D dH{}; + dH.addSpin(p, -0.5); + dH.addDiagonal( eta*vector.dot(p)); + dH.addTensorProduct(v, p, eta); + dH.addTensorProduct(p, v, -2.0*eta); + dH.addMatrixProduct(St2, p.bun(v), mu); + + return dH*this->dLog(); + } +}; + +} // namespace \ No newline at end of file diff --git a/SRC/matrix/GroupSO3.h b/SRC/matrix/GroupSO3.h new file mode 100755 index 0000000000..4d3d79a0b3 --- /dev/null +++ b/SRC/matrix/GroupSO3.h @@ -0,0 +1,665 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +// Please cite the following resource in any derivative works: +// +// Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +//===----------------------------------------------------------------------===// + +// +// References: +// +// [1] Perez, C.M., and Filippou F.C.. "On Nonlinear Geometric Transformations +// of Finite Elements" Int. J. Numer. Meth. Engrg. 2024; +// https://doi.org/10.1002/nme.7506 +// +// [2] Ritto-Corrêa, M. and Camotim, D. (2002) "On the differentiation of the +// Rodrigues formula and its significance for the vector-like parameterization +// of Reissner-Simo beam theory" +// Int. J. Numer. Meth. Engrg., 55(9), pp. +// 1005–1032. Available at: https://doi.org/10.1002/nme.532. +// +// [3] Ibrahimbegović, A. and Mikdad, M.A. (1998) ‘Finite rotations in dynamics of +// beams and implicit time‐stepping’, 41, pp. 781–814. +// +// [4] Pfister, F. (1998) ‘Bernoulli Numbers and Rotational Kinematics’, +// Journal of Applied Mechanics, 65(3), pp. 758–763. +// Available at: https://doi.org/10.1115/1.2789120. +// +// [5] Nurlanov Z (2021) Exploring SO(3) logarithmic map: degeneracies and +// derivatives. +// +//===----------------------------------------------------------------------===// + +// +// Functions related to exponential coordinates on SO(3). The implementation +// follows value semantics with the expectation that RVO will make this +// performant. +// +// Written: Claudio M. Perez +// 2023 +// +#pragma once + +#include +#include +#include "Versor.h" +#include "Matrix3D.h" +#include "Vector3D.h" +using OpenSees::Matrix3D; +using OpenSees::Versor; + +static constexpr double SmallAngle = 1e-12; // threshold for small angles +static constexpr double SmallAngle2 = SmallAngle * SmallAngle; // threshold for small angles squared + +static constexpr Matrix3D Eye3 {{ + 1, 0, 0, + 0, 1, 0, + 0, 0, 1 +}}; + + + +static inline constexpr Vector3D +Vee(const Matrix3D &X) noexcept +{ +// +// Return the axial vector x of the given skew-symmetric 3x3 matrix X. +// + return {X(2,1), X(0,2), X(1,0)}; +} + +template +static inline constexpr Matrix3D +Hat(const Vec3Type &u) noexcept +{ + return Matrix3D {{ 0 , u[2], -u[1], + -u[2], 0 , u[0], + u[1], -u[0], 0 }}; +} + + +static inline double +GibSO3(const Vector3D &vec, double *a, double *b=nullptr, double *c=nullptr) noexcept +{ +// +// Compute coefficients of the Rodrigues formula and their differentials. +// +// [1,2] | [3] +// ----------+------- +// a1 | +// a2 | c4 +// a3 | c5 +// +// b1 = -c0 | c1 +// b2 | c2 +// b3 | c3 +// +// +// [2] Ritto-Corrêa, M. and Camotim, D. (2002) "On the differentiation of the +// Rodrigues formula and its significance for the vector-like parameterization +// of Reissner-Simo beam theory" +// Int. J. Numer. Meth. Engrg., 55(9), pp. +// 1005–1032. Available at: https://doi.org/10.1002/nme.532. +// +// [3] Ibrahimbegović, A. and Mikdad, M.A. (1998) ‘Finite rotations in dynamics of +// beams and implicit time‐stepping’, 41, pp. 781–814. +// +// [4] Pfister, F. (1998) ‘Bernoulli Numbers and Rotational Kinematics’, +// Journal of Applied Mechanics, 65(3), pp. 758–763. +// Available at: https://doi.org/10.1115/1.2789120. +// +// --------------------------------------------------------------------------- +// Written: cmp 2023 +//===----------------------------------------------------------------------===// +// + double angle2 = vec.dot(vec); + + if (angle2 <= 1e-12) { + // + // Maclaurin series in Horner form + // + if (a != nullptr) { + a[0] = 1.0 - angle2*(1.0/2.0 - angle2*(1.0/6.0 - angle2/24.0)); + a[1] = 1.0 - angle2*(1.0/6.0 - angle2*(1.0/120.0 - angle2/5040.0)); + a[2] = 0.5 - angle2*(1.0/24.0 - angle2*(1.0/720.0 - angle2/40320.0)); + // a[3] = 1.0/6.0 - angle2/(1.0/120.0 - angle2/(1.0/5040.0 - angle2/362880.0)); + a[3] = 1.0/6.0 - angle2*(1.0/120.0 - angle2*(1.0/5040.0 - angle2/362880.0)); + } + if (b != nullptr) { + b[0] = - a[1]; + b[1] = - 1.0/3.0 + angle2*(1.0/30.0 - angle2*(1.0/840.0 - angle2/45360.0)); + b[2] = - 1.0/12.0 + angle2*(1.0/180.0 - angle2*(1.0/6720.0 - angle2/453600.0)); + b[3] = - 1.0/60.0 + angle2*(1.0/1260.0 - angle2*(1.0/60480 - angle2/4989600.0)); + } + if (c != nullptr) { + c[0] = - b[1]; + c[1] = b[3] - b[2]; + c[2] = 1.0/90.0 - angle2*(1.0/1680.0 - angle2*(1.0/75600.0 - angle2/5987520.0)); + c[3] = 1.0/630.0 - angle2*(1.0/15120.0 - angle2*(1.0/831600.0 - angle2/77837760.0)); + } + + } else { + // + // Use formulas of Equation (A8) from [1] + // + double angle = vec.norm(); + double sn = std::sin(angle); + double cs = std::cos(angle); + double angle3 = angle*angle2; + double angle4 = angle*angle3; + double angle5 = angle*angle4; + + if (a != nullptr) { + a[0] = cs; + a[1] = sn / angle; + a[2] = ( 1.0 - a[0] ) / angle2; + // a[3] = ( 1.0 - a[1] ) / angle2; + a[3] = (angle - sn)/(angle3); + } + + if (b != nullptr) { + b[0] = -a[1]; + b[1] = ( angle*cs - sn)/angle3; + b[2] = ( angle*sn - 2.0 + 2.0*cs)/angle4; + b[3] = ( 3.0*sn - 2.0*angle - angle*cs )/angle5; + } + + if (c != nullptr) { + c[0] = -b[1]; + c[1] = (3.*sn - angle2*sn - 3.*angle*cs)/(angle5); + c[2] = (8. - 8.*cs - 5.*angle*sn + angle2*cs)/(angle5*angle); + c[3] = (8.*angle + 7.*angle*cs + angle2*sn - 15.*sn)/(angle5*angle2); + } + } + + return std::sqrt(angle2); +} + +// +// Rotation Conversions +// + +static inline Vector3D +CayleyFromVersor(const Versor &q) +{ + const double q0 = q.scalar; + + Vector3D w; + for (int i = 0; i < 3; i++) + w[i] = 2.0 * q.vector[i]/q0; + + return w; +} + + + +// R = (q0^2 - q' * q)*I + 2 * q * q' + 2*q0*S(q); +static inline Matrix3D +MatrixFromVersor(const Versor &q) +{ + Matrix3D R{}; + + const double factor = q.scalar*q.scalar - q.vector.dot(q.vector); + + for (int i = 0; i < 3; i++) + R(i,i) = factor; + + R.addTensorProduct(q.vector, q.vector, 2.0); + R.addSpin(q.vector, 2.0*q.scalar); + + return R; +} + + +// Form rotation axis vector from a quaternion +static inline Vector3D +VectorFromVersor(const Versor& q) +{ + // Initialize to zero + Vector3D theta{}; + + double q0 = q.scalar; + + // Norm of the vector part + double qn = q.vector.norm(); + + const double* const qv = &q.vector[0]; + + // Return zero-vector + if (qn == 0) + return theta; + + double factor = 1.0; + if (q0 < 0) { + q0 = -q0; + factor = -1.0; + } + + if (qn < q0) + factor *= 2.0*std::asin(qn)/qn; + else + factor *= 2.0*std::acos(q0)/qn; + + + for (int i=0; i<3; i++) + theta[i] = qv[i]*factor; + + return theta; + +} + + +// +// Exponential Map +// + +static inline Matrix3D +ExpSO3(const Vector3D &theta) +{ + // Form the first Gib coefficients + double a[4]; + + Matrix3D R = Eye3; + if (GibSO3(theta, a) > 1e-16) { + R.addSpin(theta, a[1]); + R.addSpinSquare(theta, a[2]); + } + return R; +} + + +static inline Matrix3D +CaySO3(const Vector3D &cayley) +{ + // + // Cayley map for a rotation matrix given the "tangent-scaled pseudo-vector" + // + // R = I + (S + S*S/2)/(1 + w' * w / 4); + // + //===--------------------------------------------------------------------===// + + const double c = 1.0/(1.0 + cayley.dot(cayley)/4.0); + + Matrix3D R; + R.zero(); + R.addDiagonal(1.0); + R.addSpin(cayley, c); + R.addSpinSquare(cayley, 0.5*c); + + return R; +} + + + +// +// Exponential Differentials +// + +inline Matrix3D +TanSO3(const Vector3D &vec, char repr='L') +{ + // + // Compute right or left differential of the exponential. + // + //===--------------------------------------------------------------------===// + double a[4]; + GibSO3(vec, a); + + Matrix3D T; + + // Assemble differential + switch (repr) { + case 'R': + T(0,0) = a[1] + a[3]*vec[0]*vec[0]; + T(0,1) = -vec[2]*a[2] + a[3]*vec[0]*vec[1]; + T(0,2) = vec[1]*a[2] + a[3]*vec[0]*vec[2]; + T(1,0) = vec[2]*a[2] + a[3]*vec[1]*vec[0]; + T(1,1) = a[1] + a[3]*vec[1]*vec[1]; + T(1,2) = -vec[0]*a[2] + a[3]*vec[1]*vec[2]; + T(2,0) = -vec[1]*a[2] + a[3]*vec[2]*vec[0]; + T(2,1) = vec[0]*a[2] + a[3]*vec[2]*vec[1]; + T(2,2) = a[1] + a[3]*vec[2]*vec[2]; + return T; + + case 'L': + default: + T(0,0) = a[1] + a[3]*vec[0]*vec[0]; + T(0,1) = vec[2]*a[2] + a[3]*vec[1]*vec[0]; + T(0,2) = -vec[1]*a[2] + a[3]*vec[2]*vec[0]; + T(1,0) = -vec[2]*a[2] + a[3]*vec[0]*vec[1]; + T(1,1) = a[1] + a[3]*vec[1]*vec[1]; + T(1,2) = vec[0]*a[2] + a[3]*vec[2]*vec[1]; + T(2,0) = vec[1]*a[2] + a[3]*vec[0]*vec[2]; + T(2,1) = -vec[0]*a[2] + a[3]*vec[1]*vec[2]; + T(2,2) = a[1] + a[3]*vec[2]*vec[2]; + return T; + + } +} + + +inline Matrix3D +TExpSO3(const Vector3D &v) +{ +// Compute the right differential of the exponential on SO(3) using the formula in +// Equation (A11) in [1]: +// +// T = a[1]*Eye3 + a[2]*v.hat() + a[3]*v.bun(v); +// +// ----------------------------------------------------------------------------------------- + + // Form first Gib coefficients + double a[4]; + GibSO3(v, a); + + Matrix3D T{}; + T.addDiagonal(a[1]) + .addSpin(v, a[2]) + .addTensorProduct(v, v, a[3]); + + return T; +} + + +inline Matrix3D +ddTanSO3(const Vector3D &v, const Vector3D &p, const Vector3D &q) +{ + // + // return a[3]*psq + b[1]*p.dot(q)*Eye3 + // + b[2]*(pxq.bun(v) + v.bun(pxq) + vxp.dot(q)*Eye3) + // + b[3]*( v.dot(p)*(q.bun(v) + v.bun(q)) + // + v.dot(q)*(p.bun(v) + v.bun(p)) + // + v.dot(p)*v.dot(q)*Eye3) + // + vov*(c[1]*p.dot(q) + c[2]*(vxp.dot(q)) + c[3]*v.dot(p)*v.dot(q)); + // + // ========================================================================================= + double a[4], b[4], c[4]; + GibSO3(v, a, b, c); + + const Vector3D pxq = p.cross(q); + const Vector3D vxp = v.cross(p); + + Matrix3D dT{}; + + dT.addTensorProduct(p, q, a[3]) + .addTensorProduct(q, p, a[3]) + .addDiagonal(b[1]*p.dot(q)) + .addTensorProduct(pxq, v, b[2]) + .addTensorProduct(v, pxq, b[2]) + .addDiagonal(vxp.dot(q)*b[2]) + + .addTensorProduct(q, v, b[3]*v.dot(p)) + .addTensorProduct(v, q, b[3]*v.dot(p)) + .addTensorProduct(p, v, b[3]*v.dot(q)) + .addTensorProduct(v, p, b[3]*v.dot(q)) + .addDiagonal(v.dot(p)*v.dot(q)*b[3]) + + .addTensorProduct(v, v, c[1]*p.dot(q) + c[2]*(vxp.dot(q)) + c[3]*v.dot(p)*v.dot(q)); + + return dT; +} + + + +inline Matrix3D +dTanSO3(const Vector3D &v, const Vector3D &p, char repr='L') +{ + // Tangents of the right and left exponential differentials using Equations (A13) and (A14), + // respectively from [1]. + // + // repr 'L' or 'R' indicating left or right representation, + // respectively, for the tangent space of SO(3) + + + double a[4], b[4]; + GibSO3(v, a, b); + + Matrix3D Xi{}; + Xi.addSpin(p, a[2]*(repr == 'R' ? -1.0 : 1.0)) + .addDiagonal(a[3]*v.dot(p)) + .addTensorProduct(v, p, a[3]) + .addTensorProduct(p, v, b[1]) + .addTensorProduct(v.cross(p), v, b[2]*(repr == 'R' ? 1.0 : -1.0)) + .addTensorProduct(v, v, v.dot(p)*b[3]); + return Xi; +} + + +inline Matrix3D +dExpSO3(const Vector3D &v, const Vector3D &p) +{ + double a[4], b[4]; + GibSO3(v, a, b); + + Matrix3D Xi{}; + Xi.addSpin(p, -a[1]) + .addDiagonal(a[2]*v.dot(p)) + .addTensorProduct(v, p, a[2]) + .addTensorProduct(p, v, b[0]) + .addTensorProduct(v.cross(p), v, b[1]) + .addTensorProduct(v, v, v.dot(p)*b[2]); + + return Xi; +} + + +inline Vector3D +LogSO3(const Matrix3D &R) +{ + //===--------------------------------------------------------------------===// + // + // Inverse of the exponential map on SO(3). + // + // Returns the axial parameters associated with the rotation `R`. The result + // should satisfy the following equality for any 3-vector, `v`: + // + // LogSO3(expm(Hat(v))) == v + // + // where `expm` is matrix exponential, and `Hat` is a function + // which produces the skew-symmetric 3x3 matrix associated with vector `v`. + // + // Parameters + // R (3x3) Rotation (proper orthogonal) matrix. + // + // + // References + // 1. Nurlanov Z (2021) Exploring SO(3) logarithmic map: degeneracies and + // derivatives. + // + //===--------------------------------------------------------------------===// + + return VectorFromVersor(Versor::from_matrix(R)); +} + + +static inline Vector3D +LogC90(const Matrix3D &R) +{ + //===--------------------------------------------------------------------===// + // + // Crisfield's approximation to the logarithm on SO(3) + // + // - Crisfield M (1990) A consistent co-rotational formulation for non-linear, + // three-dimensional, beam-elements + // + //===--------------------------------------------------------------------===// + + return Vector3D { + -std::asin(0.5*(R(1,2) - R(2,1))), + std::asin(0.5*(R(0,2) - R(2,0))), + -std::asin(0.5*(R(0,1) - R(1,0))), + }; +} + +static inline Vector3D +LogC90_Skew(const Matrix3D &R) +{ + //===--------------------------------------------------------------------===// + // + // Crisfield M (1990) A consistent co-rotational formulation for non-linear, + // three-dimensional, beam-elements + // + //===--------------------------------------------------------------------===// + // Crisfield's approximation to the logarithm on SO(3) + + return Vector3D { + std::asin(0.5*(R(1,2) - R(2,1))), + std::asin(0.5*(R(0,1) - R(1,0))), + std::asin(0.5*(R(0,2) - R(2,0))), + }; +} + +namespace Utility { + +template +constexpr T horner(T x2, const std::array& c) noexcept +{ + // Evaluate c0 + c1*x2 + c2*x2² + ... with Horner's rule (and FMA if available). + T y = c.back(); + for (std::size_t i = N-1; i-- > 0; ) + y = std::fma(x2, y, c[i]); + return y; +} + +static inline double +dLogConst(double angle, double& a3, double& b3) +{ + // + // a3 == eta + // + static constexpr double tol = 1.0/20.0; + + double ahalf = angle/2.0; + double angle2 = angle*angle; + double angle3 = angle*angle2; + double angle4 = angle*angle3; + double angle5 = angle*angle4; + double angle6 = angle*angle5; + + double a1; + if (std::fabs(angle) > tol) [[unlikely]] { + // a0 = 1.0 + angle2/2.0; + a1 = ahalf/std::tan(ahalf); + + a3 = (1.0 - a1)/angle2; + // a3 = (2.0*sn - angle*(1.0+cs))/(2.0*angle2*sn); + // a3 = (1.0 - 0.5*angle*cot(0.5*angle))/angle2; + + // b3 = (angle*(angle + 2.0*hsn*hcs) - 8.0*hsn*hsn)/(4.0*angle4*hsn*hsn); // wrong? + // b3 = (angle*(angle + std::sin(angle)) - 8.0*hsn*hsn)/(4.0*angle4*hsn*hsn); + // b3 = std::fma(angle, angle + sn, 4.0*(cs - 1.0))/(2.0*angle4*(1.0 - cs)); + // b3 = std::fma(angle, angle + 2.0*hsn*hcs, -8.0*hsn*hsn)/(4.0*angle4*hsn*hsn); + b3 = std::fma(a1, a1 + 1.0, 0.25 * angle2 - 2.0)/angle4; + } + else { + // Maclaurin series + a1 = 1.0 - angle2/12.0 + angle4/720.0 - angle6/30240.0; + a3 = 1.0/12. + angle2/720. + angle4/30240. + angle6/1209600.; + b3 = 1.0/360. + angle2/7560. + angle4/201600. + angle6/5987520.; + } + return 0.0; +} + +static inline Vector3D +RescaleVector(const Vector3D &v, double &angle) +{ + static constexpr double pi = 3.14159265358979323846; + static constexpr double two_pi = 2.0 * pi; + static constexpr double eps = 1e-8; // pole-avoidance band + + Vector3D u = v; + + // NOTE: Currently we are skipping the rescaling as it is not generally + // needed by the formulations that have been ported to OpenSees from + // FEDEASLab. + return u; + + // Fast exit when |angle| already <= pi (no poles inside) + if (std::fabs(angle) <= pi) + return u; + + // Wrap once modulo 2pi + double wrapped = std::remainder(angle, two_pi); // (-pi, pi] + + // Nudge away from the sole pole at 0 + if (std::fabs(wrapped) < eps) + wrapped = (wrapped < 0.0 ? -eps : eps); + +// #define PRINCIPAL_WRAP +#ifndef PRINCIPAL_WRAP + // Keep original magnitude unless it was near a pole + if (std::fabs(angle) > pi && std::fabs(wrapped) >= eps) + wrapped = angle; +#endif + + // Rescale u + if (std::fabs(angle) > eps) { // safe denominator + double scale = wrapped / angle; + for (int i = 0; i < 3; ++i) + u[i] *= scale; + } + + angle = wrapped; + return u; +} +} + +inline Matrix3D +dLogSO3(const Vector3D &v, double* a=nullptr) +{ + //===--------------------------------------------------------------------===// + // + // d_R LogSO3(v) = Eye3 - 0.5*Sv + eta*Sv*Sv; + // + //===--------------------------------------------------------------------===// + // + + double angle = v.norm(); + const Vector3D u = Utility::RescaleVector(v, angle); + + double eta, mu; + Utility::dLogConst(angle, eta, mu); + + Matrix3D dH = Eye3; + dH.addSpin(u, -0.5); + dH.addSpinSquare(u, eta); + return dH; +} + +inline Matrix3D +ddLogSO3(const Vector3D& u, const Vector3D& p) +{ + // + // -0.5*Hat(v) + eta*(Eye3*th.dot(v) + th.bun(v) - 2.*v.bun(th)) + mu*St2*v.bun(th); + // + double angle = u.norm(); + const Vector3D th = Utility::RescaleVector(u, angle); + + double eta, mu; + Utility::dLogConst(angle, eta, mu); + + Matrix3D St2 = Hat(th); + St2 = St2*St2; + Matrix3D dH{}; + dH.addSpin(p, -0.5); + dH.addDiagonal( eta*th.dot(p)); + dH.addTensorProduct(th, p, eta); + dH.addTensorProduct(p, th, -2.0*eta); + dH.addMatrixProduct(St2, p.bun(th), mu); + + return dH*dLogSO3(th); +} diff --git a/SRC/matrix/Matrix3D.h b/SRC/matrix/Matrix3D.h new file mode 100644 index 0000000000..f8a6a57fc9 --- /dev/null +++ b/SRC/matrix/Matrix3D.h @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// + +#ifndef Matrix3D_H +#define Matrix3D_H + +#include "MatrixND.h" +#include + +namespace OpenSees { + + using Matrix3D = MatrixND<3,3,double>; + + static_assert(std::is_trivially_copyable::value, "Matrix3D is not trivially copyable."); + static_assert(std::is_trivial::value, "Matrix3D is not trivial."); + static_assert(std::is_standard_layout::value, "Matrix3D is not standard layout."); + static_assert(std::is_aggregate::value, "Matrix3D is not an aggregate type."); +} + +#endif // Matrix3D_H diff --git a/SRC/matrix/MatrixND.h b/SRC/matrix/MatrixND.h new file mode 100644 index 0000000000..f078b862a8 --- /dev/null +++ b/SRC/matrix/MatrixND.h @@ -0,0 +1,319 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Desctiption: MatrixND is a fixed-size matrix class that is suitable for +// stack-allocation. +// +// Claudio Perez +// +#pragma once +#include +#include +#include + +#include "VectorND.h" +#include "Matrix.h" +#include "Vector.h" + +namespace OpenSees { + +template +struct alignas(64) MatrixND { + std::array values; + + // + // Indexing + // + inline constexpr T& operator()(int i, int j) noexcept { return values[j*NR + i]; } + inline constexpr const T& operator()(int i, int j) const noexcept { return values[j*NR + i]; } + + constexpr T* data() noexcept { return &(*this)(0,0); } + inline constexpr const T* data() const noexcept { return values.data(); } + + // Convert to regular Matrix class + operator Matrix() { return Matrix(&(*this)(0,0), NR, NC);} + + operator const Matrix() const { return Matrix(&(*this)(0,0), NR, NC);} + + constexpr void zero() noexcept; + + constexpr MatrixND transpose() const noexcept; + + constexpr MatrixND& addDiagonal(const double vol) noexcept; + + template + void addMatrix(const MatT& A, const double scale); + + template constexpr MatrixND& + addTensorProduct(const VecA& V, const VecB& W, const double scale) noexcept; + + template void + addMatrixProduct(const MatrixND &, const MatT&, double scale); + + template void + addMatrixProduct(double, const MatrixND &, const MatT&, double scale); + + // += A'B + template void + addMatrixTransposeProduct(double thisFact, const MatrixND &, const MatT&, double scale); + + // += A'BA + template int + addMatrixTripleProduct(double thisFact, + const MatrixND &, + const MatrixND&, + double scale); + + // += A'BC + template int + addMatrixTripleProduct(double thisFact, + const MatrixND &A, + const MatrixND &B, + const MatrixND &C, double otherFact); + + template void map(F func) const; + template void map(F func, MatrixND& destination); + + template constexpr MatrixND& addSpin(const VecT& V) noexcept; + template constexpr MatrixND& addSpin(const VecT& V, double scale) noexcept; + template constexpr MatrixND& addSpinSquare(const VecT& V, double scale) noexcept; + template constexpr void addSpinProduct(const VecT& a, const VectorND& b, double scale) noexcept; + template constexpr void + addMatrixSpinProduct(const MatrixND& A, const VecT& b, double scale) noexcept; + template constexpr void + addSpinMatrixProduct(const VectorND& a, const MatT& B, double scale) noexcept; + + int invert(MatrixND &) const; + + template + inline MatrixND + extract() const noexcept; + + template + inline MatrixND + extract(int row0, int col0) const noexcept; + + template + inline constexpr void + insert(const MatrixND &M, double fact) noexcept; + + template + inline constexpr void + insert(const MatrixND &M, int init_row, int init_col, double fact) noexcept; + + template + constexpr inline void + assemble(const MatrixND &M, int init_row, int init_col, double fact) noexcept; + + template inline void + assemble(const VectorND &v, int init_row, int init_col, double fact) noexcept; + + template inline void + assembleTranspose(const MatrixND &M, int init_row, int init_col, double fact) noexcept; + + template void + assembleTranspose(const VectorND &v, int init_row, int init_col, double scale) noexcept; + + +// +// Operators +// + + constexpr MatrixND & + operator=(const Matrix &other) noexcept + { + for (index_t j = 0; j < NC; ++j) { + for (index_t i = 0; i < NR; ++i) { + (*this)(i,j) = other(i,j); + } + } + return *this; + } + + constexpr MatrixND & + operator+=(const double value) noexcept { + for (index_t j = 0; j < NC; ++j) { + for (index_t i = 0; i < NR; ++i) { + (*this)(i,j) += value; + } + } + return *this; + } + + constexpr MatrixND & + operator+=(const MatrixND &other) noexcept { + for (index_t j = 0; j < NC; ++j) { + for (index_t i = 0; i < NR; ++i) { + (*this)(i,j) += other(i,j); + } + } + return *this; + } + + constexpr MatrixND & + operator-=(const MatrixND &other) noexcept + { + for (index_t j = 0; j < NC; ++j) + for (index_t i = 0; i < NR; ++i) + (*this)(i,j) -= other(i,j); + + return *this; + } + + inline constexpr MatrixND & + operator*=(T const scalar) noexcept + { + for (index_t j = 0; j < NC; ++j) + for (index_t i = 0; i < NR; ++i) + (*this)(i,j) *= scalar; + + return *this; + } + + inline constexpr MatrixND & + operator/=(T const scalar) noexcept + { + for (index_t j = 0; j < NC; ++j) + for (index_t i = 0; i < NR; ++i) + (*this)(i,j) /= scalar; + + return *this; + } + + inline constexpr VectorND + operator^(const VectorND &V) const noexcept + { + VectorND result; + + const double *dataPtr = &(*this)(0,0); + for (int i=0; i + inline constexpr friend MatrixND + operator*(const MatrixND &left, const MatrixND &right) noexcept { + MatrixND prod; + if constexpr (NR*NC > 16) + prod.addMatrixProduct(0, left, right, 1); + else + for (index_t i = 0; i < NR; ++i) { + for (index_t j = 0; j < J; ++j) { + prod(i, j) = 0.0; + for (index_t k = 0; k < NC; ++k) { + prod(i, j) += left(i,k) * right(k,j); + } + } + } + return prod; + } + + template + friend MatrixND + operator*(const MatrixND &left, const Matrix &right) noexcept { + MatrixND prod; + for (index_t i = 0; i < NR; ++i) { + for (index_t j = 0; j < J; ++j) { + prod(i, j) = 0.0; + for (index_t k = 0; k < NC; ++k) { + prod(i, j) += left(i,k) * right(k,j); + } + } + } + return prod; + } + + // Matrix*Vector + constexpr friend VectorND + operator*(const MatrixND &left, const VectorND &right) noexcept { + VectorND prod; + for (index_t i = 0; i < NR; ++i) { + prod[i] = 0.0; + for (index_t k = 0; k < NC; ++k) { + prod[i] += left(i,k) * right[k]; + } + } + return prod; + } + + friend VectorND + operator*(const MatrixND &left, const Vector &right) noexcept { + VectorND prod; + for (index_t i = 0; i < NR; ++i) { + prod[i] = 0.0; + for (index_t k = 0; k < NC; ++k) { + prod[i] += left(i,k) * right(k); + } + } + return prod; + } + + template + inline constexpr friend MatrixND + operator^(const MatrixND &left, const MatrixND &right) { + MatrixND prod; + if constexpr (NR*NC > 48) + prod.addMatrixTransposeProduct(0.0, left, right, 1.0); + else { + for (index_t i = 0; i < NC; ++i) { + for (index_t j = 0; j < K; ++j) { + prod(i, j) = 0.0; + for (index_t k = 0; k < NR; ++k) { + prod(i, j) += left(k,i) * right(k,j); + } + } + } + } + return prod; + } + + friend constexpr MatrixND + operator/(MatrixND mat, T scalar) { + mat /= scalar; + return mat; + } +}; + +} // namespace OpenSees +#include "MatrixND.tpp" diff --git a/SRC/matrix/MatrixND.tpp b/SRC/matrix/MatrixND.tpp new file mode 100644 index 0000000000..68f9a67342 --- /dev/null +++ b/SRC/matrix/MatrixND.tpp @@ -0,0 +1,464 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +#pragma once +#include "MatrixND.h" + +#include "routines/xblas.h" +#include "routines/cmx.h" + +namespace OpenSees { + +template +MatrixND(const T (&)[nc][nr])->MatrixND; + + +template +constexpr void +MatrixND::zero() noexcept +{ + values.fill(T{}); +} + + +template +constexpr MatrixND +MatrixND::transpose() const noexcept +{ + MatrixND result = {}; + for (index_t j = 0; j < nc; ++j) { + for (index_t i = 0; i < nr; ++i) { + result(j,i) = (*this)(i,j); + } + } + return result; +} + + +template +template inline void +MatrixND::map(F func) const +{ + for (int i=0; i +template inline void +MatrixND::map(F func, MatrixND& destination) +{ + for (int i=0; i +template inline void +MatrixND::assemble(const VectorND &v, int init_row, int init_col, double fact) noexcept +{ + + [[maybe_unused]] int final_row = init_row + nr - 1; + assert((init_row >= 0) && (final_row < NR)); + + for (int j=0; j +template void +MatrixND::assembleTranspose(const MatrixND &M, int init_row, int init_col, double fact) noexcept +{ + { + [[maybe_unused]] int final_row = init_row + nc - 1; + [[maybe_unused]] int final_col = init_col + nr - 1; + assert((init_row >= 0) && (final_row < NR) && (init_col >= 0) && (final_col < NC)); + } + + for (int i=0; i +template void +MatrixND::assembleTranspose(const VectorND &v, int init_row, int init_col, double scale) noexcept +{ + { + [[maybe_unused]] int final_col = init_col + nr - 1; + assert((init_row >= 0) && (init_col >= 0) && (final_col < NC)); + } + + for (int i=0; i inline int +MatrixND::invert(MatrixND &M) const +{ + static_assert(nr == nc, "Matrix must be square"); + + int status = -1; + if constexpr (nr == 2) { + cmx_inv2(&(*this)(0,0), &M(0,0), &status); + return status; + } + if constexpr (nr == 3) { + cmx_inv3(&(*this)(0,0), &M(0,0), &status); + return status; + } + if constexpr (nr == 4) { + cmx_inv4(&(*this)(0,0), &M(0,0), &status); + return status; + } + if constexpr (nr == 5) { + cmx_inv5(&(*this)(0,0), &M(0,0), &status); + return status; + } + if constexpr (nr == 6) { + cmx_inv6(&(*this)(0,0), &M(0,0), &status); + return status; + } + + // Use Lapack + M.zero(); + M.addDiagonal(1.0); // Identity matrix + + MatrixND work = *this; + + int pivot_ind[nr]; + int nrhs = nr; + int info = 0; + int m = nr; + int n = nc; + DGESV(&m, + &nrhs, + &work(0,0), &m, + pivot_ind, + &M(0,0), + &n, + &info); + + if (info != 0) + status = -std::abs(info); + return status; +} + +template +constexpr MatrixND& +MatrixND::addDiagonal(const double diag) noexcept +{ + for (int i=0; i +template inline +void MatrixND::addMatrix(const MatT& A, const double scale) +{ + for (int i=0; i +template +constexpr inline +MatrixND& +MatrixND::addTensorProduct(const VecA& a, const VecB& b, const double scale) noexcept +{ + // Chrystal's bun order + for (int j=0; j +template inline +void +MatrixND::addMatrixProduct(const MatrixND& A, const MatT& B, double scale) +{ + if constexpr (nr*nc < 48) + for (int i=0; i(&A(0,0)), &m, + const_cast(&B(0,0)), &k, + &one, &(*this)(0,0), &m); + } +} + +#if 1 +template +template inline +void +MatrixND::addMatrixProduct(double scale_this, + const MatrixND& A, + const MatT& B, double scale) +{ + int m = nr, + n = nc, + k = nk; + DGEMM("N", "N", &m, &n, &k, &scale, + const_cast(&A(0,0)), &m, + const_cast(&B(0,0)), &k, + &scale_this, &(*this)(0,0), &m); +} +#endif + +// B'*C +template +template inline +void +MatrixND::addMatrixTransposeProduct(double thisFact, + const MatrixND& B, + const MatT& C, + double otherFact) +{ + if constexpr (nr*nc > 16) { + int m = nr, + n = nc, + k = nk; + DGEMM("T", "N", &m, &n, &k, &otherFact, + const_cast(&B(0,0)), &k, + const_cast(&C(0,0)), &k, + &thisFact, &(*this)(0,0), &m); + return; + } + + if (thisFact == 1.0) { + double *aijPtr =this->data(); + for (int j=0; jdata(); + for (int j=0; jdata(); + for (int j=0; j +template inline +int +MatrixND::addMatrixTripleProduct( + double thisFact, + const MatrixND &T, + const MatrixND &B, + double otherFact) +{ + if (otherFact == 0.0 && thisFact == 1.0) + return 0; + + MatrixND BT; + BT.zero(); + BT.addMatrixProduct(B, T, otherFact); + this->addMatrixTransposeProduct(thisFact, T, BT, 1.0); + return 0; +} + + +template +template inline int +MatrixND::addMatrixTripleProduct(double thisFact, + const MatrixND &A, + const MatrixND &B, + const MatrixND &C, double otherFact) +{ + if (otherFact == 0.0 && thisFact == 1.0) + return 0; + + MatrixND BC {}; + BC.addMatrixProduct(B, C, otherFact); + this->addMatrixTransposeProduct(thisFact, A, BC, 1.0); + return 0; +} + + +// +// 3D +// + +template +template +constexpr MatrixND& +MatrixND::addSpin(const VecT& v) noexcept +{ + static_assert(NR == 3 && NC == 3, "addSpin requires a 3x3 matrix"); + + const double v0 = v[0], + v1 = v[1], + v2 = v[2]; + + (*this)(0, 0) += 0.0; (*this)(0, 1) += -v2; (*this)(0, 2) += v1; + (*this)(1, 0) += v2; (*this)(1, 1) += 0.0; (*this)(1, 2) += -v0; + (*this)(2, 0) += -v1; (*this)(2, 1) += v0; (*this)(2, 2) += 0.0; + + return *this; +} + + +template +template +constexpr MatrixND& +MatrixND::addSpin(const VecT& v, double mult) noexcept +{ + const double v0 = mult*v[0], + v1 = mult*v[1], + v2 = mult*v[2]; + + (*this)(0, 0) += 0.0; (*this)(0, 1) += -v2; (*this)(0, 2) += v1; + (*this)(1, 0) += v2; (*this)(1, 1) += 0.00; (*this)(1, 2) += -v0; + (*this)(2, 0) += -v1; (*this)(2, 1) += v0; (*this)(2, 2) += 0.0; + return *this; +} + + +template +template +constexpr +MatrixND& +MatrixND::addSpinSquare(const VecT& v, const double scale) noexcept +{ + static_assert(NR == 3 && NC == 3, "addSpinSquare requires a 3x3 matrix"); + const double v1 = v[0], + v2 = v[1], + v3 = v[2]; + + (*this)(0,0) += scale*( -v2*v2 - v3*v3 ); + (*this)(1,1) += scale*( -v1*v1 - v3*v3 ); + (*this)(2,2) += scale*( -v1*v1 - v2*v2 ); + + (*this)(0,1) += scale*( v1*v2 ); + (*this)(1,0) += scale*( v1*v2 ); + (*this)(2,0) += scale*( v1*v3 ); + (*this)(0,2) += scale*( v1*v3 ); + (*this)(1,2) += scale*( v2*v3 ); + (*this)(2,1) += scale*( v2*v3 ); + return *this; +} + + +template +template +constexpr void +MatrixND::addSpinProduct(const VecT& a, const VectorND& b, const double scale) noexcept +{ + // a^b^ = boa - a.b 1 + // where 'o' denotes the tensor product and '.' the dot product + // + static_assert(NR == 3 && NC == 3, "Matrix must be 3x3"); + this->addTensorProduct(b, a, scale); + this->addDiagonal(-b.dot(a)*scale); +} + +template +template +constexpr void +MatrixND::addMatrixSpinProduct(const MatrixND& A, const VecT& b, const double scale) noexcept +{ + // this += s*A*[b^] + // where b^ is the skew-symmetric representation of the three-vector b, s is a scalar, + // and A a 3x3 matrix. + // + (*this)(0, 0) += scale*( A(0,1)*b[2] - A(0,2)*b[1]); + (*this)(0, 1) += scale*(-A(0,0)*b[2] + A(0,2)*b[0]); + (*this)(0, 2) += scale*( A(0,0)*b[1] - A(0,1)*b[0]); + (*this)(1, 0) += scale*( A(1,1)*b[2] - A(1,2)*b[1]); + (*this)(1, 1) += scale*(-A(1,0)*b[2] + A(1,2)*b[0]); + (*this)(1, 2) += scale*( A(1,0)*b[1] - A(1,1)*b[0]); + (*this)(2, 0) += scale*( A(2,1)*b[2] - A(2,2)*b[1]); + (*this)(2, 1) += scale*(-A(2,0)*b[2] + A(2,2)*b[0]); + (*this)(2, 2) += scale*( A(2,0)*b[1] - A(2,1)*b[0]); +} + +template +template +constexpr void +MatrixND::addSpinMatrixProduct(const VectorND& a, const MatT& B, const double scale) noexcept +{ + static_assert(NR == 3 && NC == 3, "Matrix must be 3x3"); + // this += s*[a^]*B + // where a^ is the skew-symmetric representation of the three-vector a, s is a scalar, + // and B a 3x3 matrix. + // + (*this)(0, 0) += scale*( -B(1,0)*a[2] + B(2,0)*a[1]); + (*this)(0, 1) += scale*( -B(1,1)*a[2] + B(2,1)*a[1]); + (*this)(0, 2) += scale*( -B(1,2)*a[2] + B(2,2)*a[1]); + (*this)(1, 0) += scale*( B(0,0)*a[2] - B(2,0)*a[0]); + (*this)(1, 1) += scale*( B(0,1)*a[2] - B(2,1)*a[0]); + (*this)(1, 2) += scale*( B(0,2)*a[2] - B(2,2)*a[0]); + (*this)(2, 0) += scale*( -B(0,0)*a[1] + B(1,0)*a[0]); + (*this)(2, 1) += scale*( -B(0,1)*a[1] + B(1,1)*a[0]); + (*this)(2, 2) += scale*( -B(0,2)*a[1] + B(1,2)*a[0]); +} +} // namespace OpenSees diff --git a/SRC/matrix/Vector3D.h b/SRC/matrix/Vector3D.h new file mode 100644 index 0000000000..8c3c76f38d --- /dev/null +++ b/SRC/matrix/Vector3D.h @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Implementation of a 3D Vector. The purpose of this file is to ensure that +// the VectorND class is as transparent to the compiler as possible. +// In particular, we want to ensure that the Vector3D class is +// - trivially copyable (i.e., can be copied with memcpy) +// - trivial (i.e., has no user-defined constructors, destructors, or copy) +// - standard layout (i.e., has no virtual functions, no base classes, and no +// +// Written: cmp +// +#ifndef Vector3D_h +#define Vector3D_h + +#include +#include + +using Vector3D = OpenSees::VectorND<3, double>; + +static_assert(std::is_standard_layout::value, "Vector3D is not standard layout."); +static_assert(std::is_aggregate::value, "Vector3D is not an aggregate type."); + +static_assert(std::is_trivially_copyable::value, "Vector3D is not trivially copyable."); +static_assert(std::is_trivially_move_assignable::value, "Vector3D is not trivially move assignable."); +static_assert(std::is_trivial::value, "Vector3D is not trivial."); + +static_assert(std::is_nothrow_constructible::value, "Vector3D is not nothrow constructible."); +static_assert(std::is_nothrow_move_assignable::value, "Vector3D is not nothrow move assignable."); + +#endif // Vector3D_h diff --git a/SRC/matrix/VectorND.h b/SRC/matrix/VectorND.h new file mode 100644 index 0000000000..d1f3fd9a6f --- /dev/null +++ b/SRC/matrix/VectorND.h @@ -0,0 +1,289 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Claudio Perez +// +#ifndef VectorND_H +#define VectorND_H +#include +#include +#include +#include + + +namespace OpenSees { + +typedef int index_t; + +template struct MatrixND; + +template +struct VectorND { + T values[N]; + + operator Vector() { return Vector(values, N);} + + template friend struct MatrixND; + + // + template inline void + assemble(const VectorND &v, double fact=1); + + template void + assemble(int a, const VectorND& v, double scale) noexcept; + + template inline void + insert(const VectorND &v, double fact=1); + + template void + insert(int a, const VectorND& v, double scale) noexcept; + + template + VectorND + extract(int a) noexcept; + + int + addVector(const T thisFact, const VectorND &other, const T otherFact) noexcept; + + VectorND &addCross(const VectorND& a, const VectorND &b, double fact = 1.0) { + static_assert(N == 3); + values[0] += fact * (a.values[1] * b.values[2] - a.values[2] * b.values[1]); + values[1] += fact * (a.values[2] * b.values[0] - a.values[0] * b.values[2]); + values[2] += fact * (a.values[0] * b.values[1] - a.values[1] * b.values[0]); + return *this; + } + +#ifdef XARA_VECTOR_FRIENDS + template + inline int + addMatrixVector(double thisFact, const MatrixND &m, const Vector& v, double otherFact); + + template + inline int + addMatrixTransposeVector(double thisFact, const MatrixND &m, + const Vector &v, double otherFact); + + inline int + addMatrixVector(const double thisFact, const Matrix &m, const Vector &v, const double otherFact); + + int + addVector(const T thisFact, const Vector &other, const T otherFact) noexcept; +#endif + + constexpr int + size() const { + return N; + } + + constexpr inline void + fill(double value) { + for (T& item : values) + item = value; + } + + constexpr inline void + zero() { + for (T& item : values ) + item = 0.0; + } + + template + constexpr T + dot(const VecT &other) const noexcept { + T sum = 0.0; + for (index_t i = 0; i < N; ++i) + sum += values[i] * other[i]; + + return sum; + } + + // Tensor product, also known as the "bun" product + template + constexpr inline MatrixND + bun(const VectorND &other) const noexcept { + if constexpr (N == 3 && nc == 3) + return MatrixND {{ + values[0]*other[0], values[1]*other[0], values[2]*other[0] , + values[0]*other[1], values[1]*other[1], values[2]*other[1] , + values[0]*other[2], values[1]*other[2], values[2]*other[2] + }}; + + else { + MatrixND prod; + + for (index_t j = 0; j < other.size(); ++j) + for (index_t i = 0; i < this->size(); ++i) + prod(i,j) = values[i] * other.values[j]; + + return prod; + } + } + + // Return the cross product this vector with another vector, b. + template + constexpr void + cross(const VecB& b, VecC& c) const noexcept { + static_assert(N == 3, "Cross product is only defined for 3D vectors."); + c[0] = values[1] * b[2] - values[2] * b[1]; + c[1] = values[2] * b[0] - values[0] * b[2]; + c[2] = values[0] * b[1] - values[1] * b[0]; + return c; + } + + + template + constexpr VectorND + cross(const Vec3T& b) const noexcept { + static_assert(N == 3, "Cross product is only defined for 3D vectors."); + // Return a new vector that is the cross product of this vector and b. + VectorND<3> c; + c[0] = values[1] * b[2] - values[2] * b[1]; + c[1] = values[2] * b[0] - values[0] * b[2]; + c[2] = values[0] * b[1] - values[1] * b[0]; + return c; + } + + + constexpr double + norm() const noexcept { + return std::sqrt(std::fabs(this->dot(*this))); + } + + inline double + normalize() { + double n = norm(); + + if (n != 0.0) + for (index_t i=0; i= 0 && index < N); + return values[index]; + } + + inline constexpr const T& + operator[](index_t index) const noexcept { + assert(index >= 0 && index < N); + return values[index]; + } + + inline constexpr T& + operator()(index_t index) noexcept { + return values[index]; + } + + inline constexpr const T& + operator()(index_t index) const noexcept { + return values[index]; + } + + template inline + VectorND &operator=(const VecT &right) noexcept { + for (index_t i=0; i< N; i++) + values[i] = right[i]; + return *this; + } + + inline + VectorND & + operator/=(const double &right) noexcept { + for (index_t i=0; i< N; i++) + values[i] /= right; + return *this; + } + + inline + VectorND + operator/(const double &right) const noexcept { + VectorND res(*this); + res /= right; + return res; + } + + inline constexpr + VectorND & + operator*=(const double &right) noexcept{ + for (int i=0; i< N; i++) + values[i] *= right; + return *this; + } + + inline constexpr + VectorND + operator*(const double &right) const noexcept { + VectorND res(*this); + res *= right; + return res; + } + + inline constexpr + VectorND & + operator+=(const VectorND &right) noexcept { + for (int i=0; i< N; i++) + values[i] += right[i]; + return *this; + } + + constexpr inline + VectorND & + operator+=(const Vector &right) noexcept { + assert(right.Size() == N); + for (int i=0; i< N; i++) + values[i] += right[i]; + return *this; + } + + template + VectorND operator+(const VecT &right) const noexcept { + VectorND res {*this}; + res += right; + return res; + } + + template + constexpr inline + VectorND &operator-=(const VecT &right) noexcept { + for (int i=0; i< N; i++) + values[i] -= right[i]; + return *this; + } + + template + constexpr inline + VectorND operator-(const VecT &right) const noexcept { + VectorND res {*this}; + res -= right; + return res; + } + +}; +} // namespace OpenSees + +#include "VectorND.tpp" + +template +constexpr inline OpenSees::VectorND +operator * (double a, const OpenSees::VectorND& b) noexcept { + return b * a; +} + +#endif + diff --git a/SRC/matrix/VectorND.tpp b/SRC/matrix/VectorND.tpp new file mode 100644 index 0000000000..c33b06761e --- /dev/null +++ b/SRC/matrix/VectorND.tpp @@ -0,0 +1,416 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ +// +#include +#include "VectorND.h" +#include "routines/xblas.h" + + +namespace OpenSees { + +template +template inline void +VectorND::assemble(const VectorND &v, double fact) +{ + static_assert((ir >= 0) && ((ir + nr - 1) < N)); + + for (int j=0; j +template void +VectorND::assemble(int a, const VectorND& v, double scale) noexcept +{ + for (int i=0; i +template inline void +VectorND::insert(const VectorND &v, double fact) +{ + static_assert((ir >= 0) && ((ir + nr - 1) < N)); + + for (int j=0; j +template void +VectorND::insert(int a, const VectorND& v, double scale) noexcept +{ + for (int i=0; i +template +VectorND +VectorND::extract(int a) noexcept +{ + VectorND v; + for (int i=0; i +int +VectorND::addVector(const T thisFact, const Vector &other, const T otherFact) noexcept +{ + if (otherFact == 0.0 && thisFact == 1.0) + return 0; + + else if (thisFact == 1.0) { + // want: this += other * otherFact + double *dataPtr = values; + double *otherDataPtr = other.theData; + if (otherFact == 1.0) { + // no point doing a multiplication if otherFact == 1.0 + for (int i=0; i +template +inline int +VectorND::addMatrixVector(double thisFact, const MatrixND &m, const Vector& v, double otherFact) +{ + // check the sizes are compatable + assert(NC == v.sz); + + // see if quick return + if (thisFact == 1.0 && otherFact == 0.0) + return 0; + + else { + int incr = 1, + i = N, + n = NC; + DGEMV("N", &i, &n, + &otherFact, + &m(0,0), &i, + v.theData, &incr, + &thisFact, + values, + &incr); + + return 0; + } +} + + +template +template +inline int +VectorND::addMatrixTransposeVector(double thisFact, const MatrixND &m, const Vector &v, double otherFact) +{ + // check the sizes are compatable + assert(NR == v.sz); + + + if (thisFact == 1.0 && otherFact == 0.0) + return 0; + + else { + int incr = 1, + i = NR, + n = N; + DGEMV("T", &i, &n, + &otherFact, + &m(0,0), &i, + v.theData, &incr, + &thisFact, + values, &incr); + return 0; + } +} + + +template +inline int +VectorND::addMatrixVector(const double thisFact, const Matrix &m, const Vector &v, const double otherFact) +{ + // check the sizes are compatable + assert(N == m.noRows()); + assert(m.noCols() == v.sz); + + // see if quick return + if (thisFact == 1.0 && otherFact == 0.0) + return 0; + +#ifdef VECTOR_BLAS + else if (v.sz > 10) { + int incr = 1, + i = m.numRows, + n = m.numCols; + return + DGEMV("N", &i, &n, + &otherFact, + m.data, &i, + v.theData, &incr, + &thisFact, + values, &incr); + } +#endif + + else if (thisFact == 1.0) { + + // want: this += m * v * otherFact + if (otherFact == 1.0) { // no point doing multiplication if otherFact = 1.0 + int otherSize = v.sz; + double *matrixDataPtr = m.data; + const double *otherDataPtr = v.theData; + for (int i=0; i +int +VectorND::addVector(const T thisFact, const VectorND &other, const T otherFact) noexcept +{ + if (otherFact == 0.0 && thisFact == 1.0) + return 0; + + else if (thisFact == 1.0) { + // want: this += other * otherFact + double *dataPtr = values; + const double * otherDataPtr = other.values; + if (otherFact == 1.0) { // no point doing a multiplication if otherFact == 1.0 + for (int i=0; i +#include +#include + + +namespace OpenSees { + +struct Versor { + Vector3D vector; + double scalar; + + template + static inline Versor from_vector(const Vec3T &); + + static inline Versor from_matrix(const Matrix3D &); + + template + inline Vec3T + rotate(const Vec3T& u) const { + return u + 2.0 * vector.cross( scalar*u + vector.cross(u) ); + } + + inline void + normalize() { + static constexpr double eps = 1e-12; + + double n2 = scalar*scalar + vector.dot(vector); + + // bad numbers; reset to identity + if (!std::isfinite(n2) || n2 < eps) { + scalar = 1.0; + vector[0] = vector[1] = vector[2] = 0.0; + return; + } + + // already close enough to unit + constexpr double tol = 1e-6; + if (std::abs(n2 - 1.0) < tol) + return; + + // normalize + double inv_n = 1.0 / std::sqrt(n2); + scalar *= inv_n; + vector[0] *= inv_n; + vector[1] *= inv_n; + vector[2] *= inv_n; + } + + inline constexpr Versor + conjugate() const noexcept { + return Versor{{-vector[0], -vector[1], -vector[2]}, scalar}; + } + + inline Versor + conj_mult(const Versor& other) const noexcept + { + // Equivalent to R_IJ = R_I.T @ R_J, + // i.e. q_IJ = conj(q_I)*q_J. + Versor qij; + qij.scalar = scalar * other.scalar + vector.dot(other.vector); + qij.vector = (other.vector * scalar) - (vector * other.scalar) - vector.cross(other.vector); + return qij; + } + + inline Versor + mult_conj(const Versor& other) const noexcept + { + // Equivalent to R_IJ = R_I @ R_J^T, + // i.e. q_IJ = q_I * conj(q_J). + + Versor out; + out.scalar = scalar * other.scalar + vector.dot(other.vector); + out.vector = (vector * other.scalar) + - (other.vector * scalar) + - vector.cross(other.vector); + return out; + } + + + // Unary plus + Versor operator+() const { + return *this; + } + + // Unary minus. + Versor operator-() const { + return {{-vector[0], -vector[1], -vector[2]}, -scalar}; + } +}; + +} // namespace OpenSees + +#include "Versor.tpp" + diff --git a/SRC/matrix/Versor.tpp b/SRC/matrix/Versor.tpp new file mode 100644 index 0000000000..741207f9e7 --- /dev/null +++ b/SRC/matrix/Versor.tpp @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +#include "Versor.h" +#include + +namespace OpenSees { + +static_assert(std::is_trivially_copyable::value, "Versor must be trivially copyable"); + +inline Versor +Versor::from_matrix(const Matrix3D &R) +{ + //===--------------------------------------------------------------------===// + // Form a normalized quaternion (Versor) from a proper orthogonal matrix + // using Spurrier's algorithm + //===--------------------------------------------------------------------===// + Versor q; + + // Trace of the rotation R + const double trR = R(0,0) + R(1,1) + R(2,2); + + // a = max([trR R(0,0) R(1,1) R(2,2)]); + double a = trR; + for (int i = 0; i < 3; i++) + if (R(i,i) > a) + a = R(i,i); + + if (a == trR) { + q.scalar = std::sqrt(1.0 + a)*0.5; + + for (int i = 0; i < 3; i++) { + int j = (i+1)%3; + int k = (i+2)%3; + q.vector[i] = (R(k,j) - R(j,k))/(4.0*q.scalar); + } + } + else { + for (int i = 0; i < 3; i++) + if (a == R(i,i)) { + int j = (i+1)%3; + int k = (i+2)%3; + + q.vector[i] = std::sqrt(std::max(a*0.5 + (1.0 - trR)/4.0, 0.0)); + q.scalar = (R(k,j) - R(j,k))/(4.0*q.vector[i]); + q.vector[j] = (R(j,i) + R(i,j))/(4.0*q.vector[i]); + q.vector[k] = (R(k,i) + R(i,k))/(4.0*q.vector[i]); + } + } + return q; +} + +template +inline Versor +Versor::from_vector(const Vec3T &theta) +{ + double angle2 = 0.0; + for (int i=0; i<3; i++) + angle2 += theta[i]*theta[i]; + + double angle = std::sqrt(angle2); + + Versor q; + double sc, cs; + if (angle2 < 1e-12) { + sc = 0.5 - angle2 / 48.0; // + angle2*angle2 / 3840.0 - angle2*angle2*angle2 / 362880.0; + cs = 1.0 - angle2 / 8.0; // + angle2*angle2 / 384.0 - angle2*angle2*angle2 / 40320.0; + } + else { + sc = std::sin(angle*0.5) / angle; + cs = std::cos(angle*0.5); + } + + for (int i = 0; i < 3; i++) + q.vector[i] = theta[i] * sc; + + q.scalar = cs; + return q; +} +} // namespace OpenSees + + +inline OpenSees::Versor +operator*(const OpenSees::Versor &qa, const OpenSees::Versor &qb) +{ + OpenSees::Versor q12; + q12.scalar = qa.scalar * qb.scalar - qa.vector.dot(qb.vector); + q12.vector = (qb.vector * qa.scalar) + (qa.vector * qb.scalar) + qa.vector.cross(qb.vector); + return q12; +} \ No newline at end of file diff --git a/SRC/matrix/routines/cmx.h b/SRC/matrix/routines/cmx.h new file mode 100644 index 0000000000..9e53a83def --- /dev/null +++ b/SRC/matrix/routines/cmx.h @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// + +#ifndef cmx_h +#define cmx_h + +#ifdef __cplusplus +extern "C" { +#endif + +int cmx_inv2 (const double *a, double *ainv, int*ok_flag); +int cmx_inv3 (const double *a, double *ainv, int*ok_flag); +int cmx_inv4 (const double *a, double *ainv, int*ok_flag); +int cmx_inv5 (const double *a, double *ainv, int*ok_flag); +int cmx_inv6 (const double *a, double *ainv, int*ok_flag); +int cmx_inv6_v2(const double *a, double *ainv, int*ok_flag); +int cmx_inv6_v3(const double *a, double *ainv, int*ok_flag); + +#define cmx_inv(a, inv, flag) _Generic(&(a), \ + double(*)[ 4]: cmx_inv2, \ + double(*)[ 9]: cmx_inv3, \ + double(*)[16]: cmx_inv4, \ + double(*)[25]: cmx_inv5, \ + double(*)[36]: cmx_inv6 \ + )(a, inv, flag) + +#ifdef __cplusplus +} +#endif + +#endif // cmx_h diff --git a/SRC/matrix/routines/invGL2.c b/SRC/matrix/routines/invGL2.c new file mode 100644 index 0000000000..de0c58543b --- /dev/null +++ b/SRC/matrix/routines/invGL2.c @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// adapted by CMP from code by David Simpson at +// https://caps.gsfc.nasa.gov/simpson/software/m22inv_f90.txt +// +#include + +int cmx_inv2(double *a, double *ainv, int *ok_flag__) +{ + /* **************************************************************************************** + * m22inv - compute the inverse of a 2x2 matrix. + * + * a : (input) 2x2 matrix to be inverted + * ainv : (output) 2x2 inverse of matrix a + * + * ok_flag: (output) 0 if the input matrix could be inverted, + * and -1 if the input matrix is singular. + * + * ****************************************************************************************/ + + /* Parameter adjustments */ + ainv -= 3; + a -= 3; + + const double eps = 1e-10; + const double det = a[3] * a[6] - a[5] * a[4]; + if (fabs(det) <= eps) { + *ok_flag__ = -1; + } + + double cofactor[4]; + + cofactor[0] = a[6]; + cofactor[2] = -a[4]; + cofactor[1] = -a[5]; + cofactor[3] = a[3]; + + for (int i__ = 1; i__ <= 2; ++i__) + for (int j = 1; j <= 2; ++j) + ainv[j + (i__ << 1)] = cofactor[i__ + (j << 1) - 3] / det; + + *ok_flag__ = 0; + return 0; +} diff --git a/SRC/matrix/routines/invGL3.c b/SRC/matrix/routines/invGL3.c new file mode 100644 index 0000000000..bc31f2836c --- /dev/null +++ b/SRC/matrix/routines/invGL3.c @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// adapted from https://caps.gsfc.nasa.gov/simpson/software/m33inv_f90.txt +// +#include + + +int cmx_inv3(double *a, double *ainv, int *ok_flag__) +{ +/* **************************************************************************************** */ +/* m33inv - compute the inverse of a 3x3 matrix. */ + +/* a = input 3x3 matrix to be inverted */ +/* ainv = output 3x3 inverse of matrix a */ +/* ok_flag = (output) .true. if the input matrix could be inverted, and */ +/* .false. if the input matrix is singular. */ +/* **************************************************************************************** */ + + + /* Parameter adjustments */ + ainv -= 4; + a -= 4; + + const double det = a[4]*a[8]*a[12] + - a[4]*a[11]*a[9] + - a[7]*a[5]*a[12] + + a[7]*a[11]*a[6] + + a[10]*a[5]*a[9] + - a[10]*a[8]*a[6]; + + const double eps=1e-10; + if (fabs(det) <= eps) { + *ok_flag__ = -1; + // return 0; + } + + double cofactor[9]; + cofactor[0] = a[8]*a[12] - a[11]*a[9]; + cofactor[3] = -(a[5]*a[12] - a[11]*a[6]); + cofactor[6] = a[5]*a[9] - a[8]*a[6]; + cofactor[1] = -(a[7]*a[12] - a[10]*a[9]); + cofactor[4] = a[4]*a[12] - a[10]*a[6]; + cofactor[7] = -(a[4]*a[9] - a[7]*a[6]); + cofactor[2] = a[7]*a[11] - a[10]*a[8]; + cofactor[5] = -(a[4]*a[11] - a[10]*a[5]); + cofactor[8] = a[4]*a[8] - a[7]*a[5]; + + for (int i__ = 1; i__ <= 3; ++i__) + for (int j = 1; j <= 3; ++j) + ainv[j + i__ * 3] = cofactor[i__ + j * 3 - 4] / det; + + *ok_flag__ = 0; + return 0; +} + diff --git a/SRC/matrix/routines/invGL4.c b/SRC/matrix/routines/invGL4.c new file mode 100644 index 0000000000..477d1ce896 --- /dev/null +++ b/SRC/matrix/routines/invGL4.c @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// adapted from https://caps.gsfc.nasa.gov/simpson/software/m44inv_f90.txt +// +#include + +int cmx_inv4(double *a, double *ainv, int *ok_flag__) +{ +/* **************************************************************************************** + * m44inv - compute the inverse of a 4x4 matrix. + + * a = input 4x4 matrix to be inverted + * ainv = output 4x4 inverse of matrix a + * ok_flag = (output) .true. if the input matrix could be inverted, and .false. if the input matrix is singular. + * **************************************************************************************** */ + static double cofactor[16]; + static double eps=1e-10; + + /* Parameter adjustments */ + ainv -= 5; + a -= 5; + + const double det = a[ 5]*(a[10]*(a[15]*a[20] - a[19]*a[16]) + + a[14]*(a[19]*a[12] - a[11]*a[20]) + + a[18]*(a[11]*a[16] - a[15]*a[12])) + - a[ 9]*(a[ 6]*(a[15]*a[20] - a[19]*a[16]) + + a[14]*(a[19]*a[ 8] - a[ 7]*a[20]) + + a[18]*(a[ 7]*a[16] - a[15]*a[ 8])) + + a[13]*(a[ 6]*(a[11]*a[20] - a[19]*a[12]) + + a[10]*(a[19]*a[ 8] - a[ 7]*a[20]) + + a[18]*(a[ 7]*a[12] - a[11]*a[ 8])) + - a[17]*(a[ 6]*(a[11]*a[16] - a[15]*a[12]) + + a[10]*(a[15]*a[ 8] - a[ 7]*a[16]) + + a[14]*(a[ 7]*a[12] - a[11]*a[ 8])); + + if (fabs(det) <= eps) { + *ok_flag__ = -1; + } + + cofactor[ 0] = a[10]*(a[15]*a[20] - a[19]*a[16]) + + a[14]*(a[19]*a[12] - a[11]*a[20]) + + a[18]*(a[11]*a[16] - a[15]*a[12]); + cofactor[ 4] = a[ 6]*(a[19]*a[16] - a[15]*a[20]) + + a[14]*(a[ 7]*a[20] - a[19]*a[ 8]) + + a[18]*(a[15]*a[ 8] - a[ 7]*a[16]); + cofactor[ 8] = a[ 6]*(a[11]*a[20] - a[19]*a[12]) + + a[10]*(a[19]*a[ 8] - a[ 7]*a[20]) + + a[18]*(a[ 7]*a[12] - a[11]*a[ 8]); + cofactor[12] = a[ 6]*(a[15]*a[12] - a[11]*a[16]) + + a[10]*(a[ 7]*a[16] - a[15]*a[ 8]) + + a[14]*(a[11]*a[ 8] - a[ 7]*a[12]); + cofactor[ 1] = a[ 9]*(a[19]*a[16] - a[15]*a[20]) + + a[13]*(a[11]*a[20] - a[19]*a[12]) + + a[17]*(a[15]*a[12] - a[11]*a[16]); + cofactor[ 5] = a[ 5]*(a[15]*a[20] - a[19]*a[16]) + + a[13]*(a[19]*a[ 8] - a[ 7]*a[20]) + + a[17]*(a[ 7]*a[16] - a[15]*a[ 8]); + cofactor[ 9] = a[ 5]*(a[19]*a[12] - a[11]*a[20]) + + a[ 9]*(a[ 7]*a[20] - a[19]*a[ 8]) + + a[17]*(a[11]*a[ 8] - a[ 7]*a[12]); + cofactor[13] = a[ 5]*(a[11]*a[16] - a[15]*a[12]) + + a[ 9]*(a[15]*a[ 8] - a[ 7]*a[16]) + + a[13]*(a[ 7]*a[12] - a[11]*a[ 8]); + cofactor[ 2] = a[ 9]*(a[14]*a[20] - a[18]*a[16]) + + a[13]*(a[18]*a[12] - a[10]*a[20]) + + a[17]*(a[10]*a[16] - a[14]*a[12]); + cofactor[ 6] = a[ 5]*(a[18]*a[16] - a[14]*a[20]) + + a[13]*(a[ 6]*a[20] - a[18]*a[ 8]) + + a[17]*(a[14]*a[ 8] - a[ 6]*a[16]); + cofactor[10] = a[ 5]*(a[10]*a[20] - a[18]*a[12]) + + a[ 9]*(a[18]*a[ 8] - a[ 6]*a[20]) + + a[17]*(a[ 6]*a[12] - a[10]*a[ 8]); + cofactor[14] = a[ 5]*(a[14]*a[12] - a[10]*a[16]) + + a[ 9]*(a[ 6]*a[16] - a[14]*a[ 8]) + + a[13]*(a[10]*a[ 8] - a[ 6]*a[12]); + cofactor[ 3] = a[ 9]*(a[18]*a[15] - a[14]*a[19]) + + a[13]*(a[10]*a[19] - a[18]*a[11]) + + a[17]*(a[14]*a[11] - a[10]*a[15]); + cofactor[ 7] = a[ 5]*(a[14]*a[19] - a[18]*a[15]) + + a[13]*(a[18]*a[ 7] - a[ 6]*a[19]) + + a[17]*(a[ 6]*a[15] - a[14]*a[ 7]); + cofactor[11] = a[ 5]*(a[18]*a[11] - a[10]*a[19]) + + a[ 9]*(a[ 6]*a[19] - a[18]*a[ 7]) + + a[17]*(a[10]*a[ 7] - a[ 6]*a[11]); + cofactor[15] = a[ 5]*(a[10]*a[15] - a[14]*a[11]) + + a[ 9]*(a[14]*a[ 7] - a[ 6]*a[15]) + + a[13]*(a[ 6]*a[11] - a[10]*a[ 7]); + + for (int i__ = 1; i__ <= 4; ++i__) + for (int j = 1; j <= 4; ++j) + ainv[j + (i__ << 2)] = cofactor[i__ + (j << 2) - 5] / det; + + *ok_flag__ = 0; + return 0; +} + diff --git a/SRC/matrix/routines/invGL5.c b/SRC/matrix/routines/invGL5.c new file mode 100644 index 0000000000..1cfbdbfa35 --- /dev/null +++ b/SRC/matrix/routines/invGL5.c @@ -0,0 +1,357 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// adapted from https://caps.gsfc.nasa.gov/simpson/software/m55inv_f90.txt +// +#include + +int cmx_inv5(double *a, double *ainv, int *ok_flag__) +{ +/* **************************************************************************************** + * m55inv - compute the inverse of a 5x5 matrix. + + * a = input 5x5 matrix to be inverted + * ainv = output 5x5 inverse of matrix a + * ok_flag = (output) .true. if the input matrix could be inverted, and .false. if the input matrix is singular. + ***************************************************************************************** */ + static double cofactor[25]; + static double a11, a12, a13, a14, a15, a21, a22, a23, a24, a25, a31, + a32, a33, a34, a35, a41, a42, a43, a44, a45, a51, a52, a53, a54, + a55, det; + + const double eps = 1e-10; + + /* Parameter adjustments */ + ainv -= 6; + a -= 6; + + a11 = a[6]; + a12 = a[11]; + a13 = a[16]; + a14 = a[21]; + a15 = a[26]; + a21 = a[7]; + a22 = a[12]; + a23 = a[17]; + a24 = a[22]; + a25 = a[27]; + a31 = a[8]; + a32 = a[13]; + a33 = a[18]; + a34 = a[23]; + a35 = a[28]; + a41 = a[9]; + a42 = a[14]; + a43 = a[19]; + a44 = a[24]; + a45 = a[29]; + a51 = a[10]; + a52 = a[15]; + a53 = a[20]; + a54 = a[25]; + a55 = a[30]; + det = a15*a24*a33*a42*a51 - a14*a25*a33*a42*a51 - a15* + a23*a34*a42*a51 + a13*a25*a34*a42*a51 + a14*a23* + a35*a42*a51 - a13*a24*a35*a42*a51 - a15*a24*a32* + a43*a51 + a14*a25*a32*a43*a51 + a15*a22*a34*a43* + a51 - a12*a25*a34*a43*a51 - a14*a22*a35*a43*a51 + + a12*a24*a35*a43*a51 + a15*a23*a32*a44*a51 - a13* + a25*a32*a44*a51 - a15*a22*a33*a44*a51 + a12*a25* + a33*a44*a51 + a13*a22*a35*a44*a51 - a12*a23*a35* + a44*a51 - a14*a23*a32*a45*a51 + a13*a24*a32*a45* + a51 + a14*a22*a33*a45*a51 - a12*a24*a33*a45*a51 - + a13*a22*a34*a45*a51 + a12*a23*a34*a45*a51 - a15* + a24*a33*a41*a52 + a14*a25*a33*a41*a52 + a15*a23* + a34*a41*a52 - a13*a25*a34*a41*a52 - a14*a23*a35* + a41*a52 + a13*a24*a35*a41*a52 + a15*a24*a31*a43* + a52 - a14*a25*a31*a43*a52 - a15*a21*a34*a43*a52 + + a11*a25*a34*a43*a52 + a14*a21*a35*a43*a52 - a11* + a24*a35*a43*a52 - a15*a23*a31*a44*a52 + a13*a25* + a31*a44*a52 + a15*a21*a33*a44*a52 - a11*a25*a33* + a44*a52 - a13*a21*a35*a44*a52 + a11*a23*a35*a44* + a52 + a14*a23*a31*a45*a52 - a13*a24*a31*a45*a52 - + a14*a21*a33*a45*a52 + a11*a24*a33*a45*a52 + a13* + a21*a34*a45*a52 - a11*a23*a34*a45*a52 + a15*a24* + a32*a41*a53 - a14*a25*a32*a41*a53 - a15*a22*a34* + a41*a53 + a12*a25*a34*a41*a53 + a14*a22*a35*a41* + a53 - a12*a24*a35*a41*a53 - a15*a24*a31*a42*a53 + + a14*a25*a31*a42*a53 + a15*a21*a34*a42*a53 - a11* + a25*a34*a42*a53 - a14*a21*a35*a42*a53 + a11*a24* + a35*a42*a53 + a15*a22*a31*a44*a53 - a12*a25*a31* + a44*a53 - a15*a21*a32*a44*a53 + a11*a25*a32*a44* + a53 + a12*a21*a35*a44*a53 - a11*a22*a35*a44*a53 - + a14*a22*a31*a45*a53 + a12*a24*a31*a45*a53 + a14* + a21*a32*a45*a53 - a11*a24*a32*a45*a53 - a12*a21* + a34*a45*a53 + a11*a22*a34*a45*a53 - a15*a23*a32* + a41*a54 + a13*a25*a32*a41*a54 + a15*a22*a33*a41* + a54 - a12*a25*a33*a41*a54 - a13*a22*a35*a41*a54 + + a12*a23*a35*a41*a54 + a15*a23*a31*a42*a54 - a13* + a25*a31*a42*a54 - a15*a21*a33*a42*a54 + a11*a25* + a33*a42*a54 + a13*a21*a35*a42*a54 - a11*a23*a35* + a42*a54 - a15*a22*a31*a43*a54 + a12*a25*a31*a43* + a54 + a15*a21*a32*a43*a54 - a11*a25*a32*a43*a54 - + a12*a21*a35*a43*a54 + a11*a22*a35*a43*a54 + a13* + a22*a31*a45*a54 - a12*a23*a31*a45*a54 - a13*a21* + a32*a45*a54 + a11*a23*a32*a45*a54 + a12*a21*a33* + a45*a54 - a11*a22*a33*a45*a54 + a14*a23*a32*a41* + a55 - a13*a24*a32*a41*a55 - a14*a22*a33*a41*a55 + + a12*a24*a33*a41*a55 + a13*a22*a34*a41*a55 - a12* + a23*a34*a41*a55 - a14*a23*a31*a42*a55 + a13*a24* + a31*a42*a55 + a14*a21*a33*a42*a55 - a11*a24*a33* + a42*a55 - a13*a21*a34*a42*a55 + a11*a23*a34*a42* + a55 + a14*a22*a31*a43*a55 - a12*a24*a31*a43*a55 - + a14*a21*a32*a43*a55 + a11*a24*a32*a43*a55 + a12* + a21*a34*a43*a55 - a11*a22*a34*a43*a55 - a13*a22* + a31*a44*a55 + a12*a23*a31*a44*a55 + a13*a21*a32* + a44*a55 - a11*a23*a32*a44*a55 - a12*a21*a33*a44* + a55 + a11*a22*a33*a44*a55; + if (fabs(det) <= eps) { + *ok_flag__ = -1; + return 0; + } + cofactor[0] = a25*a34*a43*a52 - a24*a35*a43*a52 - a25*a33* + a44*a52 + a23*a35*a44*a52 + a24*a33*a45*a52 - a23* + a34*a45*a52 - a25*a34*a42*a53 + a24*a35*a42*a53 + + a25*a32*a44*a53 - a22*a35*a44*a53 - a24*a32*a45* + a53 + a22*a34*a45*a53 + a25*a33*a42*a54 - a23*a35* + a42*a54 - a25*a32*a43*a54 + a22*a35*a43*a54 + a23* + a32*a45*a54 - a22*a33*a45*a54 - a24*a33*a42*a55 + + a23*a34*a42*a55 + a24*a32*a43*a55 - a22*a34*a43* + a55 - a23*a32*a44*a55 + a22*a33*a44*a55; + cofactor[1] = -a15*a34*a43*a52 + a14*a35*a43*a52 + a15*a33 * + a44*a52 - a13*a35*a44*a52 - a14*a33*a45*a52 + a13 * + a34*a45*a52 + a15*a34*a42*a53 - a14*a35*a42*a53 + - a15*a32*a44*a53 + a12*a35*a44*a53 + a14*a32*a45 + *a53 - a12*a34*a45*a53 - a15*a33*a42*a54 + a13*a35 + *a42*a54 + a15*a32*a43*a54 - a12*a35*a43*a54 - a13 + *a32*a45*a54 + a12*a33*a45*a54 + a14*a33*a42*a55 + - a13*a34*a42*a55 - a14*a32*a43*a55 + a12*a34*a43 + *a55 + a13*a32*a44*a55 - a12*a33*a44*a55; + cofactor[2] = a15*a24*a43*a52 - a14*a25*a43*a52 - a15*a23* + a44*a52 + a13*a25*a44*a52 + a14*a23*a45*a52 - a13* + a24*a45*a52 - a15*a24*a42*a53 + a14*a25*a42*a53 + + a15*a22*a44*a53 - a12*a25*a44*a53 - a14*a22*a45* + a53 + a12*a24*a45*a53 + a15*a23*a42*a54 - a13*a25* + a42*a54 - a15*a22*a43*a54 + a12*a25*a43*a54 + a13* + a22*a45*a54 - a12*a23*a45*a54 - a14*a23*a42*a55 + + a13*a24*a42*a55 + a14*a22*a43*a55 - a12*a24*a43* + a55 - a13*a22*a44*a55 + a12*a23*a44*a55; + cofactor[3] = -a15*a24*a33*a52 + a14*a25*a33*a52 + a15*a23 * + a34*a52 - a13*a25*a34*a52 - a14*a23*a35*a52 + a13 * + a24*a35*a52 + a15*a24*a32*a53 - a14*a25*a32*a53 + - a15*a22*a34*a53 + a12*a25*a34*a53 + a14*a22*a35 + *a53 - a12*a24*a35*a53 - a15*a23*a32*a54 + a13*a25 + *a32*a54 + a15*a22*a33*a54 - a12*a25*a33*a54 - a13 + *a22*a35*a54 + a12*a23*a35*a54 + a14*a23*a32*a55 + - a13*a24*a32*a55 - a14*a22*a33*a55 + a12*a24*a33 + *a55 + a13*a22*a34*a55 - a12*a23*a34*a55; + cofactor[4] = a15*a24*a33*a42 - a14*a25*a33*a42 - a15*a23* + a34*a42 + a13*a25*a34*a42 + a14*a23*a35*a42 - a13* + a24*a35*a42 - a15*a24*a32*a43 + a14*a25*a32*a43 + + a15*a22*a34*a43 - a12*a25*a34*a43 - a14*a22*a35* + a43 + a12*a24*a35*a43 + a15*a23*a32*a44 - a13*a25* + a32*a44 - a15*a22*a33*a44 + a12*a25*a33*a44 + a13* + a22*a35*a44 - a12*a23*a35*a44 - a14*a23*a32*a45 + + a13*a24*a32*a45 + a14*a22*a33*a45 - a12*a24*a33* + a45 - a13*a22*a34*a45 + a12*a23*a34*a45; + cofactor[5] = -a25*a34*a43*a51 + a24*a35*a43*a51 + a25*a33 * + a44*a51 - a23*a35*a44*a51 - a24*a33*a45*a51 + a23 * + a34*a45*a51 + a25*a34*a41*a53 - a24*a35*a41*a53 + - a25*a31*a44*a53 + a21*a35*a44*a53 + a24*a31*a45 + *a53 - a21*a34*a45*a53 - a25*a33*a41*a54 + a23*a35 + *a41*a54 + a25*a31*a43*a54 - a21*a35*a43*a54 - a23 + *a31*a45*a54 + a21*a33*a45*a54 + a24*a33*a41*a55 + - a23*a34*a41*a55 - a24*a31*a43*a55 + a21*a34*a43 + *a55 + a23*a31*a44*a55 - a21*a33*a44*a55; + cofactor[6] = a15*a34*a43*a51 - a14*a35*a43*a51 - a15*a33* + a44*a51 + a13*a35*a44*a51 + a14*a33*a45*a51 - a13* + a34*a45*a51 - a15*a34*a41*a53 + a14*a35*a41*a53 + + a15*a31*a44*a53 - a11*a35*a44*a53 - a14*a31*a45* + a53 + a11*a34*a45*a53 + a15*a33*a41*a54 - a13*a35* + a41*a54 - a15*a31*a43*a54 + a11*a35*a43*a54 + a13* + a31*a45*a54 - a11*a33*a45*a54 - a14*a33*a41*a55 + + a13*a34*a41*a55 + a14*a31*a43*a55 - a11*a34*a43* + a55 - a13*a31*a44*a55 + a11*a33*a44*a55; + cofactor[7] = -a15*a24*a43*a51 + a14*a25*a43*a51 + a15*a23 * + a44*a51 - a13*a25*a44*a51 - a14*a23*a45*a51 + a13 * + a24*a45*a51 + a15*a24*a41*a53 - a14*a25*a41*a53 + - a15*a21*a44*a53 + a11*a25*a44*a53 + a14*a21*a45 + *a53 - a11*a24*a45*a53 - a15*a23*a41*a54 + a13*a25 + *a41*a54 + a15*a21*a43*a54 - a11*a25*a43*a54 - a13 + *a21*a45*a54 + a11*a23*a45*a54 + a14*a23*a41*a55 + - a13*a24*a41*a55 - a14*a21*a43*a55 + a11*a24*a43 + *a55 + a13*a21*a44*a55 - a11*a23*a44*a55; + cofactor[8] = a15*a24*a33*a51 - a14*a25*a33*a51 - a15*a23* + a34*a51 + a13*a25*a34*a51 + a14*a23*a35*a51 - a13* + a24*a35*a51 - a15*a24*a31*a53 + a14*a25*a31*a53 + + a15*a21*a34*a53 - a11*a25*a34*a53 - a14*a21*a35* + a53 + a11*a24*a35*a53 + a15*a23*a31*a54 - a13*a25* + a31*a54 - a15*a21*a33*a54 + a11*a25*a33*a54 + a13* + a21*a35*a54 - a11*a23*a35*a54 - a14*a23*a31*a55 + + a13*a24*a31*a55 + a14*a21*a33*a55 - a11*a24*a33* + a55 - a13*a21*a34*a55 + a11*a23*a34*a55; + cofactor[9] = -a15*a24*a33*a41 + a14*a25*a33*a41 + a15*a23 * + a34*a41 - a13*a25*a34*a41 - a14*a23*a35*a41 + a13 * + a24*a35*a41 + a15*a24*a31*a43 - a14*a25*a31*a43 + - a15*a21*a34*a43 + a11*a25*a34*a43 + a14*a21*a35 + *a43 - a11*a24*a35*a43 - a15*a23*a31*a44 + a13*a25 + *a31*a44 + a15*a21*a33*a44 - a11*a25*a33*a44 - a13 + *a21*a35*a44 + a11*a23*a35*a44 + a14*a23*a31*a45 + - a13*a24*a31*a45 - a14*a21*a33*a45 + a11*a24*a33 + *a45 + a13*a21*a34*a45 - a11*a23*a34*a45; + cofactor[10] = a25*a34*a42*a51 - a24*a35*a42*a51 - a25*a32 * + a44*a51 + a22*a35*a44*a51 + a24*a32*a45*a51 - a22 * + a34*a45*a51 - a25*a34*a41*a52 + a24*a35*a41*a52 + + a25*a31*a44*a52 - a21*a35*a44*a52 - a24*a31*a45 + *a52 + a21*a34*a45*a52 + a25*a32*a41*a54 - a22*a35 + *a41*a54 - a25*a31*a42*a54 + a21*a35*a42*a54 + a22 + *a31*a45*a54 - a21*a32*a45*a54 - a24*a32*a41*a55 + + a22*a34*a41*a55 + a24*a31*a42*a55 - a21*a34*a42 + *a55 - a22*a31*a44*a55 + a21*a32*a44*a55; + cofactor[11] = -a15*a34*a42*a51 + a14*a35*a42*a51 + a15*a32 + *a44*a51 - a12*a35*a44*a51 - a14*a32*a45*a51 + a12 + *a34*a45*a51 + a15*a34*a41*a52 - a14*a35*a41*a52 + - a15*a31*a44*a52 + a11*a35*a44*a52 + a14*a31*a45 + *a52 - a11*a34*a45*a52 - a15*a32*a41*a54 + a12*a35 + *a41*a54 + a15*a31*a42*a54 - a11*a35*a42*a54 - a12 + *a31*a45*a54 + a11*a32*a45*a54 + a14*a32*a41*a55 + - a12*a34*a41*a55 - a14*a31*a42*a55 + a11*a34*a42 + *a55 + a12*a31*a44*a55 - a11*a32*a44*a55; + cofactor[12] = a15*a24*a42*a51 - a14*a25*a42*a51 - a15*a22 * + a44*a51 + a12*a25*a44*a51 + a14*a22*a45*a51 - a12 * + a24*a45*a51 - a15*a24*a41*a52 + a14*a25*a41*a52 + + a15*a21*a44*a52 - a11*a25*a44*a52 - a14*a21*a45 + *a52 + a11*a24*a45*a52 + a15*a22*a41*a54 - a12*a25 + *a41*a54 - a15*a21*a42*a54 + a11*a25*a42*a54 + a12 + *a21*a45*a54 - a11*a22*a45*a54 - a14*a22*a41*a55 + + a12*a24*a41*a55 + a14*a21*a42*a55 - a11*a24*a42 + *a55 - a12*a21*a44*a55 + a11*a22*a44*a55; + cofactor[13] = -a15*a24*a32*a51 + a14*a25*a32*a51 + a15*a22 + *a34*a51 - a12*a25*a34*a51 - a14*a22*a35*a51 + a12 + *a24*a35*a51 + a15*a24*a31*a52 - a14*a25*a31*a52 + - a15*a21*a34*a52 + a11*a25*a34*a52 + a14*a21*a35 + *a52 - a11*a24*a35*a52 - a15*a22*a31*a54 + a12*a25 + *a31*a54 + a15*a21*a32*a54 - a11*a25*a32*a54 - a12 + *a21*a35*a54 + a11*a22*a35*a54 + a14*a22*a31*a55 + - a12*a24*a31*a55 - a14*a21*a32*a55 + a11*a24*a32 + *a55 + a12*a21*a34*a55 - a11*a22*a34*a55; + cofactor[14] = a15*a24*a32*a41 - a14*a25*a32*a41 - a15*a22 * + a34*a41 + a12*a25*a34*a41 + a14*a22*a35*a41 - a12 * + a24*a35*a41 - a15*a24*a31*a42 + a14*a25*a31*a42 + + a15*a21*a34*a42 - a11*a25*a34*a42 - a14*a21*a35 + *a42 + a11*a24*a35*a42 + a15*a22*a31*a44 - a12*a25 + *a31*a44 - a15*a21*a32*a44 + a11*a25*a32*a44 + a12 + *a21*a35*a44 - a11*a22*a35*a44 - a14*a22*a31*a45 + + a12*a24*a31*a45 + a14*a21*a32*a45 - a11*a24*a32 + *a45 - a12*a21*a34*a45 + a11*a22*a34*a45; + cofactor[15] = -a25*a33*a42*a51 + a23*a35*a42*a51 + a25*a32 + *a43*a51 - a22*a35*a43*a51 - a23*a32*a45*a51 + a22 + *a33*a45*a51 + a25*a33*a41*a52 - a23*a35*a41*a52 + - a25*a31*a43*a52 + a21*a35*a43*a52 + a23*a31*a45 + *a52 - a21*a33*a45*a52 - a25*a32*a41*a53 + a22*a35 + *a41*a53 + a25*a31*a42*a53 - a21*a35*a42*a53 - a22 + *a31*a45*a53 + a21*a32*a45*a53 + a23*a32*a41*a55 + - a22*a33*a41*a55 - a23*a31*a42*a55 + a21*a33*a42 + *a55 + a22*a31*a43*a55 - a21*a32*a43*a55; + cofactor[16] = a15*a33*a42*a51 - a13*a35*a42*a51 - a15*a32 * + a43*a51 + a12*a35*a43*a51 + a13*a32*a45*a51 - a12 * + a33*a45*a51 - a15*a33*a41*a52 + a13*a35*a41*a52 + + a15*a31*a43*a52 - a11*a35*a43*a52 - a13*a31*a45 + *a52 + a11*a33*a45*a52 + a15*a32*a41*a53 - a12*a35 + *a41*a53 - a15*a31*a42*a53 + a11*a35*a42*a53 + a12 + *a31*a45*a53 - a11*a32*a45*a53 - a13*a32*a41*a55 + + a12*a33*a41*a55 + a13*a31*a42*a55 - a11*a33*a42 + *a55 - a12*a31*a43*a55 + a11*a32*a43*a55; + cofactor[17] = -a15*a23*a42*a51 + a13*a25*a42*a51 + a15*a22 + *a43*a51 - a12*a25*a43*a51 - a13*a22*a45*a51 + a12 + *a23*a45*a51 + a15*a23*a41*a52 - a13*a25*a41*a52 + - a15*a21*a43*a52 + a11*a25*a43*a52 + a13*a21*a45 + *a52 - a11*a23*a45*a52 - a15*a22*a41*a53 + a12*a25 + *a41*a53 + a15*a21*a42*a53 - a11*a25*a42*a53 - a12 + *a21*a45*a53 + a11*a22*a45*a53 + a13*a22*a41*a55 + - a12*a23*a41*a55 - a13*a21*a42*a55 + a11*a23*a42 + *a55 + a12*a21*a43*a55 - a11*a22*a43*a55; + cofactor[18] = a15*a23*a32*a51 - a13*a25*a32*a51 - a15*a22 * + a33*a51 + a12*a25*a33*a51 + a13*a22*a35*a51 - a12 * + a23*a35*a51 - a15*a23*a31*a52 + a13*a25*a31*a52 + + a15*a21*a33*a52 - a11*a25*a33*a52 - a13*a21*a35 + *a52 + a11*a23*a35*a52 + a15*a22*a31*a53 - a12*a25 + *a31*a53 - a15*a21*a32*a53 + a11*a25*a32*a53 + a12 + *a21*a35*a53 - a11*a22*a35*a53 - a13*a22*a31*a55 + + a12*a23*a31*a55 + a13*a21*a32*a55 - a11*a23*a32 + *a55 - a12*a21*a33*a55 + a11*a22*a33*a55; + cofactor[19] = -a15*a23*a32*a41 + a13*a25*a32*a41 + a15*a22 + *a33*a41 - a12*a25*a33*a41 - a13*a22*a35*a41 + a12 + *a23*a35*a41 + a15*a23*a31*a42 - a13*a25*a31*a42 + - a15*a21*a33*a42 + a11*a25*a33*a42 + a13*a21*a35 + *a42 - a11*a23*a35*a42 - a15*a22*a31*a43 + a12*a25 + *a31*a43 + a15*a21*a32*a43 - a11*a25*a32*a43 - a12 + *a21*a35*a43 + a11*a22*a35*a43 + a13*a22*a31*a45 + - a12*a23*a31*a45 - a13*a21*a32*a45 + a11*a23*a32 + *a45 + a12*a21*a33*a45 - a11*a22*a33*a45; + cofactor[20] = a24*a33*a42*a51 - a23*a34*a42*a51 - a24*a32 * + a43*a51 + a22*a34*a43*a51 + a23*a32*a44*a51 - a22 * + a33*a44*a51 - a24*a33*a41*a52 + a23*a34*a41*a52 + + a24*a31*a43*a52 - a21*a34*a43*a52 - a23*a31*a44 + *a52 + a21*a33*a44*a52 + a24*a32*a41*a53 - a22*a34 + *a41*a53 - a24*a31*a42*a53 + a21*a34*a42*a53 + a22 + *a31*a44*a53 - a21*a32*a44*a53 - a23*a32*a41*a54 + + a22*a33*a41*a54 + a23*a31*a42*a54 - a21*a33*a42 + *a54 - a22*a31*a43*a54 + a21*a32*a43*a54; + cofactor[21] = -a14*a33*a42*a51 + a13*a34*a42*a51 + a14*a32 + *a43*a51 - a12*a34*a43*a51 - a13*a32*a44*a51 + a12 + *a33*a44*a51 + a14*a33*a41*a52 - a13*a34*a41*a52 + - a14*a31*a43*a52 + a11*a34*a43*a52 + a13*a31*a44 + *a52 - a11*a33*a44*a52 - a14*a32*a41*a53 + a12*a34 + *a41*a53 + a14*a31*a42*a53 - a11*a34*a42*a53 - a12 + *a31*a44*a53 + a11*a32*a44*a53 + a13*a32*a41*a54 + - a12*a33*a41*a54 - a13*a31*a42*a54 + a11*a33*a42 + *a54 + a12*a31*a43*a54 - a11*a32*a43*a54; + cofactor[22] = a14*a23*a42*a51 - a13*a24*a42*a51 - a14*a22 * + a43*a51 + a12*a24*a43*a51 + a13*a22*a44*a51 - a12 * + a23*a44*a51 - a14*a23*a41*a52 + a13*a24*a41*a52 + + a14*a21*a43*a52 - a11*a24*a43*a52 - a13*a21*a44 + *a52 + a11*a23*a44*a52 + a14*a22*a41*a53 - a12*a24 + *a41*a53 - a14*a21*a42*a53 + a11*a24*a42*a53 + a12 + *a21*a44*a53 - a11*a22*a44*a53 - a13*a22*a41*a54 + + a12*a23*a41*a54 + a13*a21*a42*a54 - a11*a23*a42 + *a54 - a12*a21*a43*a54 + a11*a22*a43*a54; + cofactor[23] = -a14*a23*a32*a51 + a13*a24*a32*a51 + a14*a22 + *a33*a51 - a12*a24*a33*a51 - a13*a22*a34*a51 + a12 + *a23*a34*a51 + a14*a23*a31*a52 - a13*a24*a31*a52 + - a14*a21*a33*a52 + a11*a24*a33*a52 + a13*a21*a34 + *a52 - a11*a23*a34*a52 - a14*a22*a31*a53 + a12*a24 + *a31*a53 + a14*a21*a32*a53 - a11*a24*a32*a53 - a12 + *a21*a34*a53 + a11*a22*a34*a53 + a13*a22*a31*a54 + - a12*a23*a31*a54 - a13*a21*a32*a54 + a11*a23*a32 + *a54 + a12*a21*a33*a54 - a11*a22*a33*a54; + cofactor[24] = a14*a23*a32*a41 - a13*a24*a32*a41 - a14*a22 * + a33*a41 + a12*a24*a33*a41 + a13*a22*a34*a41 - a12 * + a23*a34*a41 - a14*a23*a31*a42 + a13*a24*a31*a42 + + a14*a21*a33*a42 - a11*a24*a33*a42 - a13*a21*a34 + *a42 + a11*a23*a34*a42 + a14*a22*a31*a43 - a12*a24 + *a31*a43 - a14*a21*a32*a43 + a11*a24*a32*a43 + a12 + *a21*a34*a43 - a11*a22*a34*a43 - a13*a22*a31*a44 + + a12*a23*a31*a44 + a13*a21*a32*a44 - a11*a23*a32 + *a44 - a12*a21*a33*a44 + a11*a22*a33*a44; + + for (int i__ = 1; i__ <= 5; ++i__) + for (int j = 1; j <= 5; ++j) + ainv[j + i__*5] = cofactor[i__ + j*5 - 6] / det; + + *ok_flag__ = 0; + return 0; +} + diff --git a/SRC/matrix/routines/invGL6.c b/SRC/matrix/routines/invGL6.c new file mode 100644 index 0000000000..3f800b5fe3 --- /dev/null +++ b/SRC/matrix/routines/invGL6.c @@ -0,0 +1,5456 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// adapted from https://caps.gsfc.nasa.gov/simpson/software/m66inv_f90.txt +// +// +#include + + +#define a11 a[ 0] +#define a12 a[6] +#define a13 a[12] +#define a14 a[18] +#define a15 a[24] +#define a16 a[30] +#define a21 a[ 1] +#define a22 a[7] +#define a23 a[13] +#define a24 a[19] +#define a25 a[25] +#define a26 a[31] +#define a31 a[ 2] +#define a32 a[8] +#define a33 a[14] +#define a34 a[20] +#define a35 a[26] +#define a36 a[32] +#define a41 a[3] +#define a42 a[9] +#define a43 a[15] +#define a44 a[21] +#define a45 a[27] +#define a46 a[33] +#define a51 a[4] +#define a52 a[10] +#define a53 a[16] +#define a54 a[22] +#define a55 a[28] +#define a56 a[34] +#define a61 a[5] +#define a62 a[11] +#define a63 a[17] +#define a64 a[23] +#define a65 a[29] +#define a66 a[35] + +int cmx_inv6(const double a[36], double *ainv, int*ok_flag__) +{ + double cofactor[36]; + + /* Parameter adjustments */ + + /* Function Body */ + const double eps = 1e-10; + const double + det = - ( a16*a25*a34*a43*a52 + - a15*a26*a34*a43*a52 + - a16*a24*a35*a43*a52 + + a14*a26*a35*a43*a52 + + a15*a24*a36*a43*a52 + - a14*a25*a36*a43*a52 + - a16*a25*a33*a44*a52 + + a15*a26*a33*a44*a52 + + a16*a23*a35*a44*a52 + - a13*a26*a35*a44*a52 + - a15*a23*a36*a44*a52 + + a13*a25*a36*a44*a52 + + a16*a24*a33*a45*a52 + - a14*a26*a33*a45*a52 + - a16*a23*a34*a45*a52 + + a13*a26*a34*a45*a52 + + a14*a23*a36*a45*a52 + - a13*a24*a36*a45*a52 + - a15*a24*a33*a46*a52 + + a14*a25*a33*a46*a52 + + a15*a23*a34*a46*a52 + - a13*a25*a34*a46*a52 + - a14*a23*a35*a46*a52 + + a13*a24*a35*a46*a52 + - a16*a25*a34*a42*a53 + + a15*a26*a34*a42*a53 + + a16*a24*a35*a42*a53 + - a14*a26*a35*a42*a53 + - a15*a24*a36*a42*a53 + + a14*a25*a36*a42*a53 + + a16*a25*a32*a44*a53 + - a15*a26*a32*a44*a53 + - a16*a22*a35*a44*a53 + + + a12*a26*a35*a44*a53 + + a15*a22*a36*a44*a53 + - a12*a25*a36*a44*a53 + - a16*a24*a32*a45*a53 + + a14*a26*a32*a45*a53 + + a16*a22*a34*a45*a53 + - a12*a26*a34*a45*a53 + - a14*a22*a36*a45*a53 + + a12*a24*a36*a45*a53 + + a15*a24*a32*a46*a53 + - a14*a25*a32*a46*a53 + - + a15*a22*a34*a46*a53 + + a12*a25*a34*a46*a53 + + a14*a22*a35*a46*a53 + - a12*a24*a35*a46*a53 + + a16*a25*a33*a42*a54 + - a15*a26*a33*a42*a54 + - a16*a23*a35*a42*a54 + + a13*a26*a35*a42*a54 + + a15*a23*a36*a42*a54 + - a13*a25*a36*a42*a54 + - a16*a25*a32*a43*a54 + + + a15*a26*a32*a43*a54 + + a16*a22*a35*a43*a54 + - a12*a26*a35*a43*a54 + - a15*a22*a36*a43*a54 + + a12*a25*a36*a43*a54 + + a16*a23*a32*a45*a54 + - a13*a26*a32*a45*a54 + - a16*a22*a33*a45*a54 + + a12*a26*a33*a45*a54 + + a13*a22*a36*a45*a54 + - a12*a23*a36*a45*a54 + - + a15*a23*a32*a46*a54 + + a13*a25*a32*a46*a54 + + a15*a22*a33*a46*a54 + - a12*a25*a33*a46*a54 + - a13*a22*a35*a46*a54 + + a12*a23*a35*a46*a54 + - a16*a24*a33*a42*a55 + + a14*a26*a33*a42*a55 + + a16*a23*a34*a42*a55 + - a13*a26*a34*a42*a55 + - a14*a23*a36*a42*a55 + + a13*a24*a36*a42*a55 + + a16*a24*a32*a43*a55 + - a14*a26*a32*a43*a55 + - a16*a22*a34*a43*a55 + + a12*a26*a34*a43*a55 + + a14*a22*a36*a43*a55 + - a12*a24*a36*a43*a55 + - a16*a23*a32*a44*a55 + + a13*a26*a32*a44*a55 + + a16*a22*a33*a44*a55 + - a12*a26*a33*a44*a55 + - a13*a22*a36*a44*a55 + + a12*a23*a36*a44*a55 + + a14*a23*a32*a46*a55 + - a13*a24*a32*a46*a55 + - a14*a22*a33*a46*a55 + + a12*a24*a33*a46*a55 + + a13*a22*a34*a46*a55 + - a12*a23*a34*a46*a55 + + a15*a24*a33*a42*a56 + - a14*a25*a33*a42*a56 + - a15*a23*a34*a42*a56 + + a13*a25*a34*a42*a56 + + a14*a23*a35*a42*a56 + - a13*a24*a35*a42*a56 + - a15*a24*a32*a43*a56 + + a14*a25*a32*a43*a56 + + a15*a22*a34*a43*a56 + - a12*a25*a34*a43*a56 + - a14*a22*a35*a43*a56 + + a12*a24*a35*a43*a56 + + a15*a23*a32*a44*a56 + - a13*a25*a32*a44*a56 + - a15*a22*a33*a44*a56 + + a12*a25*a33*a44*a56 + + a13*a22*a35*a44*a56 + - a12*a23*a35*a44*a56 + - a14*a23*a32*a45*a56 + + a13*a24*a32*a45*a56 + + a14*a22*a33*a45*a56 + - a12*a24*a33*a45*a56 + - a13*a22*a34*a45*a56 + + a12*a23*a34*a45*a56)*a61 + + + (a16*a25*a34*a43*a51 + - a15*a26*a34*a43*a51 + - a16*a24*a35*a43*a51 + + a14*a26*a35*a43*a51 + + a15*a24*a36*a43*a51 + - a14*a25*a36*a43*a51 + - a16*a25*a33*a44*a51 + + a15*a26*a33*a44*a51 + + a16*a23*a35*a44*a51 + - a13*a26*a35*a44*a51 + - a15*a23*a36*a44*a51 + + a13*a25*a36*a44*a51 + + a16*a24*a33*a45*a51 + - a14*a26*a33*a45*a51 + - a16*a23*a34*a45*a51 + + a13*a26*a34*a45*a51 + + a14*a23*a36*a45*a51 + - a13*a24*a36*a45*a51 + - a15*a24*a33*a46*a51 + + a14*a25*a33*a46*a51 + + a15*a23*a34*a46*a51 + - a13*a25*a34*a46*a51 + - a14*a23*a35*a46*a51 + + a13*a24*a35*a46*a51 + - a16*a25*a34*a41*a53 + + a15*a26*a34*a41*a53 + + a16*a24*a35*a41*a53 + - a14*a26*a35*a41*a53 + - a15*a24*a36*a41*a53 + + a14*a25*a36*a41*a53 + + a16*a25*a31*a44*a53 + - a15*a26*a31*a44*a53 + - a16*a21*a35*a44*a53 + + a11*a26*a35*a44*a53 + + a15*a21*a36*a44*a53 + - a11*a25*a36*a44*a53 + - a16*a24*a31*a45*a53 + + a14*a26*a31*a45*a53 + + a16*a21*a34*a45*a53 + - a11*a26*a34*a45*a53 + - a14*a21*a36*a45*a53 + + a11*a24*a36*a45*a53 + + a15*a24*a31*a46*a53 + - a14*a25*a31*a46*a53 + - a15*a21*a34*a46*a53 + + a11*a25*a34*a46*a53 + + a14*a21*a35*a46*a53 + - a11*a24*a35*a46*a53 + + a16*a25*a33*a41*a54 + - a15*a26*a33*a41*a54 + - a16*a23*a35*a41*a54 + + a13*a26*a35*a41*a54 + + a15*a23*a36*a41*a54 + - a13*a25*a36*a41*a54 + - a16*a25*a31*a43*a54 + + a15*a26*a31*a43*a54 + + a16*a21*a35*a43*a54 + - a11*a26*a35*a43*a54 + - a15*a21*a36*a43*a54 + + a11*a25*a36*a43*a54 + + a16*a23*a31*a45*a54 + - a13*a26*a31*a45*a54 + - a16*a21*a33*a45*a54 + + a11*a26*a33*a45*a54 + + a13*a21*a36*a45*a54 + - a11*a23*a36*a45*a54 + - a15*a23*a31*a46*a54 + + a13*a25*a31*a46*a54 + + a15*a21*a33*a46*a54 + - a11*a25*a33*a46*a54 + - a13*a21*a35*a46*a54 + + a11*a23*a35*a46*a54 + - a16*a24*a33*a41*a55 + + a14*a26*a33*a41*a55 + + a16*a23*a34*a41*a55 + - a13*a26*a34*a41*a55 + - a14*a23*a36*a41*a55 + + a13*a24*a36*a41*a55 + + a16*a24*a31*a43*a55 + - a14*a26*a31*a43*a55 + - a16*a21*a34*a43*a55 + + a11*a26*a34*a43*a55 + + a14*a21*a36*a43*a55 + - a11*a24*a36*a43*a55 + - a16*a23*a31*a44*a55 + + a13*a26*a31*a44*a55 + + a16*a21*a33*a44*a55 + - a11*a26*a33*a44*a55 + - a13*a21*a36*a44*a55 + + a11*a23*a36*a44*a55 + + a14*a23*a31*a46*a55 + - a13*a24*a31*a46*a55 + - a14*a21*a33*a46*a55 + + a11*a24*a33*a46*a55 + + a13*a21*a34*a46*a55 + - a11*a23*a34*a46*a55 + + a15*a24*a33*a41*a56 + - a14*a25*a33*a41*a56 + - a15*a23*a34*a41*a56 + + a13*a25*a34*a41*a56 + + a14*a23*a35*a41*a56 + - a13*a24*a35*a41*a56 + - a15*a24*a31*a43*a56 + + a14*a25*a31*a43*a56 + + a15*a21*a34*a43*a56 + - a11*a25*a34*a43*a56 + - a14*a21*a35*a43*a56 + + a11*a24*a35*a43*a56 + + a15*a23*a31*a44*a56 + - a13*a25*a31*a44*a56 + - a15*a21*a33*a44*a56 + + a11*a25*a33*a44*a56 + + a13*a21*a35*a44*a56 + - a11*a23*a35*a44*a56 + - a14*a23*a31*a45*a56 + + a13*a24*a31*a45*a56 + + a14*a21*a33*a45*a56 + - a11*a24*a33*a45*a56 + - a13*a21*a34*a45*a56 + + a11*a23*a34*a45*a56)*a62 + - (a16*a25*a34*a42*a51 + - a15*a26*a34*a42*a51 + - a16*a24*a35*a42*a51 + + a14*a26*a35*a42*a51 + + a15*a24*a36*a42*a51 + - a14*a25*a36*a42*a51 + - a16*a25*a32*a44*a51 + + a15*a26*a32*a44*a51 + + + a16*a22*a35*a44*a51 + - a12*a26*a35*a44*a51 + - a15*a22*a36*a44*a51 + + a12*a25*a36*a44*a51 + + a16*a24*a32*a45*a51 + - a14*a26*a32*a45*a51 + - a16*a22*a34*a45*a51 + + a12*a26*a34*a45*a51 + + a14*a22*a36*a45*a51 + - a12*a24*a36*a45*a51 + - a15*a24*a32*a46*a51 + + + a14*a25*a32*a46*a51 + + a15*a22*a34*a46*a51 + - a12*a25*a34*a46*a51 + - a14*a22*a35*a46*a51 + + a12*a24*a35*a46*a51 + - a16*a25*a34*a41*a52 + + a15*a26*a34*a41*a52 + + a16*a24*a35*a41*a52 + - a14*a26*a35*a41*a52 + - a15*a24*a36*a41*a52 + + a14*a25*a36*a41*a52 + + + a16*a25*a31*a44*a52 + - a15*a26*a31*a44*a52 + - a16*a21*a35*a44*a52 + + a11*a26*a35*a44*a52 + + a15*a21*a36*a44*a52 + - a11*a25*a36*a44*a52 + - a16*a24*a31*a45*a52 + + a14*a26*a31*a45*a52 + + a16*a21*a34*a45*a52 + - a11*a26*a34*a45*a52 + - a14*a21*a36*a45*a52 + + + a11*a24*a36*a45*a52 + + a15*a24*a31*a46*a52 + - a14*a25*a31*a46*a52 + - a15*a21*a34*a46*a52 + + a11*a25*a34*a46*a52 + + a14*a21*a35*a46*a52 + - a11*a24*a35*a46*a52 + + a16*a25*a32*a41*a54 + - a15*a26*a32*a41*a54 + - a16*a22*a35*a41*a54 + + a12*a26*a35*a41*a54 + + + a15*a22*a36*a41*a54 + - a12*a25*a36*a41*a54 + - a16*a25*a31*a42*a54 + + a15*a26*a31*a42*a54 + + a16*a21*a35*a42*a54 + - a11*a26*a35*a42*a54 + - a15*a21*a36*a42*a54 + + a11*a25*a36*a42*a54 + + a16*a22*a31*a45*a54 + - a12*a26*a31*a45*a54 + - a16*a21*a32*a45*a54 + + + a11*a26*a32*a45*a54 + + a12*a21*a36*a45*a54 + - a11*a22*a36*a45*a54 + - a15*a22*a31*a46*a54 + + a12*a25*a31*a46*a54 + + a15*a21*a32*a46*a54 + - a11*a25*a32*a46*a54 + - a12*a21*a35*a46*a54 + + a11*a22*a35*a46*a54 + - a16*a24*a32*a41*a55 + + a14*a26*a32*a41*a55 + + + a16*a22*a34*a41*a55 + - a12*a26*a34*a41*a55 + - a14*a22*a36*a41*a55 + + a12*a24*a36*a41*a55 + + a16*a24*a31*a42*a55 + - a14*a26*a31*a42*a55 + - a16*a21*a34*a42*a55 + + a11*a26*a34*a42*a55 + + a14*a21*a36*a42*a55 + - a11*a24*a36*a42*a55 + - a16*a22*a31*a44*a55 + + + a12*a26*a31*a44*a55 + + a16*a21*a32*a44*a55 + - a11*a26*a32*a44*a55 + - a12*a21*a36*a44*a55 + + a11*a22*a36*a44*a55 + + a14*a22*a31*a46*a55 + - a12*a24*a31*a46*a55 + - a14*a21*a32*a46*a55 + + a11*a24*a32*a46*a55 + + a12*a21*a34*a46*a55 + - a11*a22*a34*a46*a55 + + + a15*a24*a32*a41*a56 + - a14*a25*a32*a41*a56 + - a15*a22*a34*a41*a56 + + a12*a25*a34*a41*a56 + + a14*a22*a35*a41*a56 + - a12*a24*a35*a41*a56 + - a15*a24*a31*a42*a56 + + a14*a25*a31*a42*a56 + + a15*a21*a34*a42*a56 + - a11*a25*a34*a42*a56 + - a14*a21*a35*a42*a56 + + + a11*a24*a35*a42*a56 + + a15*a22*a31*a44*a56 + - a12*a25*a31*a44*a56 + - a15*a21*a32*a44*a56 + + a11*a25*a32*a44*a56 + + a12*a21*a35*a44*a56 + - a11*a22*a35*a44*a56 + - a14*a22*a31*a45*a56 + + a12*a24*a31*a45*a56 + + a14*a21*a32*a45*a56 + - a11*a24*a32*a45*a56 + - + a12*a21*a34*a45*a56 + + a11*a22*a34*a45*a56)*a63 + + (a16*a25*a33*a42*a51 + - a15*a26*a33*a42*a51 + - + a16*a23*a35*a42*a51 + + a13*a26*a35*a42*a51 + + a15*a23*a36*a42*a51 + - a13*a25*a36*a42*a51 + - a16*a25*a32*a43*a51 + + a15*a26*a32*a43*a51 + + a16*a22*a35*a43*a51 + - a12*a26*a35*a43*a51 + - a15*a22*a36*a43*a51 + + a12*a25*a36*a43*a51 + + a16*a23*a32*a45*a51 + - + a13*a26*a32*a45*a51 + - a16*a22*a33*a45*a51 + + a12*a26*a33*a45*a51 + + a13*a22*a36*a45*a51 + - a12*a23*a36*a45*a51 + - a15*a23*a32*a46*a51 + + a13*a25*a32*a46*a51 + + a15*a22*a33*a46*a51 + - a12*a25*a33*a46*a51 + - a13*a22*a35*a46*a51 + + a12*a23*a35*a46*a51 + - + a16*a25*a33*a41*a52 + + a15*a26*a33*a41*a52 + + a16*a23*a35*a41*a52 + - a13*a26*a35*a41*a52 + - a15*a23*a36*a41*a52 + + a13*a25*a36*a41*a52 + + a16*a25*a31*a43*a52 + - a15*a26*a31*a43*a52 + - a16*a21*a35*a43*a52 + + a11*a26*a35*a43*a52 + + a15*a21*a36*a43*a52 + - a11*a25*a36*a43*a52 + - a16*a23*a31*a45*a52 + + a13*a26*a31*a45*a52 + + a16*a21*a33*a45*a52 + - a11*a26*a33*a45*a52 + - a13*a21*a36*a45*a52 + + a11*a23*a36*a45*a52 + + a15*a23*a31*a46*a52 + - a13*a25*a31*a46*a52 + - a15*a21*a33*a46*a52 + + a11*a25*a33*a46*a52 + + a13*a21*a35*a46*a52 + - a11*a23*a35*a46*a52 + + a16*a25*a32*a41*a53 + - a15*a26*a32*a41*a53 + - a16*a22*a35*a41*a53 + + a12*a26*a35*a41*a53 + + a15*a22*a36*a41*a53 + - a12*a25*a36*a41*a53 + - a16*a25*a31*a42*a53 + + a15*a26*a31*a42*a53 + + a16*a21*a35*a42*a53 + - a11*a26*a35*a42*a53 + - a15*a21*a36*a42*a53 + + a11*a25*a36*a42*a53 + + a16*a22*a31*a45*a53 + - a12*a26*a31*a45*a53 + - a16*a21*a32*a45*a53 + + a11*a26*a32*a45*a53 + + a12*a21*a36*a45*a53 + - a11*a22*a36*a45*a53 + - a15*a22*a31*a46*a53 + + a12*a25*a31*a46*a53 + + a15*a21*a32*a46*a53 + - a11*a25*a32*a46*a53 + - a12*a21*a35*a46*a53 + + a11*a22*a35*a46*a53 + - a16*a23*a32*a41*a55 + + a13*a26*a32*a41*a55 + + a16*a22*a33*a41*a55 + - a12*a26*a33*a41*a55 + - a13*a22*a36*a41*a55 + + a12*a23*a36*a41*a55 + + a16*a23*a31*a42*a55 + - a13*a26*a31*a42*a55 + - a16*a21*a33*a42*a55 + + a11*a26*a33*a42*a55 + + a13*a21*a36*a42*a55 + - a11*a23*a36*a42*a55 + - a16*a22*a31*a43*a55 + + a12*a26*a31*a43*a55 + + a16*a21*a32*a43*a55 + - a11*a26*a32*a43*a55 + - a12*a21*a36*a43*a55 + + a11*a22*a36*a43*a55 + + a13*a22*a31*a46*a55 + - a12*a23*a31*a46*a55 + - a13*a21*a32*a46*a55 + + a11*a23*a32*a46*a55 + + a12*a21*a33*a46*a55 + - a11*a22*a33*a46*a55 + + a15*a23*a32*a41*a56 + - a13*a25*a32*a41*a56 + - a15*a22*a33*a41*a56 + + a12*a25*a33*a41*a56 + + a13*a22*a35*a41*a56 + - a12*a23*a35*a41*a56 + - a15*a23*a31*a42*a56 + + a13*a25*a31*a42*a56 + + a15*a21*a33*a42*a56 + - a11*a25*a33*a42*a56 + - a13*a21*a35*a42*a56 + + a11*a23*a35*a42*a56 + + a15*a22*a31*a43*a56 + - a12*a25*a31*a43*a56 + - a15*a21*a32*a43*a56 + + a11*a25*a32*a43*a56 + + a12*a21*a35*a43*a56 + - a11*a22*a35*a43*a56 + - a13*a22*a31*a45*a56 + + a12*a23*a31*a45*a56 + + a13*a21*a32*a45*a56 + - a11*a23*a32*a45*a56 + - a12*a21*a33*a45*a56 + + a11*a22*a33*a45*a56)*a64 + + - (a16*a24*a33*a42*a51 + - a14*a26*a33*a42*a51 + - a16*a23*a34*a42*a51 + + a13*a26*a34*a42*a51 + + a14*a23*a36*a42*a51 + - a13*a24*a36*a42*a51 + - a16*a24*a32*a43*a51 + + a14*a26*a32*a43*a51 + + a16*a22*a34*a43*a51 + - a12*a26*a34*a43*a51 + - a14*a22*a36*a43*a51 + + a12*a24*a36*a43*a51 + + a16*a23*a32*a44*a51 + - a13*a26*a32*a44*a51 + - a16*a22*a33*a44*a51 + + a12*a26*a33*a44*a51 + + a13*a22*a36*a44*a51 + - a12*a23*a36*a44*a51 + - a14*a23*a32*a46*a51 + + a13*a24*a32*a46*a51 + + a14*a22*a33*a46*a51 + - a12*a24*a33*a46*a51 + - a13*a22*a34*a46*a51 + + a12*a23*a34*a46*a51 + - a16*a24*a33*a41*a52 + + a14*a26*a33*a41*a52 + + a16*a23*a34*a41*a52 + - a13*a26*a34*a41*a52 + - a14*a23*a36*a41*a52 + + a13*a24*a36*a41*a52 + + a16*a24*a31*a43*a52 + - a14*a26*a31*a43*a52 + - a16*a21*a34*a43*a52 + + a11*a26*a34*a43*a52 + + a14*a21*a36*a43*a52 + - a11*a24*a36*a43*a52 + - a16*a23*a31*a44*a52 + + a13*a26*a31*a44*a52 + + a16*a21*a33*a44*a52 + - a11*a26*a33*a44*a52 + - a13*a21*a36*a44*a52 + + a11*a23*a36*a44*a52 + + a14*a23*a31*a46*a52 + - a13*a24*a31*a46*a52 + - a14*a21*a33*a46*a52 + + a11*a24*a33*a46*a52 + + a13*a21*a34*a46*a52 + - a11*a23*a34*a46*a52 + + a16*a24*a32*a41*a53 + - a14*a26*a32*a41*a53 + - a16*a22*a34*a41*a53 + + a12*a26*a34*a41*a53 + + a14*a22*a36*a41*a53 + - a12*a24*a36*a41*a53 + - a16*a24*a31*a42*a53 + + a14*a26*a31*a42*a53 + + a16*a21*a34*a42*a53 + - a11*a26*a34*a42*a53 + - a14*a21*a36*a42*a53 + + a11*a24*a36*a42*a53 + + a16*a22*a31*a44*a53 + - a12*a26*a31*a44*a53 + - a16*a21*a32*a44*a53 + + a11*a26*a32*a44*a53 + + a12*a21*a36*a44*a53 + - a11*a22*a36*a44*a53 + - a14*a22*a31*a46*a53 + + a12*a24*a31*a46*a53 + + a14*a21*a32*a46*a53 + - a11*a24*a32*a46*a53 + - a12*a21*a34*a46*a53 + + a11*a22*a34*a46*a53 + - a16*a23*a32*a41*a54 + + a13*a26*a32*a41*a54 + + a16*a22*a33*a41*a54 + - a12*a26*a33*a41*a54 + - a13*a22*a36*a41*a54 + + a12*a23*a36*a41*a54 + + a16*a23*a31*a42*a54 + - a13*a26*a31*a42*a54 + - a16*a21*a33*a42*a54 + + a11*a26*a33*a42*a54 + + a13*a21*a36*a42*a54 + - a11*a23*a36*a42*a54 + - a16*a22*a31*a43*a54 + + a12*a26*a31*a43*a54 + + a16*a21*a32*a43*a54 + - a11*a26*a32*a43*a54 + - a12*a21*a36*a43*a54 + + a11*a22*a36*a43*a54 + + a13*a22*a31*a46*a54 + - a12*a23*a31*a46*a54 + - a13*a21*a32*a46*a54 + + a11*a23*a32*a46*a54 + + a12*a21*a33*a46*a54 + - a11*a22*a33*a46*a54 + + a14*a23*a32*a41*a56 + - a13*a24*a32*a41*a56 + - a14*a22*a33*a41*a56 + + a12*a24*a33*a41*a56 + + a13*a22*a34*a41*a56 + - a12*a23*a34*a41*a56 + - a14*a23*a31*a42*a56 + + a13*a24*a31*a42*a56 + + a14*a21*a33*a42*a56 + - a11*a24*a33*a42*a56 + - a13*a21*a34*a42*a56 + + a11*a23*a34*a42*a56 + + a14*a22*a31*a43*a56 + - a12*a24*a31*a43*a56 + - a14*a21*a32*a43*a56 + + a11*a24*a32*a43*a56 + + a12*a21*a34*a43*a56 + - a11*a22*a34*a43*a56 + - a13*a22*a31*a44*a56 + + a12*a23*a31*a44*a56 + + a13*a21*a32*a44*a56 + - a11*a23*a32*a44*a56 + - a12*a21*a33*a44*a56 + + a11*a22*a33*a44*a56)*a65 + + (a15*a24*a33*a42*a51 + - a14*a25*a33*a42*a51 + - a15*a23*a34*a42*a51 + + a13*a25*a34*a42*a51 + + a14*a23*a35*a42*a51 + - a13*a24*a35*a42*a51 + - a15*a24*a32*a43*a51 + + a14*a25*a32*a43*a51 + + a15*a22*a34*a43*a51 + - a12*a25*a34*a43*a51 + - a14*a22*a35*a43*a51 + + a12*a24*a35*a43*a51 + + a15*a23*a32*a44*a51 + - a13*a25*a32*a44*a51 + - a15*a22*a33*a44*a51 + + a12*a25*a33*a44*a51 + + a13*a22*a35*a44*a51 + - a12*a23*a35*a44*a51 + - a14*a23*a32*a45*a51 + + a13*a24*a32*a45*a51 + + a14*a22*a33*a45*a51 + - + a12*a24*a33*a45*a51 + - a13*a22*a34*a45*a51 + + a12*a23*a34*a45*a51 + - a15*a24*a33*a41*a52 + + a14*a25*a33*a41*a52 + + a15*a23*a34*a41*a52 + - a13*a25*a34*a41*a52 + - a14*a23*a35*a41*a52 + + a13*a24*a35*a41*a52 + + a15*a24*a31*a43*a52 + - a14*a25*a31*a43*a52 + - + a15*a21*a34*a43*a52 + + a11*a25*a34*a43*a52 + + a14*a21*a35*a43*a52 + - a11*a24*a35*a43*a52 + - a15*a23*a31*a44*a52 + + a13*a25*a31*a44*a52 + + a15*a21*a33*a44*a52 + - a11*a25*a33*a44*a52 + - a13*a21*a35*a44*a52 + + a11*a23*a35*a44*a52 + + a14*a23*a31*a45*a52 + - + a13*a24*a31*a45*a52 + - a14*a21*a33*a45*a52 + + a11*a24*a33*a45*a52 + + a13*a21*a34*a45*a52 + - a11*a23*a34*a45*a52 + + a15*a24*a32*a41*a53 + - a14*a25*a32*a41*a53 + - a15*a22*a34*a41*a53 + + a12*a25*a34*a41*a53 + + a14*a22*a35*a41*a53 + - a12*a24*a35*a41*a53 + - + a15*a24*a31*a42*a53 + + a14*a25*a31*a42*a53 + + a15*a21*a34*a42*a53 + - a11*a25*a34*a42*a53 + - a14*a21*a35*a42*a53 + + a11*a24*a35*a42*a53 + + a15*a22*a31*a44*a53 + - a12*a25*a31*a44*a53 + - a15*a21*a32*a44*a53 + + a11*a25*a32*a44*a53 + + a12*a21*a35*a44*a53 + - + a11*a22*a35*a44*a53 + - a14*a22*a31*a45*a53 + + a12*a24*a31*a45*a53 + + a14*a21*a32*a45*a53 + - a11*a24*a32*a45*a53 + - a12*a21*a34*a45*a53 + + a11*a22*a34*a45*a53 + - a15*a23*a32*a41*a54 + + a13*a25*a32*a41*a54 + + a15*a22*a33*a41*a54 + - a12*a25*a33*a41*a54 + - + a13*a22*a35*a41*a54 + + a12*a23*a35*a41*a54 + + a15*a23*a31*a42*a54 + - a13*a25*a31*a42*a54 + - a15*a21*a33*a42*a54 + + a11*a25*a33*a42*a54 + + a13*a21*a35*a42*a54 + - a11*a23*a35*a42*a54 + - a15*a22*a31*a43*a54 + + a12*a25*a31*a43*a54 + + a15*a21*a32*a43*a54 + - + a11*a25*a32*a43*a54 + - a12*a21*a35*a43*a54 + + a11*a22*a35*a43*a54 + + a13*a22*a31*a45*a54 + - a12*a23*a31*a45*a54 + - a13*a21*a32*a45*a54 + + a11*a23*a32*a45*a54 + + a12*a21*a33*a45*a54 + - a11*a22*a33*a45*a54 + + a14*a23*a32*a41*a55 + - a13*a24*a32*a41*a55 + - + a14*a22*a33*a41*a55 + + a12*a24*a33*a41*a55 + + a13*a22*a34*a41*a55 + - a12*a23*a34*a41*a55 + - a14*a23*a31*a42*a55 + + a13*a24*a31*a42*a55 + + a14*a21*a33*a42*a55 + - a11*a24*a33*a42*a55 + - a13*a21*a34*a42*a55 + + a11*a23*a34*a42*a55 + + a14*a22*a31*a43*a55 + - a12*a24*a31*a43*a55 + - a14*a21*a32*a43*a55 + + a11*a24*a32*a43*a55 + + a12*a21*a34*a43*a55 + - a11*a22*a34*a43*a55 + - a13*a22*a31*a44*a55 + + a12*a23*a31*a44*a55 + + a13*a21*a32*a44*a55 + - a11*a23*a32*a44*a55 + - a12*a21*a33*a44*a55 + + a11*a22*a33*a44*a55)*a66; + + if (fabs(det) <= eps) { + // printf("inv6: det = %lf\n", det); + *ok_flag__ = -1; + // return -1; + } + cofactor[0] = a26*a35*a44*a53*a62 + - a25*a36*a44*a53*a62 + - + a26*a34*a45*a53*a62 + + a24*a36*a45*a53*a62 + + a25* + a34*a46*a53*a62 + - a24*a35*a46*a53*a62 + - a26*a35* + a43*a54*a62 + + a25*a36*a43*a54*a62 + + a26*a33*a45* + a54*a62 + - a23*a36*a45*a54*a62 + - a25*a33*a46*a54* + a62 + + a23*a35*a46*a54*a62 + + a26*a34*a43*a55*a62 + - + a24*a36*a43*a55*a62 + - a26*a33*a44*a55*a62 + + a23* + a36*a44*a55*a62 + + a24*a33*a46*a55*a62 + - a23*a34* + a46*a55*a62 + - a25*a34*a43*a56*a62 + + a24*a35*a43* + a56*a62 + + a25*a33*a44*a56*a62 + - a23*a35*a44*a56* + a62 + - a24*a33*a45*a56*a62 + + a23*a34*a45*a56*a62 + - + a26*a35*a44*a52*a63 + + a25*a36*a44*a52*a63 + + a26* + a34*a45*a52*a63 + - a24*a36*a45*a52*a63 + - a25*a34* + a46*a52*a63 + + a24*a35*a46*a52*a63 + + a26*a35*a42* + a54*a63 + - a25*a36*a42*a54*a63 + - a26*a32*a45*a54* + a63 + + a22*a36*a45*a54*a63 + + a25*a32*a46*a54*a63 + - + a22*a35*a46*a54*a63 + - a26*a34*a42*a55*a63 + + a24* + a36*a42*a55*a63 + + a26*a32*a44*a55*a63 + - a22*a36* + a44*a55*a63 + - a24*a32*a46*a55*a63 + + a22*a34*a46* + a55*a63 + + a25*a34*a42*a56*a63 + - a24*a35*a42*a56* + a63 + - a25*a32*a44*a56*a63 + + a22*a35*a44*a56*a63 + + + a24*a32*a45*a56*a63 + - a22*a34*a45*a56*a63 + + a26* + a35*a43*a52*a64 + - a25*a36*a43*a52*a64 + - a26*a33* + a45*a52*a64 + + a23*a36*a45*a52*a64 + + a25*a33*a46* + a52*a64 + - a23*a35*a46*a52*a64 + - a26*a35*a42*a53* + a64 + + a25*a36*a42*a53*a64 + + a26*a32*a45*a53*a64 + - + a22*a36*a45*a53*a64 + - a25*a32*a46*a53*a64 + + a22* + a35*a46*a53*a64 + + a26*a33*a42*a55*a64 + - a23*a36* + a42*a55*a64 + - a26*a32*a43*a55*a64 + + a22*a36*a43* + a55*a64 + + a23*a32*a46*a55*a64 + - a22*a33*a46*a55* + a64 + - a25*a33*a42*a56*a64 + + a23*a35*a42*a56*a64 + + + a25*a32*a43*a56*a64 + - a22*a35*a43*a56*a64 + - a23* + a32*a45*a56*a64 + + a22*a33*a45*a56*a64 + - a26*a34* + a43*a52*a65 + + a24*a36*a43*a52*a65 + + a26*a33*a44* + a52*a65 + - a23*a36*a44*a52*a65 + - a24*a33*a46*a52* + a65 + + a23*a34*a46*a52*a65 + + a26*a34*a42*a53*a65 + - + a24*a36*a42*a53*a65 + - a26*a32*a44*a53*a65 + + a22* + a36*a44*a53*a65 + + a24*a32*a46*a53*a65 + - a22*a34* + a46*a53*a65 + - a26*a33*a42*a54*a65 + + a23*a36*a42* + a54*a65 + + a26*a32*a43*a54*a65 + - a22*a36*a43*a54* + a65 + - a23*a32*a46*a54*a65 + + a22*a33*a46*a54*a65 + + + a24*a33*a42*a56*a65 + - a23*a34*a42*a56*a65 + - a24* + a32*a43*a56*a65 + + a22*a34*a43*a56*a65 + + a23*a32* + a44*a56*a65 + - a22*a33*a44*a56*a65 + + a25*a34*a43* + a52*a66 + - a24*a35*a43*a52*a66 + - a25*a33*a44*a52* + a66 + + a23*a35*a44*a52*a66 + + a24*a33*a45*a52*a66 + - + a23*a34*a45*a52*a66 + - a25*a34*a42*a53*a66 + + a24* + a35*a42*a53*a66 + + a25*a32*a44*a53*a66 + - a22*a35* + a44*a53*a66 + - a24*a32*a45*a53*a66 + + a22*a34*a45* + a53*a66 + + a25*a33*a42*a54*a66 + - a23*a35*a42*a54* + a66 + - a25*a32*a43*a54*a66 + + a22*a35*a43*a54*a66 + + + a23*a32*a45*a54*a66 + - a22*a33*a45*a54*a66 + - a24* + a33*a42*a55*a66 + + a23*a34*a42*a55*a66 + + a24*a32* + a43*a55*a66 + - a22*a34*a43*a55*a66 + - a23*a32*a44* + a55*a66 + + a22*a33*a44*a55*a66; + cofactor[1] = -a16*a35*a44*a53*a62 + + a15*a36*a44*a53*a62 + + a16*a34*a45*a53*a62 + - a14*a36*a45*a53*a62 + - a15*a34*a46*a53*a62 + + a14*a35*a46*a53*a62 + + a16*a35*a43*a54*a62 + - a15*a36*a43*a54*a62 + - a16*a33*a45*a54*a62 + + a13*a36*a45*a54*a62 + + a15*a33*a46*a54*a62 + - a13*a35*a46*a54*a62 + - a16*a34*a43*a55*a62 + + a14*a36*a43*a55*a62 + + a16*a33*a44*a55*a62 + - a13*a36*a44*a55*a62 + - a14*a33*a46*a55*a62 + + a13*a34*a46*a55*a62 + + a15*a34*a43*a56*a62 + - a14*a35*a43*a56*a62 + - a15*a33*a44*a56*a62 + + a13*a35*a44*a56*a62 + + a14*a33*a45*a56*a62 + - a13*a34*a45*a56*a62 + + a16*a35*a44*a52*a63 + - a15*a36*a44*a52*a63 + - a16*a34*a45*a52*a63 + + a14*a36*a45*a52*a63 + + a15*a34*a46*a52*a63 + - a14*a35*a46*a52*a63 + - a16*a35*a42*a54*a63 + + a15*a36*a42*a54*a63 + + a16*a32*a45*a54*a63 + - a12*a36*a45*a54*a63 + - a15*a32*a46*a54*a63 + + a12*a35*a46*a54*a63 + + a16*a34*a42*a55*a63 + - a14*a36*a42*a55*a63 + - a16*a32*a44*a55*a63 + + a12*a36*a44*a55*a63 + + a14*a32*a46*a55*a63 + - a12*a34*a46*a55*a63 + - a15*a34*a42*a56*a63 + + a14*a35*a42*a56*a63 + + a15*a32*a44*a56*a63 + - a12*a35*a44*a56*a63 + - a14*a32*a45*a56*a63 + + a12*a34*a45*a56*a63 + - a16*a35*a43*a52*a64 + + a15*a36*a43*a52*a64 + + a16*a33*a45*a52*a64 + - a13*a36*a45*a52*a64 + - a15*a33*a46*a52*a64 + + a13*a35*a46*a52*a64 + + a16*a35*a42*a53*a64 + - a15*a36*a42*a53*a64 + - a16*a32*a45*a53*a64 + + a12*a36*a45*a53*a64 + + a15*a32*a46*a53*a64 + - a12*a35*a46*a53*a64 + - a16*a33*a42*a55*a64 + + a13*a36*a42*a55*a64 + + a16*a32*a43*a55*a64 + - a12*a36*a43*a55*a64 + - a13*a32*a46*a55*a64 + + a12*a33*a46*a55*a64 + + a15*a33*a42*a56*a64 + - a13*a35*a42*a56*a64 + - a15*a32*a43*a56*a64 + + a12*a35*a43*a56*a64 + + a13*a32*a45*a56*a64 + - a12*a33*a45*a56*a64 + + a16*a34*a43*a52*a65 + - a14*a36*a43*a52*a65 + - a16*a33*a44*a52*a65 + + a13*a36*a44*a52*a65 + + a14*a33*a46*a52*a65 + - a13*a34*a46*a52*a65 + - a16*a34*a42*a53*a65 + + a14*a36*a42*a53*a65 + + a16*a32*a44*a53*a65 + - a12*a36*a44*a53*a65 + - a14*a32*a46*a53*a65 + + a12*a34*a46*a53*a65 + + a16*a33*a42*a54*a65 + - a13*a36*a42*a54*a65 + - a16*a32*a43*a54*a65 + + a12*a36*a43*a54*a65 + + a13*a32*a46*a54*a65 + - a12*a33*a46*a54*a65 + - a14*a33*a42*a56*a65 + + a13*a34*a42*a56*a65 + + a14*a32*a43*a56*a65 + - a12*a34*a43*a56*a65 + - a13*a32*a44*a56*a65 + + a12*a33*a44*a56*a65 + - a15*a34*a43*a52*a66 + + a14*a35*a43*a52*a66 + + a15*a33*a44*a52*a66 + - a13*a35*a44*a52*a66 + - a14*a33*a45*a52*a66 + + a13*a34*a45*a52*a66 + + a15*a34*a42*a53*a66 + - a14*a35*a42*a53*a66 + - a15*a32*a44*a53*a66 + + a12*a35*a44*a53*a66 + + a14*a32*a45*a53*a66 + - a12*a34*a45*a53*a66 + - a15*a33*a42*a54*a66 + + a13*a35*a42*a54*a66 + + a15*a32*a43*a54*a66 + - a12*a35*a43*a54*a66 + - a13*a32*a45*a54*a66 + + a12*a33*a45*a54*a66 + + a14*a33*a42*a55*a66 + - a13*a34*a42*a55*a66 + - a14*a32*a43*a55*a66 + + a12*a34*a43*a55*a66 + + a13*a32*a44*a55*a66 + - a12*a33*a44*a55*a66; + cofactor[2] = a16*a25*a44*a53*a62 + - a15*a26*a44*a53*a62 + - + a16*a24*a45*a53*a62 + + a14*a26*a45*a53*a62 + + a15* + a24*a46*a53*a62 + - a14*a25*a46*a53*a62 + - a16*a25* + a43*a54*a62 + + a15*a26*a43*a54*a62 + + a16*a23*a45* + a54*a62 + - a13*a26*a45*a54*a62 + - a15*a23*a46*a54* + a62 + + a13*a25*a46*a54*a62 + + a16*a24*a43*a55*a62 + - + a14*a26*a43*a55*a62 + - a16*a23*a44*a55*a62 + + a13* + a26*a44*a55*a62 + + a14*a23*a46*a55*a62 + - a13*a24* + a46*a55*a62 + - a15*a24*a43*a56*a62 + + a14*a25*a43* + a56*a62 + + a15*a23*a44*a56*a62 + - a13*a25*a44*a56* + a62 + - a14*a23*a45*a56*a62 + + a13*a24*a45*a56*a62 + - + a16*a25*a44*a52*a63 + + a15*a26*a44*a52*a63 + + a16* + a24*a45*a52*a63 + - a14*a26*a45*a52*a63 + - a15*a24* + a46*a52*a63 + + a14*a25*a46*a52*a63 + + a16*a25*a42* + a54*a63 + - a15*a26*a42*a54*a63 + - a16*a22*a45*a54* + a63 + + a12*a26*a45*a54*a63 + + a15*a22*a46*a54*a63 + - + a12*a25*a46*a54*a63 + - a16*a24*a42*a55*a63 + + a14* + a26*a42*a55*a63 + + a16*a22*a44*a55*a63 + - a12*a26* + a44*a55*a63 + - a14*a22*a46*a55*a63 + + a12*a24*a46* + a55*a63 + + a15*a24*a42*a56*a63 + - a14*a25*a42*a56* + a63 + - a15*a22*a44*a56*a63 + + a12*a25*a44*a56*a63 + + + a14*a22*a45*a56*a63 + - a12*a24*a45*a56*a63 + + a16* + a25*a43*a52*a64 + - a15*a26*a43*a52*a64 + - a16*a23* + a45*a52*a64 + + a13*a26*a45*a52*a64 + + a15*a23*a46* + a52*a64 + - a13*a25*a46*a52*a64 + - a16*a25*a42*a53* + a64 + + a15*a26*a42*a53*a64 + + a16*a22*a45*a53*a64 + - + a12*a26*a45*a53*a64 + - a15*a22*a46*a53*a64 + + a12* + a25*a46*a53*a64 + + a16*a23*a42*a55*a64 + - a13*a26* + a42*a55*a64 + - a16*a22*a43*a55*a64 + + a12*a26*a43* + a55*a64 + + a13*a22*a46*a55*a64 + - a12*a23*a46*a55* + a64 + - a15*a23*a42*a56*a64 + + a13*a25*a42*a56*a64 + + + a15*a22*a43*a56*a64 + - a12*a25*a43*a56*a64 + - a13* + a22*a45*a56*a64 + + a12*a23*a45*a56*a64 + - a16*a24* + a43*a52*a65 + + a14*a26*a43*a52*a65 + + a16*a23*a44* + a52*a65 + - a13*a26*a44*a52*a65 + - a14*a23*a46*a52* + a65 + + a13*a24*a46*a52*a65 + + a16*a24*a42*a53*a65 + - + a14*a26*a42*a53*a65 + - a16*a22*a44*a53*a65 + + a12* + a26*a44*a53*a65 + + a14*a22*a46*a53*a65 + - a12*a24* + a46*a53*a65 + - a16*a23*a42*a54*a65 + + a13*a26*a42* + a54*a65 + + a16*a22*a43*a54*a65 + - a12*a26*a43*a54* + a65 + - a13*a22*a46*a54*a65 + + a12*a23*a46*a54*a65 + + + a14*a23*a42*a56*a65 + - a13*a24*a42*a56*a65 + - a14* + a22*a43*a56*a65 + + a12*a24*a43*a56*a65 + + a13*a22* + a44*a56*a65 + - a12*a23*a44*a56*a65 + + a15*a24*a43* + a52*a66 + - a14*a25*a43*a52*a66 + - a15*a23*a44*a52* + a66 + + a13*a25*a44*a52*a66 + + a14*a23*a45*a52*a66 + - + a13*a24*a45*a52*a66 + - a15*a24*a42*a53*a66 + + a14* + a25*a42*a53*a66 + + a15*a22*a44*a53*a66 + - a12*a25* + a44*a53*a66 + - a14*a22*a45*a53*a66 + + a12*a24*a45* + a53*a66 + + a15*a23*a42*a54*a66 + - a13*a25*a42*a54* + a66 + - a15*a22*a43*a54*a66 + + a12*a25*a43*a54*a66 + + + a13*a22*a45*a54*a66 + - a12*a23*a45*a54*a66 + - a14* + a23*a42*a55*a66 + + a13*a24*a42*a55*a66 + + a14*a22* + a43*a55*a66 + - a12*a24*a43*a55*a66 + - a13*a22*a44* + a55*a66 + + a12*a23*a44*a55*a66; + cofactor[3] = -a16*a25*a34*a53*a62 + + a15*a26*a34*a53*a62 + + a16*a24*a35*a53*a62 + - a14*a26*a35*a53*a62 + - a15*a24*a36*a53*a62 + + a14*a25*a36*a53*a62 + + a16*a25*a33*a54*a62 + - a15*a26*a33*a54*a62 + - a16*a23*a35*a54*a62 + + a13*a26*a35*a54*a62 + + a15*a23*a36*a54*a62 + - a13*a25*a36*a54*a62 + - a16*a24*a33*a55*a62 + + a14*a26*a33*a55*a62 + + a16*a23*a34*a55*a62 + - a13*a26*a34*a55*a62 + - a14*a23*a36*a55*a62 + + a13*a24*a36*a55*a62 + + a15*a24*a33*a56*a62 + - a14*a25*a33*a56*a62 + - a15*a23*a34*a56*a62 + + a13*a25*a34*a56*a62 + + a14*a23*a35*a56*a62 + - a13*a24*a35*a56*a62 + + a16*a25*a34*a52*a63 + - a15*a26*a34*a52*a63 + - a16*a24*a35*a52*a63 + + a14*a26*a35*a52*a63 + + a15*a24*a36*a52*a63 + - a14*a25*a36*a52*a63 + - a16*a25*a32*a54*a63 + + a15*a26*a32*a54*a63 + + a16*a22*a35*a54*a63 + - a12*a26*a35*a54*a63 + - a15*a22*a36*a54*a63 + + a12*a25*a36*a54*a63 + + a16*a24*a32*a55*a63 + - a14*a26*a32*a55*a63 + - a16*a22*a34*a55*a63 + + a12*a26*a34*a55*a63 + + a14*a22*a36*a55*a63 + - a12*a24*a36*a55*a63 + - a15*a24*a32*a56*a63 + + a14*a25*a32*a56*a63 + + a15*a22*a34*a56*a63 + - a12*a25*a34*a56*a63 + - a14*a22*a35*a56*a63 + + a12*a24*a35*a56*a63 + - a16*a25*a33*a52*a64 + + a15*a26*a33*a52*a64 + + a16*a23*a35*a52*a64 + - a13*a26*a35*a52*a64 + - a15*a23*a36*a52*a64 + + a13*a25*a36*a52*a64 + + a16*a25*a32*a53*a64 + - a15*a26*a32*a53*a64 + - a16*a22*a35*a53*a64 + + a12*a26*a35*a53*a64 + + a15*a22*a36*a53*a64 + - a12*a25*a36*a53*a64 + - a16*a23*a32*a55*a64 + + a13*a26*a32*a55*a64 + + a16*a22*a33*a55*a64 + - a12*a26*a33*a55*a64 + - a13*a22*a36*a55*a64 + + a12*a23*a36*a55*a64 + + a15*a23*a32*a56*a64 + - a13*a25*a32*a56*a64 + - a15*a22*a33*a56*a64 + + a12*a25*a33*a56*a64 + + a13*a22*a35*a56*a64 + - a12*a23*a35*a56*a64 + + a16*a24*a33*a52*a65 + - a14*a26*a33*a52*a65 + - a16*a23*a34*a52*a65 + + a13*a26*a34*a52*a65 + + a14*a23*a36*a52*a65 + - a13*a24*a36*a52*a65 + - a16*a24*a32*a53*a65 + + a14*a26*a32*a53*a65 + + a16*a22*a34*a53*a65 + - a12*a26*a34*a53*a65 + - a14*a22*a36*a53*a65 + + a12*a24*a36*a53*a65 + + a16*a23*a32*a54*a65 + - a13*a26*a32*a54*a65 + - a16*a22*a33*a54*a65 + + a12*a26*a33*a54*a65 + + a13*a22*a36*a54*a65 + - a12*a23*a36*a54*a65 + - a14*a23*a32*a56*a65 + + a13*a24*a32*a56*a65 + + a14*a22*a33*a56*a65 + - a12*a24*a33*a56*a65 + - a13*a22*a34*a56*a65 + + a12*a23*a34*a56*a65 + - a15*a24*a33*a52*a66 + + a14*a25*a33*a52*a66 + + a15*a23*a34*a52*a66 + - a13*a25*a34*a52*a66 + - a14*a23*a35*a52*a66 + + a13*a24*a35*a52*a66 + + a15*a24*a32*a53*a66 + - a14*a25*a32*a53*a66 + - a15*a22*a34*a53*a66 + + a12*a25*a34*a53*a66 + + a14*a22*a35*a53*a66 + - a12*a24*a35*a53*a66 + - a15*a23*a32*a54*a66 + + a13*a25*a32*a54*a66 + + a15*a22*a33*a54*a66 + - a12*a25*a33*a54*a66 + - a13*a22*a35*a54*a66 + + a12*a23*a35*a54*a66 + + a14*a23*a32*a55*a66 + - a13*a24*a32*a55*a66 + - a14*a22*a33*a55*a66 + + a12*a24*a33*a55*a66 + + a13*a22*a34*a55*a66 + - a12*a23*a34*a55*a66; + cofactor[4] = a16*a25*a34*a43*a62 + - a15*a26*a34*a43*a62 + - + a16*a24*a35*a43*a62 + + a14*a26*a35*a43*a62 + + a15* + a24*a36*a43*a62 + - a14*a25*a36*a43*a62 + - a16*a25* + a33*a44*a62 + + a15*a26*a33*a44*a62 + + a16*a23*a35* + a44*a62 + - a13*a26*a35*a44*a62 + - a15*a23*a36*a44* + a62 + + a13*a25*a36*a44*a62 + + a16*a24*a33*a45*a62 + - + a14*a26*a33*a45*a62 + - a16*a23*a34*a45*a62 + + a13* + a26*a34*a45*a62 + + a14*a23*a36*a45*a62 + - a13*a24* + a36*a45*a62 + - a15*a24*a33*a46*a62 + + a14*a25*a33* + a46*a62 + + a15*a23*a34*a46*a62 + - a13*a25*a34*a46* + a62 + - a14*a23*a35*a46*a62 + + a13*a24*a35*a46*a62 + - + a16*a25*a34*a42*a63 + + a15*a26*a34*a42*a63 + + a16* + a24*a35*a42*a63 + - a14*a26*a35*a42*a63 + - a15*a24* + a36*a42*a63 + + a14*a25*a36*a42*a63 + + a16*a25*a32* + a44*a63 + - a15*a26*a32*a44*a63 + - a16*a22*a35*a44* + a63 + + a12*a26*a35*a44*a63 + + a15*a22*a36*a44*a63 + - + a12*a25*a36*a44*a63 + - a16*a24*a32*a45*a63 + + a14* + a26*a32*a45*a63 + + a16*a22*a34*a45*a63 + - a12*a26* + a34*a45*a63 + - a14*a22*a36*a45*a63 + + a12*a24*a36* + a45*a63 + + a15*a24*a32*a46*a63 + - a14*a25*a32*a46* + a63 + - a15*a22*a34*a46*a63 + + a12*a25*a34*a46*a63 + + + a14*a22*a35*a46*a63 + - a12*a24*a35*a46*a63 + + a16* + a25*a33*a42*a64 + - a15*a26*a33*a42*a64 + - a16*a23* + a35*a42*a64 + + a13*a26*a35*a42*a64 + + a15*a23*a36* + a42*a64 + - a13*a25*a36*a42*a64 + - a16*a25*a32*a43* + a64 + + a15*a26*a32*a43*a64 + + a16*a22*a35*a43*a64 + - + a12*a26*a35*a43*a64 + - a15*a22*a36*a43*a64 + + a12* + a25*a36*a43*a64 + + a16*a23*a32*a45*a64 + - a13*a26* + a32*a45*a64 + - a16*a22*a33*a45*a64 + + a12*a26*a33* + a45*a64 + + a13*a22*a36*a45*a64 + - a12*a23*a36*a45* + a64 + - a15*a23*a32*a46*a64 + + a13*a25*a32*a46*a64 + + + a15*a22*a33*a46*a64 + - a12*a25*a33*a46*a64 + - a13* + a22*a35*a46*a64 + + a12*a23*a35*a46*a64 + - a16*a24* + a33*a42*a65 + + a14*a26*a33*a42*a65 + + a16*a23*a34* + a42*a65 + - a13*a26*a34*a42*a65 + - a14*a23*a36*a42* + a65 + + a13*a24*a36*a42*a65 + + a16*a24*a32*a43*a65 + - + a14*a26*a32*a43*a65 + - a16*a22*a34*a43*a65 + + a12* + a26*a34*a43*a65 + + a14*a22*a36*a43*a65 + - a12*a24* + a36*a43*a65 + - a16*a23*a32*a44*a65 + + a13*a26*a32* + a44*a65 + + a16*a22*a33*a44*a65 + - a12*a26*a33*a44* + a65 + - a13*a22*a36*a44*a65 + + a12*a23*a36*a44*a65 + + + a14*a23*a32*a46*a65 + - a13*a24*a32*a46*a65 + - a14* + a22*a33*a46*a65 + + a12*a24*a33*a46*a65 + + a13*a22* + a34*a46*a65 + - a12*a23*a34*a46*a65 + + a15*a24*a33* + a42*a66 + - a14*a25*a33*a42*a66 + - a15*a23*a34*a42* + a66 + + a13*a25*a34*a42*a66 + + a14*a23*a35*a42*a66 + - + a13*a24*a35*a42*a66 + - a15*a24*a32*a43*a66 + + a14* + a25*a32*a43*a66 + + a15*a22*a34*a43*a66 + - a12*a25* + a34*a43*a66 + - a14*a22*a35*a43*a66 + + a12*a24*a35* + a43*a66 + + a15*a23*a32*a44*a66 + - a13*a25*a32*a44* + a66 + - a15*a22*a33*a44*a66 + + a12*a25*a33*a44*a66 + + + a13*a22*a35*a44*a66 + - a12*a23*a35*a44*a66 + - a14* + a23*a32*a45*a66 + + a13*a24*a32*a45*a66 + + a14*a22* + a33*a45*a66 + - a12*a24*a33*a45*a66 + - a13*a22*a34* + a45*a66 + + a12*a23*a34*a45*a66; + cofactor[5] = -a16*a25*a34*a43*a52 + + a15*a26*a34*a43*a52 + + a16*a24*a35*a43*a52 + - a14*a26*a35*a43*a52 + - a15*a24*a36*a43*a52 + + a14*a25*a36*a43*a52 + + a16*a25*a33*a44*a52 + - a15*a26*a33*a44*a52 + - a16*a23*a35*a44*a52 + + a13*a26*a35*a44*a52 + + a15*a23*a36*a44*a52 + - a13*a25*a36*a44*a52 + - a16*a24*a33*a45*a52 + + a14*a26*a33*a45*a52 + + a16*a23*a34*a45*a52 + - a13*a26*a34*a45*a52 + - a14*a23*a36*a45*a52 + + a13*a24*a36*a45*a52 + + a15*a24*a33*a46*a52 + - a14*a25*a33*a46*a52 + - a15*a23*a34*a46*a52 + + a13*a25*a34*a46*a52 + + a14*a23*a35*a46*a52 + - a13*a24*a35*a46*a52 + + a16*a25*a34*a42*a53 + - a15*a26*a34*a42*a53 + - a16*a24*a35*a42*a53 + + a14*a26*a35*a42*a53 + + a15*a24*a36*a42*a53 + - a14*a25*a36*a42*a53 + - a16*a25*a32*a44*a53 + + a15*a26*a32*a44*a53 + + a16*a22*a35*a44*a53 + - a12*a26*a35*a44*a53 + - a15*a22*a36*a44*a53 + + a12*a25*a36*a44*a53 + + a16*a24*a32*a45*a53 + - a14*a26*a32*a45*a53 + - a16*a22*a34*a45*a53 + + a12*a26*a34*a45*a53 + + a14*a22*a36*a45*a53 + - a12*a24*a36*a45*a53 + - a15*a24*a32*a46*a53 + + a14*a25*a32*a46*a53 + + a15*a22*a34*a46*a53 + - a12*a25*a34*a46*a53 + - a14*a22*a35*a46*a53 + + a12*a24*a35*a46*a53 + - a16*a25*a33*a42*a54 + + a15*a26*a33*a42*a54 + + a16*a23*a35*a42*a54 + - a13*a26*a35*a42*a54 + - a15*a23*a36*a42*a54 + + a13*a25*a36*a42*a54 + + a16*a25*a32*a43*a54 + - a15*a26*a32*a43*a54 + - a16*a22*a35*a43*a54 + + a12*a26*a35*a43*a54 + + a15*a22*a36*a43*a54 + - a12*a25*a36*a43*a54 + - a16*a23*a32*a45*a54 + + a13*a26*a32*a45*a54 + + a16*a22*a33*a45*a54 + - a12*a26*a33*a45*a54 + - a13*a22*a36*a45*a54 + + a12*a23*a36*a45*a54 + + a15*a23*a32*a46*a54 + - a13*a25*a32*a46*a54 + - a15*a22*a33*a46*a54 + + a12*a25*a33*a46*a54 + + a13*a22*a35*a46*a54 + - a12*a23*a35*a46*a54 + + a16*a24*a33*a42*a55 + - a14*a26*a33*a42*a55 + - a16*a23*a34*a42*a55 + + a13*a26*a34*a42*a55 + + a14*a23*a36*a42*a55 + - a13*a24*a36*a42*a55 + - a16*a24*a32*a43*a55 + + a14*a26*a32*a43*a55 + + a16*a22*a34*a43*a55 + - a12*a26*a34*a43*a55 + - a14*a22*a36*a43*a55 + + a12*a24*a36*a43*a55 + + a16*a23*a32*a44*a55 + - a13*a26*a32*a44*a55 + - a16*a22*a33*a44*a55 + + a12*a26*a33*a44*a55 + + a13*a22*a36*a44*a55 + - a12*a23*a36*a44*a55 + - a14*a23*a32*a46*a55 + + a13*a24*a32*a46*a55 + + a14*a22*a33*a46*a55 + - a12*a24*a33*a46*a55 + - a13*a22*a34*a46*a55 + + a12*a23*a34*a46*a55 + - a15*a24*a33*a42*a56 + + a14*a25*a33*a42*a56 + + a15*a23*a34*a42*a56 + - a13*a25*a34*a42*a56 + - a14*a23*a35*a42*a56 + + a13*a24*a35*a42*a56 + + a15*a24*a32*a43*a56 + - a14*a25*a32*a43*a56 + - a15*a22*a34*a43*a56 + + a12*a25*a34*a43*a56 + + a14*a22*a35*a43*a56 + - a12*a24*a35*a43*a56 + - a15*a23*a32*a44*a56 + + a13*a25*a32*a44*a56 + + a15*a22*a33*a44*a56 + - a12*a25*a33*a44*a56 + - a13*a22*a35*a44*a56 + + a12*a23*a35*a44*a56 + + a14*a23*a32*a45*a56 + - a13*a24*a32*a45*a56 + - a14*a22*a33*a45*a56 + + a12*a24*a33*a45*a56 + + a13*a22*a34*a45*a56 + - a12*a23*a34*a45*a56; + cofactor[6] = -a26*a35*a44*a53*a61 + + a25*a36*a44*a53*a61 + + a26*a34*a45*a53*a61 + - a24*a36*a45*a53*a61 + - a25*a34*a46*a53*a61 + + a24*a35*a46*a53*a61 + + a26*a35*a43*a54*a61 + - a25*a36*a43*a54*a61 + - a26*a33*a45*a54*a61 + + a23*a36*a45*a54*a61 + + a25*a33*a46*a54*a61 + - a23*a35*a46*a54*a61 + - a26*a34*a43*a55*a61 + + a24*a36*a43*a55*a61 + + a26*a33*a44*a55*a61 + - a23*a36*a44*a55*a61 + - a24*a33*a46*a55*a61 + + a23*a34*a46*a55*a61 + + a25*a34*a43*a56*a61 + - a24*a35*a43*a56*a61 + - a25*a33*a44*a56*a61 + + a23*a35*a44*a56*a61 + + a24*a33*a45*a56*a61 + - a23*a34*a45*a56*a61 + + a26*a35*a44*a51*a63 + - a25*a36*a44*a51*a63 + - a26*a34*a45*a51*a63 + + a24*a36*a45*a51*a63 + + a25*a34*a46*a51*a63 + - a24*a35*a46*a51*a63 + - a26*a35*a41*a54*a63 + + a25*a36*a41*a54*a63 + + a26*a31*a45*a54*a63 + - a21*a36*a45*a54*a63 + - a25*a31*a46*a54*a63 + + a21*a35*a46*a54*a63 + + a26*a34*a41*a55*a63 + - a24*a36*a41*a55*a63 + - a26*a31*a44*a55*a63 + + a21*a36*a44*a55*a63 + + a24*a31*a46*a55*a63 + - a21*a34*a46*a55*a63 + - a25*a34*a41*a56*a63 + + a24*a35*a41*a56*a63 + + a25*a31*a44*a56*a63 + - a21*a35*a44*a56*a63 + - a24*a31*a45*a56*a63 + + a21*a34*a45*a56*a63 + - a26*a35*a43*a51*a64 + + a25*a36*a43*a51*a64 + + a26*a33*a45*a51*a64 + - a23*a36*a45*a51*a64 + - a25*a33*a46*a51*a64 + + a23*a35*a46*a51*a64 + + a26*a35*a41*a53*a64 + - a25*a36*a41*a53*a64 + - a26*a31*a45*a53*a64 + + a21*a36*a45*a53*a64 + + a25*a31*a46*a53*a64 + - a21*a35*a46*a53*a64 + - a26*a33*a41*a55*a64 + + a23*a36*a41*a55*a64 + + a26*a31*a43*a55*a64 + - a21*a36*a43*a55*a64 + - a23*a31*a46*a55*a64 + + a21*a33*a46*a55*a64 + + a25*a33*a41*a56*a64 + - a23*a35*a41*a56*a64 + - a25*a31*a43*a56*a64 + + a21*a35*a43*a56*a64 + + a23*a31*a45*a56*a64 + - a21*a33*a45*a56*a64 + + a26*a34*a43*a51*a65 + - a24*a36*a43*a51*a65 + - a26*a33*a44*a51*a65 + + a23*a36*a44*a51*a65 + + a24*a33*a46*a51*a65 + - a23*a34*a46*a51*a65 + - a26*a34*a41*a53*a65 + + a24*a36*a41*a53*a65 + + a26*a31*a44*a53*a65 + - a21*a36*a44*a53*a65 + - a24*a31*a46*a53*a65 + + a21*a34*a46*a53*a65 + + a26*a33*a41*a54*a65 + - a23*a36*a41*a54*a65 + - a26*a31*a43*a54*a65 + + a21*a36*a43*a54*a65 + + a23*a31*a46*a54*a65 + - a21*a33*a46*a54*a65 + - a24*a33*a41*a56*a65 + + a23*a34*a41*a56*a65 + + a24*a31*a43*a56*a65 + - a21*a34*a43*a56*a65 + - a23*a31*a44*a56*a65 + + a21*a33*a44*a56*a65 + - a25*a34*a43*a51*a66 + + a24*a35*a43*a51*a66 + + a25*a33*a44*a51*a66 + - a23*a35*a44*a51*a66 + - a24*a33*a45*a51*a66 + + a23*a34*a45*a51*a66 + + a25*a34*a41*a53*a66 + - a24*a35*a41*a53*a66 + - a25*a31*a44*a53*a66 + + a21*a35*a44*a53*a66 + + a24*a31*a45*a53*a66 + - a21*a34*a45*a53*a66 + - a25*a33*a41*a54*a66 + + a23*a35*a41*a54*a66 + + a25*a31*a43*a54*a66 + - a21*a35*a43*a54*a66 + - a23*a31*a45*a54*a66 + + a21*a33*a45*a54*a66 + + a24*a33*a41*a55*a66 + - a23*a34*a41*a55*a66 + - a24*a31*a43*a55*a66 + + a21*a34*a43*a55*a66 + + a23*a31*a44*a55*a66 + - a21*a33*a44*a55*a66; + cofactor[7] = a16*a35*a44*a53*a61 + - a15*a36*a44*a53*a61 + - + a16*a34*a45*a53*a61 + + a14*a36*a45*a53*a61 + + a15* + a34*a46*a53*a61 + - a14*a35*a46*a53*a61 + - a16*a35* + a43*a54*a61 + + a15*a36*a43*a54*a61 + + a16*a33*a45* + a54*a61 + - a13*a36*a45*a54*a61 + - a15*a33*a46*a54* + a61 + + a13*a35*a46*a54*a61 + + a16*a34*a43*a55*a61 + - + a14*a36*a43*a55*a61 + - a16*a33*a44*a55*a61 + + a13* + a36*a44*a55*a61 + + a14*a33*a46*a55*a61 + - a13*a34* + a46*a55*a61 + - a15*a34*a43*a56*a61 + + a14*a35*a43* + a56*a61 + + a15*a33*a44*a56*a61 + - a13*a35*a44*a56* + a61 + - a14*a33*a45*a56*a61 + + a13*a34*a45*a56*a61 + - + a16*a35*a44*a51*a63 + + a15*a36*a44*a51*a63 + + a16* + a34*a45*a51*a63 + - a14*a36*a45*a51*a63 + - a15*a34* + a46*a51*a63 + + a14*a35*a46*a51*a63 + + a16*a35*a41* + a54*a63 + - a15*a36*a41*a54*a63 + - a16*a31*a45*a54* + a63 + + a11*a36*a45*a54*a63 + + a15*a31*a46*a54*a63 + - + a11*a35*a46*a54*a63 + - a16*a34*a41*a55*a63 + + a14* + a36*a41*a55*a63 + + a16*a31*a44*a55*a63 + - a11*a36* + a44*a55*a63 + - a14*a31*a46*a55*a63 + + a11*a34*a46* + a55*a63 + + a15*a34*a41*a56*a63 + - a14*a35*a41*a56* + a63 + - a15*a31*a44*a56*a63 + + a11*a35*a44*a56*a63 + + + a14*a31*a45*a56*a63 + - a11*a34*a45*a56*a63 + + a16* + a35*a43*a51*a64 + - a15*a36*a43*a51*a64 + - a16*a33* + a45*a51*a64 + + a13*a36*a45*a51*a64 + + a15*a33*a46* + a51*a64 + - a13*a35*a46*a51*a64 + - a16*a35*a41*a53* + a64 + + a15*a36*a41*a53*a64 + + a16*a31*a45*a53*a64 + - + a11*a36*a45*a53*a64 + - a15*a31*a46*a53*a64 + + a11* + a35*a46*a53*a64 + + a16*a33*a41*a55*a64 + - a13*a36* + a41*a55*a64 + - a16*a31*a43*a55*a64 + + a11*a36*a43* + a55*a64 + + a13*a31*a46*a55*a64 + - a11*a33*a46*a55* + a64 + - a15*a33*a41*a56*a64 + + a13*a35*a41*a56*a64 + + + a15*a31*a43*a56*a64 + - a11*a35*a43*a56*a64 + - a13* + a31*a45*a56*a64 + + a11*a33*a45*a56*a64 + - a16*a34* + a43*a51*a65 + + a14*a36*a43*a51*a65 + + a16*a33*a44* + a51*a65 + - a13*a36*a44*a51*a65 + - a14*a33*a46*a51* + a65 + + a13*a34*a46*a51*a65 + + a16*a34*a41*a53*a65 + - + a14*a36*a41*a53*a65 + - a16*a31*a44*a53*a65 + + a11* + a36*a44*a53*a65 + + a14*a31*a46*a53*a65 + - a11*a34* + a46*a53*a65 + - a16*a33*a41*a54*a65 + + a13*a36*a41* + a54*a65 + + a16*a31*a43*a54*a65 + - a11*a36*a43*a54* + a65 + - a13*a31*a46*a54*a65 + + a11*a33*a46*a54*a65 + + + a14*a33*a41*a56*a65 + - a13*a34*a41*a56*a65 + - a14* + a31*a43*a56*a65 + + a11*a34*a43*a56*a65 + + a13*a31* + a44*a56*a65 + - a11*a33*a44*a56*a65 + + a15*a34*a43* + a51*a66 + - a14*a35*a43*a51*a66 + - a15*a33*a44*a51* + a66 + + a13*a35*a44*a51*a66 + + a14*a33*a45*a51*a66 + - + a13*a34*a45*a51*a66 + - a15*a34*a41*a53*a66 + + a14* + a35*a41*a53*a66 + + a15*a31*a44*a53*a66 + - a11*a35* + a44*a53*a66 + - a14*a31*a45*a53*a66 + + a11*a34*a45* + a53*a66 + + a15*a33*a41*a54*a66 + - a13*a35*a41*a54* + a66 + - a15*a31*a43*a54*a66 + + a11*a35*a43*a54*a66 + + + a13*a31*a45*a54*a66 + - a11*a33*a45*a54*a66 + - a14* + a33*a41*a55*a66 + + a13*a34*a41*a55*a66 + + a14*a31* + a43*a55*a66 + - a11*a34*a43*a55*a66 + - a13*a31*a44* + a55*a66 + + a11*a33*a44*a55*a66; + cofactor[8] = -a16*a25*a44*a53*a61 + + a15*a26*a44*a53*a61 + + a16*a24*a45*a53*a61 + - a14*a26*a45*a53*a61 + - a15*a24*a46*a53*a61 + + a14*a25*a46*a53*a61 + + a16*a25*a43*a54*a61 + - a15*a26*a43*a54*a61 + - a16*a23*a45*a54*a61 + + a13*a26*a45*a54*a61 + + a15*a23*a46*a54*a61 + - a13*a25*a46*a54*a61 + - a16*a24*a43*a55*a61 + + a14*a26*a43*a55*a61 + + a16*a23*a44*a55*a61 + - a13*a26*a44*a55*a61 + - a14*a23*a46*a55*a61 + + a13*a24*a46*a55*a61 + + a15*a24*a43*a56*a61 + - a14*a25*a43*a56*a61 + - a15*a23*a44*a56*a61 + + a13*a25*a44*a56*a61 + + a14*a23*a45*a56*a61 + - a13*a24*a45*a56*a61 + + a16*a25*a44*a51*a63 + - a15*a26*a44*a51*a63 + - a16*a24*a45*a51*a63 + + a14*a26*a45*a51*a63 + + a15*a24*a46*a51*a63 + - a14*a25*a46*a51*a63 + - a16*a25*a41*a54*a63 + + a15*a26*a41*a54*a63 + + a16*a21*a45*a54*a63 + - a11*a26*a45*a54*a63 + - a15*a21*a46*a54*a63 + + a11*a25*a46*a54*a63 + + a16*a24*a41*a55*a63 + - a14*a26*a41*a55*a63 + - a16*a21*a44*a55*a63 + + a11*a26*a44*a55*a63 + + a14*a21*a46*a55*a63 + - a11*a24*a46*a55*a63 + - a15*a24*a41*a56*a63 + + a14*a25*a41*a56*a63 + + a15*a21*a44*a56*a63 + - a11*a25*a44*a56*a63 + - a14*a21*a45*a56*a63 + + a11*a24*a45*a56*a63 + - a16*a25*a43*a51*a64 + + a15*a26*a43*a51*a64 + + a16*a23*a45*a51*a64 + - a13*a26*a45*a51*a64 + - a15*a23*a46*a51*a64 + + a13*a25*a46*a51*a64 + + a16*a25*a41*a53*a64 + - a15*a26*a41*a53*a64 + - a16*a21*a45*a53*a64 + + a11*a26*a45*a53*a64 + + a15*a21*a46*a53*a64 + - a11*a25*a46*a53*a64 + - a16*a23*a41*a55*a64 + + a13*a26*a41*a55*a64 + + a16*a21*a43*a55*a64 + - a11*a26*a43*a55*a64 + - a13*a21*a46*a55*a64 + + a11*a23*a46*a55*a64 + + a15*a23*a41*a56*a64 + - a13*a25*a41*a56*a64 + - a15*a21*a43*a56*a64 + + a11*a25*a43*a56*a64 + + a13*a21*a45*a56*a64 + - a11*a23*a45*a56*a64 + + a16*a24*a43*a51*a65 + - a14*a26*a43*a51*a65 + - a16*a23*a44*a51*a65 + + a13*a26*a44*a51*a65 + + a14*a23*a46*a51*a65 + - a13*a24*a46*a51*a65 + - a16*a24*a41*a53*a65 + + a14*a26*a41*a53*a65 + + a16*a21*a44*a53*a65 + - a11*a26*a44*a53*a65 + - a14*a21*a46*a53*a65 + + a11*a24*a46*a53*a65 + + a16*a23*a41*a54*a65 + - a13*a26*a41*a54*a65 + - a16*a21*a43*a54*a65 + + a11*a26*a43*a54*a65 + + a13*a21*a46*a54*a65 + - a11*a23*a46*a54*a65 + - a14*a23*a41*a56*a65 + + a13*a24*a41*a56*a65 + + a14*a21*a43*a56*a65 + - a11*a24*a43*a56*a65 + - a13*a21*a44*a56*a65 + + a11*a23*a44*a56*a65 + - a15*a24*a43*a51*a66 + + a14*a25*a43*a51*a66 + + a15*a23*a44*a51*a66 + - a13*a25*a44*a51*a66 + - a14*a23*a45*a51*a66 + + a13*a24*a45*a51*a66 + + a15*a24*a41*a53*a66 + - a14*a25*a41*a53*a66 + - a15*a21*a44*a53*a66 + + a11*a25*a44*a53*a66 + + a14*a21*a45*a53*a66 + - a11*a24*a45*a53*a66 + - a15*a23*a41*a54*a66 + + a13*a25*a41*a54*a66 + + a15*a21*a43*a54*a66 + - a11*a25*a43*a54*a66 + - a13*a21*a45*a54*a66 + + a11*a23*a45*a54*a66 + + a14*a23*a41*a55*a66 + - a13*a24*a41*a55*a66 + - a14*a21*a43*a55*a66 + + a11*a24*a43*a55*a66 + + a13*a21*a44*a55*a66 + - a11*a23*a44*a55*a66; + cofactor[9] = a16*a25*a34*a53*a61 + - a15*a26*a34*a53*a61 + - + a16*a24*a35*a53*a61 + + a14*a26*a35*a53*a61 + + a15* + a24*a36*a53*a61 + - a14*a25*a36*a53*a61 + - a16*a25* + a33*a54*a61 + + a15*a26*a33*a54*a61 + + a16*a23*a35* + a54*a61 + - a13*a26*a35*a54*a61 + - a15*a23*a36*a54* + a61 + + a13*a25*a36*a54*a61 + + a16*a24*a33*a55*a61 + - + a14*a26*a33*a55*a61 + - a16*a23*a34*a55*a61 + + a13* + a26*a34*a55*a61 + + a14*a23*a36*a55*a61 + - a13*a24* + a36*a55*a61 + - a15*a24*a33*a56*a61 + + a14*a25*a33* + a56*a61 + + a15*a23*a34*a56*a61 + - a13*a25*a34*a56* + a61 + - a14*a23*a35*a56*a61 + + a13*a24*a35*a56*a61 + - + a16*a25*a34*a51*a63 + + a15*a26*a34*a51*a63 + + a16* + a24*a35*a51*a63 + - a14*a26*a35*a51*a63 + - a15*a24* + a36*a51*a63 + + a14*a25*a36*a51*a63 + + a16*a25*a31* + a54*a63 + - a15*a26*a31*a54*a63 + - a16*a21*a35*a54* + a63 + + a11*a26*a35*a54*a63 + + a15*a21*a36*a54*a63 + - + a11*a25*a36*a54*a63 + - a16*a24*a31*a55*a63 + + a14* + a26*a31*a55*a63 + + a16*a21*a34*a55*a63 + - a11*a26* + a34*a55*a63 + - a14*a21*a36*a55*a63 + + a11*a24*a36* + a55*a63 + + a15*a24*a31*a56*a63 + - a14*a25*a31*a56* + a63 + - a15*a21*a34*a56*a63 + + a11*a25*a34*a56*a63 + + + a14*a21*a35*a56*a63 + - a11*a24*a35*a56*a63 + + a16* + a25*a33*a51*a64 + - a15*a26*a33*a51*a64 + - a16*a23* + a35*a51*a64 + + a13*a26*a35*a51*a64 + + a15*a23*a36* + a51*a64 + - a13*a25*a36*a51*a64 + - a16*a25*a31*a53* + a64 + + a15*a26*a31*a53*a64 + + a16*a21*a35*a53*a64 + - + a11*a26*a35*a53*a64 + - a15*a21*a36*a53*a64 + + a11* + a25*a36*a53*a64 + + a16*a23*a31*a55*a64 + - a13*a26* + a31*a55*a64 + - a16*a21*a33*a55*a64 + + a11*a26*a33* + a55*a64 + + a13*a21*a36*a55*a64 + - a11*a23*a36*a55* + a64 + - a15*a23*a31*a56*a64 + + a13*a25*a31*a56*a64 + + + a15*a21*a33*a56*a64 + - a11*a25*a33*a56*a64 + - a13* + a21*a35*a56*a64 + + a11*a23*a35*a56*a64 + - a16*a24* + a33*a51*a65 + + a14*a26*a33*a51*a65 + + a16*a23*a34* + a51*a65 + - a13*a26*a34*a51*a65 + - a14*a23*a36*a51* + a65 + + a13*a24*a36*a51*a65 + + a16*a24*a31*a53*a65 + - + a14*a26*a31*a53*a65 + - a16*a21*a34*a53*a65 + + a11* + a26*a34*a53*a65 + + a14*a21*a36*a53*a65 + - a11*a24* + a36*a53*a65 + - a16*a23*a31*a54*a65 + + a13*a26*a31* + a54*a65 + + a16*a21*a33*a54*a65 + - a11*a26*a33*a54* + a65 + - a13*a21*a36*a54*a65 + + a11*a23*a36*a54*a65 + + + a14*a23*a31*a56*a65 + - a13*a24*a31*a56*a65 + - a14* + a21*a33*a56*a65 + + a11*a24*a33*a56*a65 + + a13*a21* + a34*a56*a65 + - a11*a23*a34*a56*a65 + + a15*a24*a33* + a51*a66 + - a14*a25*a33*a51*a66 + - a15*a23*a34*a51* + a66 + + a13*a25*a34*a51*a66 + + a14*a23*a35*a51*a66 + - + a13*a24*a35*a51*a66 + - a15*a24*a31*a53*a66 + + a14* + a25*a31*a53*a66 + + a15*a21*a34*a53*a66 + - a11*a25* + a34*a53*a66 + - a14*a21*a35*a53*a66 + + a11*a24*a35* + a53*a66 + + a15*a23*a31*a54*a66 + - a13*a25*a31*a54* + a66 + - a15*a21*a33*a54*a66 + + a11*a25*a33*a54*a66 + + + a13*a21*a35*a54*a66 + - a11*a23*a35*a54*a66 + - a14* + a23*a31*a55*a66 + + a13*a24*a31*a55*a66 + + a14*a21* + a33*a55*a66 + - a11*a24*a33*a55*a66 + - a13*a21*a34* + a55*a66 + + a11*a23*a34*a55*a66; + cofactor[10] = -a16*a25*a34*a43*a61 + + a15*a26*a34*a43*a61 + + a16*a24*a35*a43*a61 + - a14*a26*a35*a43*a61 + - a15*a24*a36*a43*a61 + + a14*a25*a36*a43*a61 + + a16*a25*a33*a44*a61 + - a15*a26*a33*a44*a61 + - a16*a23*a35*a44*a61 + + a13*a26*a35*a44*a61 + + a15*a23*a36*a44*a61 + - a13*a25*a36*a44*a61 + - a16*a24*a33*a45*a61 + + a14*a26*a33*a45*a61 + + a16*a23*a34*a45*a61 + - a13*a26*a34*a45*a61 + - a14*a23*a36*a45*a61 + + a13*a24*a36*a45*a61 + + a15*a24*a33*a46*a61 + - a14*a25*a33*a46*a61 + - a15*a23*a34*a46*a61 + + a13*a25*a34*a46*a61 + + a14*a23*a35*a46*a61 + - a13*a24*a35*a46*a61 + + a16*a25*a34*a41*a63 + - a15*a26*a34*a41*a63 + - a16*a24*a35*a41*a63 + + a14*a26*a35*a41*a63 + + a15*a24*a36*a41*a63 + - a14*a25*a36*a41*a63 + - a16*a25*a31*a44*a63 + + a15*a26*a31*a44*a63 + + a16*a21*a35*a44*a63 + - a11*a26*a35*a44*a63 + - a15*a21*a36*a44*a63 + + a11*a25*a36*a44*a63 + + a16*a24*a31*a45*a63 + - a14*a26*a31*a45*a63 + - a16*a21*a34*a45*a63 + + a11*a26*a34*a45*a63 + + a14*a21*a36*a45*a63 + - a11*a24*a36*a45*a63 + - a15*a24*a31*a46*a63 + + a14*a25*a31*a46*a63 + + a15*a21*a34*a46*a63 + - a11*a25*a34*a46*a63 + - a14*a21*a35*a46*a63 + + a11*a24*a35*a46*a63 + - a16*a25*a33*a41*a64 + + a15*a26*a33*a41*a64 + + a16*a23*a35*a41*a64 + - a13*a26*a35*a41*a64 + - a15*a23*a36*a41*a64 + + a13*a25*a36*a41*a64 + + a16*a25*a31*a43*a64 + - a15*a26*a31*a43*a64 + - a16*a21*a35*a43*a64 + + a11*a26*a35*a43*a64 + + a15*a21*a36*a43*a64 + - a11*a25*a36*a43*a64 + - a16*a23*a31*a45*a64 + + a13*a26*a31*a45*a64 + + a16*a21*a33*a45*a64 + - a11*a26*a33*a45*a64 + - a13*a21*a36*a45*a64 + + a11*a23*a36*a45*a64 + + a15*a23*a31*a46*a64 + - a13*a25*a31*a46*a64 + - a15*a21*a33*a46*a64 + + a11*a25*a33*a46*a64 + + a13*a21*a35*a46*a64 + - a11*a23*a35*a46*a64 + + a16*a24*a33*a41*a65 + - a14*a26*a33*a41*a65 + - a16*a23*a34*a41*a65 + + a13*a26*a34*a41*a65 + + a14*a23*a36*a41*a65 + - a13*a24*a36*a41*a65 + - a16*a24*a31*a43*a65 + + a14*a26*a31*a43*a65 + + a16*a21*a34*a43*a65 + - a11*a26*a34*a43*a65 + - a14*a21*a36*a43*a65 + + a11*a24*a36*a43*a65 + + a16*a23*a31*a44*a65 + - a13*a26*a31*a44*a65 + - a16*a21*a33*a44*a65 + + a11*a26*a33*a44*a65 + + a13*a21*a36*a44*a65 + - a11*a23*a36*a44*a65 + - a14*a23*a31*a46*a65 + + a13*a24*a31*a46*a65 + + a14*a21*a33*a46*a65 + - a11*a24*a33*a46*a65 + - a13*a21*a34*a46*a65 + + a11*a23*a34*a46*a65 + - a15*a24*a33*a41*a66 + + a14*a25*a33*a41*a66 + + a15*a23*a34*a41*a66 + - a13*a25*a34*a41*a66 + - a14*a23*a35*a41*a66 + + a13*a24*a35*a41*a66 + + a15*a24*a31*a43*a66 + - a14*a25*a31*a43*a66 + - a15*a21*a34*a43*a66 + + a11*a25*a34*a43*a66 + + a14*a21*a35*a43*a66 + - a11*a24*a35*a43*a66 + - a15*a23*a31*a44*a66 + + a13*a25*a31*a44*a66 + + a15*a21*a33*a44*a66 + - a11*a25*a33*a44*a66 + - a13*a21*a35*a44*a66 + + a11*a23*a35*a44*a66 + + a14*a23*a31*a45*a66 + - a13*a24*a31*a45*a66 + - a14*a21*a33*a45*a66 + + a11*a24*a33*a45*a66 + + a13*a21*a34*a45*a66 + - a11*a23*a34*a45*a66; + cofactor[11] = a16*a25*a34*a43*a51 + - a15*a26*a34*a43*a51 + - a16*a24*a35*a43*a51 + + a14*a26*a35*a43*a51 + + a15*a24*a36*a43*a51 + - a14*a25*a36*a43*a51 + - a16*a25*a33*a44*a51 + + a15*a26*a33*a44*a51 + + a16*a23*a35*a44*a51 + - a13*a26*a35*a44*a51 + - a15*a23*a36*a44*a51 + + a13*a25*a36*a44*a51 + + a16*a24*a33*a45*a51 + - a14*a26*a33*a45*a51 + - a16*a23*a34*a45*a51 + + a13*a26*a34*a45*a51 + + a14*a23*a36*a45*a51 + - a13*a24*a36*a45*a51 + - a15*a24*a33*a46*a51 + + a14*a25*a33*a46*a51 + + a15*a23*a34*a46*a51 + - a13*a25*a34*a46*a51 + - a14*a23*a35*a46*a51 + + a13*a24*a35*a46*a51 + - a16*a25*a34*a41*a53 + + a15*a26*a34*a41*a53 + + a16*a24*a35*a41*a53 + - a14*a26*a35*a41*a53 + - a15*a24*a36*a41*a53 + + a14*a25*a36*a41*a53 + + a16*a25*a31*a44*a53 + - a15*a26*a31*a44*a53 + - a16*a21*a35*a44*a53 + + a11*a26*a35*a44*a53 + + a15*a21*a36*a44*a53 + - a11*a25*a36*a44*a53 + - a16*a24*a31*a45*a53 + + a14*a26*a31*a45*a53 + + a16*a21*a34*a45*a53 + - a11*a26*a34*a45*a53 + - a14*a21*a36*a45*a53 + + a11*a24*a36*a45*a53 + + a15*a24*a31*a46*a53 + - a14*a25*a31*a46*a53 + - a15*a21*a34*a46*a53 + + a11*a25*a34*a46*a53 + + a14*a21*a35*a46*a53 + - a11*a24*a35*a46*a53 + + a16*a25*a33*a41*a54 + - a15*a26*a33*a41*a54 + - a16*a23*a35*a41*a54 + + a13*a26*a35*a41*a54 + + a15*a23*a36*a41*a54 + - a13*a25*a36*a41*a54 + - a16*a25*a31*a43*a54 + + a15*a26*a31*a43*a54 + + a16*a21*a35*a43*a54 + - a11*a26*a35*a43*a54 + - a15*a21*a36*a43*a54 + + a11*a25*a36*a43*a54 + + a16*a23*a31*a45*a54 + - a13*a26*a31*a45*a54 + - a16*a21*a33*a45*a54 + + a11*a26*a33*a45*a54 + + a13*a21*a36*a45*a54 + - a11*a23*a36*a45*a54 + - a15*a23*a31*a46*a54 + + a13*a25*a31*a46*a54 + + a15*a21*a33*a46*a54 + - a11*a25*a33*a46*a54 + - a13*a21*a35*a46*a54 + + a11*a23*a35*a46*a54 + - a16*a24*a33*a41*a55 + + a14*a26*a33*a41*a55 + + a16*a23*a34*a41*a55 + - a13*a26*a34*a41*a55 + - a14*a23*a36*a41*a55 + + a13*a24*a36*a41*a55 + + a16*a24*a31*a43*a55 + - a14*a26*a31*a43*a55 + - a16*a21*a34*a43*a55 + + a11*a26*a34*a43*a55 + + a14*a21*a36*a43*a55 + - a11*a24*a36*a43*a55 + - a16*a23*a31*a44*a55 + + a13*a26*a31*a44*a55 + + a16*a21*a33*a44*a55 + - a11*a26*a33*a44*a55 + - a13*a21*a36*a44*a55 + + a11*a23*a36*a44*a55 + + a14*a23*a31*a46*a55 + - a13*a24*a31*a46*a55 + - a14*a21*a33*a46*a55 + + a11*a24*a33*a46*a55 + + a13*a21*a34*a46*a55 + - a11*a23*a34*a46*a55 + + a15*a24*a33*a41*a56 + - a14*a25*a33*a41*a56 + - a15*a23*a34*a41*a56 + + a13*a25*a34*a41*a56 + + a14*a23*a35*a41*a56 + - a13*a24*a35*a41*a56 + - a15*a24*a31*a43*a56 + + a14*a25*a31*a43*a56 + + a15*a21*a34*a43*a56 + - a11*a25*a34*a43*a56 + - a14*a21*a35*a43*a56 + + a11*a24*a35*a43*a56 + + a15*a23*a31*a44*a56 + - a13*a25*a31*a44*a56 + - a15*a21*a33*a44*a56 + + a11*a25*a33*a44*a56 + + a13*a21*a35*a44*a56 + - a11*a23*a35*a44*a56 + - a14*a23*a31*a45*a56 + + a13*a24*a31*a45*a56 + + a14*a21*a33*a45*a56 + - a11*a24*a33*a45*a56 + - a13*a21*a34*a45*a56 + + a11*a23*a34*a45*a56; + cofactor[12] = a26*a35*a44*a52*a61 + - a25*a36*a44*a52*a61 + - a26*a34*a45*a52*a61 + + a24*a36*a45*a52*a61 + + a25*a34*a46*a52*a61 + - a24*a35*a46*a52*a61 + - a26*a35*a42*a54*a61 + + a25*a36*a42*a54*a61 + + a26*a32*a45*a54*a61 + - a22*a36*a45*a54*a61 + - a25*a32*a46*a54*a61 + + a22*a35*a46*a54*a61 + + a26*a34*a42*a55*a61 + - a24*a36*a42*a55*a61 + - a26*a32*a44*a55*a61 + + a22*a36*a44*a55*a61 + + a24*a32*a46*a55*a61 + - a22*a34*a46*a55*a61 + - a25*a34*a42*a56*a61 + + a24*a35*a42*a56*a61 + + a25*a32*a44*a56*a61 + - a22*a35*a44*a56*a61 + - a24*a32*a45*a56*a61 + + a22*a34*a45*a56*a61 + - a26*a35*a44*a51*a62 + + a25*a36*a44*a51*a62 + + a26*a34*a45*a51*a62 + - a24*a36*a45*a51*a62 + - a25*a34*a46*a51*a62 + + a24*a35*a46*a51*a62 + + a26*a35*a41*a54*a62 + - a25*a36*a41*a54*a62 + - a26*a31*a45*a54*a62 + + a21*a36*a45*a54*a62 + + a25*a31*a46*a54*a62 + - a21*a35*a46*a54*a62 + - a26*a34*a41*a55*a62 + + a24*a36*a41*a55*a62 + + a26*a31*a44*a55*a62 + - a21*a36*a44*a55*a62 + - a24*a31*a46*a55*a62 + + a21*a34*a46*a55*a62 + + a25*a34*a41*a56*a62 + - a24*a35*a41*a56*a62 + - a25*a31*a44*a56*a62 + + a21*a35*a44*a56*a62 + + a24*a31*a45*a56*a62 + - a21*a34*a45*a56*a62 + + a26*a35*a42*a51*a64 + - a25*a36*a42*a51*a64 + - a26*a32*a45*a51*a64 + + a22*a36*a45*a51*a64 + + a25*a32*a46*a51*a64 + - a22*a35*a46*a51*a64 + - a26*a35*a41*a52*a64 + + a25*a36*a41*a52*a64 + + a26*a31*a45*a52*a64 + - a21*a36*a45*a52*a64 + - a25*a31*a46*a52*a64 + + a21*a35*a46*a52*a64 + + a26*a32*a41*a55*a64 + - a22*a36*a41*a55*a64 + - a26*a31*a42*a55*a64 + + a21*a36*a42*a55*a64 + + a22*a31*a46*a55*a64 + - a21*a32*a46*a55*a64 + - a25*a32*a41*a56*a64 + + a22*a35*a41*a56*a64 + + a25*a31*a42*a56*a64 + - a21*a35*a42*a56*a64 + - a22*a31*a45*a56*a64 + + a21*a32*a45*a56*a64 + - a26*a34*a42*a51*a65 + + a24*a36*a42*a51*a65 + + a26*a32*a44*a51*a65 + - a22*a36*a44*a51*a65 + - a24*a32*a46*a51*a65 + + a22*a34*a46*a51*a65 + + a26*a34*a41*a52*a65 + - a24*a36*a41*a52*a65 + - a26*a31*a44*a52*a65 + + a21*a36*a44*a52*a65 + + a24*a31*a46*a52*a65 + - a21*a34*a46*a52*a65 + - a26*a32*a41*a54*a65 + + a22*a36*a41*a54*a65 + + a26*a31*a42*a54*a65 + - a21*a36*a42*a54*a65 + - a22*a31*a46*a54*a65 + + a21*a32*a46*a54*a65 + + a24*a32*a41*a56*a65 + - a22*a34*a41*a56*a65 + - a24*a31*a42*a56*a65 + + a21*a34*a42*a56*a65 + + a22*a31*a44*a56*a65 + - a21*a32*a44*a56*a65 + + a25*a34*a42*a51*a66 + - a24*a35*a42*a51*a66 + - a25*a32*a44*a51*a66 + + a22*a35*a44*a51*a66 + + a24*a32*a45*a51*a66 + - a22*a34*a45*a51*a66 + - a25*a34*a41*a52*a66 + + a24*a35*a41*a52*a66 + + a25*a31*a44*a52*a66 + - a21*a35*a44*a52*a66 + - a24*a31*a45*a52*a66 + + a21*a34*a45*a52*a66 + + a25*a32*a41*a54*a66 + - a22*a35*a41*a54*a66 + - a25*a31*a42*a54*a66 + + a21*a35*a42*a54*a66 + + a22*a31*a45*a54*a66 + - a21*a32*a45*a54*a66 + - a24*a32*a41*a55*a66 + + a22*a34*a41*a55*a66 + + a24*a31*a42*a55*a66 + - a21*a34*a42*a55*a66 + - a22*a31*a44*a55*a66 + + a21*a32*a44*a55*a66; + cofactor[13] = -a16*a35*a44*a52*a61 + + a15*a36*a44*a52*a61 + + a16*a34*a45*a52*a61 + - a14*a36*a45*a52*a61 + - a15*a34*a46*a52*a61 + + a14*a35*a46*a52*a61 + + a16*a35*a42*a54*a61 + - a15*a36*a42*a54*a61 + - a16*a32*a45*a54*a61 + + a12*a36*a45*a54*a61 + + a15*a32*a46*a54*a61 + - a12*a35*a46*a54*a61 + - a16*a34*a42*a55*a61 + + a14*a36*a42*a55*a61 + + a16*a32*a44*a55*a61 + - a12*a36*a44*a55*a61 + - a14*a32*a46*a55*a61 + + a12*a34*a46*a55*a61 + + a15*a34*a42*a56*a61 + - a14*a35*a42*a56*a61 + - a15*a32*a44*a56*a61 + + a12*a35*a44*a56*a61 + + a14*a32*a45*a56*a61 + - a12*a34*a45*a56*a61 + + a16*a35*a44*a51*a62 + - a15*a36*a44*a51*a62 + - a16*a34*a45*a51*a62 + + a14*a36*a45*a51*a62 + + a15*a34*a46*a51*a62 + - a14*a35*a46*a51*a62 + - a16*a35*a41*a54*a62 + + a15*a36*a41*a54*a62 + + a16*a31*a45*a54*a62 + - a11*a36*a45*a54*a62 + - a15*a31*a46*a54*a62 + + a11*a35*a46*a54*a62 + + a16*a34*a41*a55*a62 + - a14*a36*a41*a55*a62 + - a16*a31*a44*a55*a62 + + a11*a36*a44*a55*a62 + + a14*a31*a46*a55*a62 + - a11*a34*a46*a55*a62 + - a15*a34*a41*a56*a62 + + a14*a35*a41*a56*a62 + + a15*a31*a44*a56*a62 + - a11*a35*a44*a56*a62 + - a14*a31*a45*a56*a62 + + a11*a34*a45*a56*a62 + - a16*a35*a42*a51*a64 + + a15*a36*a42*a51*a64 + + a16*a32*a45*a51*a64 + - a12*a36*a45*a51*a64 + - a15*a32*a46*a51*a64 + + a12*a35*a46*a51*a64 + + a16*a35*a41*a52*a64 + - a15*a36*a41*a52*a64 + - a16*a31*a45*a52*a64 + + a11*a36*a45*a52*a64 + + a15*a31*a46*a52*a64 + - a11*a35*a46*a52*a64 + - a16*a32*a41*a55*a64 + + a12*a36*a41*a55*a64 + + a16*a31*a42*a55*a64 + - a11*a36*a42*a55*a64 + - a12*a31*a46*a55*a64 + + a11*a32*a46*a55*a64 + + a15*a32*a41*a56*a64 + - a12*a35*a41*a56*a64 + - a15*a31*a42*a56*a64 + + a11*a35*a42*a56*a64 + + a12*a31*a45*a56*a64 + - a11*a32*a45*a56*a64 + + a16*a34*a42*a51*a65 + - a14*a36*a42*a51*a65 + - a16*a32*a44*a51*a65 + + a12*a36*a44*a51*a65 + + a14*a32*a46*a51*a65 + - a12*a34*a46*a51*a65 + - a16*a34*a41*a52*a65 + + a14*a36*a41*a52*a65 + + a16*a31*a44*a52*a65 + - a11*a36*a44*a52*a65 + - a14*a31*a46*a52*a65 + + a11*a34*a46*a52*a65 + + a16*a32*a41*a54*a65 + - a12*a36*a41*a54*a65 + - a16*a31*a42*a54*a65 + + a11*a36*a42*a54*a65 + + a12*a31*a46*a54*a65 + - a11*a32*a46*a54*a65 + - a14*a32*a41*a56*a65 + + a12*a34*a41*a56*a65 + + a14*a31*a42*a56*a65 + - a11*a34*a42*a56*a65 + - a12*a31*a44*a56*a65 + + a11*a32*a44*a56*a65 + - a15*a34*a42*a51*a66 + + a14*a35*a42*a51*a66 + + a15*a32*a44*a51*a66 + - a12*a35*a44*a51*a66 + - a14*a32*a45*a51*a66 + + a12*a34*a45*a51*a66 + + a15*a34*a41*a52*a66 + - a14*a35*a41*a52*a66 + - a15*a31*a44*a52*a66 + + a11*a35*a44*a52*a66 + + a14*a31*a45*a52*a66 + - a11*a34*a45*a52*a66 + - a15*a32*a41*a54*a66 + + a12*a35*a41*a54*a66 + + a15*a31*a42*a54*a66 + - a11*a35*a42*a54*a66 + - a12*a31*a45*a54*a66 + + a11*a32*a45*a54*a66 + + a14*a32*a41*a55*a66 + - a12*a34*a41*a55*a66 + - a14*a31*a42*a55*a66 + + a11*a34*a42*a55*a66 + + a12*a31*a44*a55*a66 + - a11*a32*a44*a55*a66; + cofactor[14] = a16*a25*a44*a52*a61 + - a15*a26*a44*a52*a61 + - a16*a24*a45*a52*a61 + + a14*a26*a45*a52*a61 + + a15*a24*a46*a52*a61 + - a14*a25*a46*a52*a61 + - a16*a25*a42*a54*a61 + + a15*a26*a42*a54*a61 + + a16*a22*a45*a54*a61 + - a12*a26*a45*a54*a61 + - a15*a22*a46*a54*a61 + + a12*a25*a46*a54*a61 + + a16*a24*a42*a55*a61 + - a14*a26*a42*a55*a61 + - a16*a22*a44*a55*a61 + + a12*a26*a44*a55*a61 + + a14*a22*a46*a55*a61 + - a12*a24*a46*a55*a61 + - a15*a24*a42*a56*a61 + + a14*a25*a42*a56*a61 + + a15*a22*a44*a56*a61 + - a12*a25*a44*a56*a61 + - a14*a22*a45*a56*a61 + + a12*a24*a45*a56*a61 + - a16*a25*a44*a51*a62 + + a15*a26*a44*a51*a62 + + a16*a24*a45*a51*a62 + - a14*a26*a45*a51*a62 + - a15*a24*a46*a51*a62 + + a14*a25*a46*a51*a62 + + a16*a25*a41*a54*a62 + - a15*a26*a41*a54*a62 + - a16*a21*a45*a54*a62 + + a11*a26*a45*a54*a62 + + a15*a21*a46*a54*a62 + - a11*a25*a46*a54*a62 + - a16*a24*a41*a55*a62 + + a14*a26*a41*a55*a62 + + a16*a21*a44*a55*a62 + - a11*a26*a44*a55*a62 + - a14*a21*a46*a55*a62 + + a11*a24*a46*a55*a62 + + a15*a24*a41*a56*a62 + - a14*a25*a41*a56*a62 + - a15*a21*a44*a56*a62 + + a11*a25*a44*a56*a62 + + a14*a21*a45*a56*a62 + - a11*a24*a45*a56*a62 + + a16*a25*a42*a51*a64 + - a15*a26*a42*a51*a64 + - a16*a22*a45*a51*a64 + + a12*a26*a45*a51*a64 + + a15*a22*a46*a51*a64 + - a12*a25*a46*a51*a64 + - a16*a25*a41*a52*a64 + + a15*a26*a41*a52*a64 + + a16*a21*a45*a52*a64 + - a11*a26*a45*a52*a64 + - a15*a21*a46*a52*a64 + + a11*a25*a46*a52*a64 + + a16*a22*a41*a55*a64 + - a12*a26*a41*a55*a64 + - a16*a21*a42*a55*a64 + + a11*a26*a42*a55*a64 + + a12*a21*a46*a55*a64 + - a11*a22*a46*a55*a64 + - a15*a22*a41*a56*a64 + + a12*a25*a41*a56*a64 + + a15*a21*a42*a56*a64 + - a11*a25*a42*a56*a64 + - a12*a21*a45*a56*a64 + + a11*a22*a45*a56*a64 + - a16*a24*a42*a51*a65 + + a14*a26*a42*a51*a65 + + a16*a22*a44*a51*a65 + - a12*a26*a44*a51*a65 + - a14*a22*a46*a51*a65 + + a12*a24*a46*a51*a65 + + a16*a24*a41*a52*a65 + - a14*a26*a41*a52*a65 + - a16*a21*a44*a52*a65 + + a11*a26*a44*a52*a65 + + a14*a21*a46*a52*a65 + - a11*a24*a46*a52*a65 + - a16*a22*a41*a54*a65 + + a12*a26*a41*a54*a65 + + a16*a21*a42*a54*a65 + - a11*a26*a42*a54*a65 + - a12*a21*a46*a54*a65 + + a11*a22*a46*a54*a65 + + a14*a22*a41*a56*a65 + - a12*a24*a41*a56*a65 + - a14*a21*a42*a56*a65 + + a11*a24*a42*a56*a65 + + a12*a21*a44*a56*a65 + - a11*a22*a44*a56*a65 + + a15*a24*a42*a51*a66 + - a14*a25*a42*a51*a66 + - a15*a22*a44*a51*a66 + + a12*a25*a44*a51*a66 + + a14*a22*a45*a51*a66 + - a12*a24*a45*a51*a66 + - a15*a24*a41*a52*a66 + + a14*a25*a41*a52*a66 + + a15*a21*a44*a52*a66 + - a11*a25*a44*a52*a66 + - a14*a21*a45*a52*a66 + + a11*a24*a45*a52*a66 + + a15*a22*a41*a54*a66 + - a12*a25*a41*a54*a66 + - a15*a21*a42*a54*a66 + + a11*a25*a42*a54*a66 + + a12*a21*a45*a54*a66 + - a11*a22*a45*a54*a66 + - a14*a22*a41*a55*a66 + + a12*a24*a41*a55*a66 + + a14*a21*a42*a55*a66 + - a11*a24*a42*a55*a66 + - a12*a21*a44*a55*a66 + + a11*a22*a44*a55*a66; + cofactor[15] = -a16*a25*a34*a52*a61 + + a15*a26*a34*a52*a61 + + a16*a24*a35*a52*a61 + - a14*a26*a35*a52*a61 + - a15*a24*a36*a52*a61 + + a14*a25*a36*a52*a61 + + a16*a25*a32*a54*a61 + - a15*a26*a32*a54*a61 + - a16*a22*a35*a54*a61 + + a12*a26*a35*a54*a61 + + a15*a22*a36*a54*a61 + - a12*a25*a36*a54*a61 + - a16*a24*a32*a55*a61 + + a14*a26*a32*a55*a61 + + a16*a22*a34*a55*a61 + - a12*a26*a34*a55*a61 + - a14*a22*a36*a55*a61 + + a12*a24*a36*a55*a61 + + a15*a24*a32*a56*a61 + - a14*a25*a32*a56*a61 + - a15*a22*a34*a56*a61 + + a12*a25*a34*a56*a61 + + a14*a22*a35*a56*a61 + - a12*a24*a35*a56*a61 + + a16*a25*a34*a51*a62 + - a15*a26*a34*a51*a62 + - a16*a24*a35*a51*a62 + + a14*a26*a35*a51*a62 + + a15*a24*a36*a51*a62 + - a14*a25*a36*a51*a62 + - a16*a25*a31*a54*a62 + + a15*a26*a31*a54*a62 + + a16*a21*a35*a54*a62 + - a11*a26*a35*a54*a62 + - a15*a21*a36*a54*a62 + + a11*a25*a36*a54*a62 + + a16*a24*a31*a55*a62 + - a14*a26*a31*a55*a62 + - a16*a21*a34*a55*a62 + + a11*a26*a34*a55*a62 + + a14*a21*a36*a55*a62 + - a11*a24*a36*a55*a62 + - a15*a24*a31*a56*a62 + + a14*a25*a31*a56*a62 + + a15*a21*a34*a56*a62 + - a11*a25*a34*a56*a62 + - a14*a21*a35*a56*a62 + + a11*a24*a35*a56*a62 + - a16*a25*a32*a51*a64 + + a15*a26*a32*a51*a64 + + a16*a22*a35*a51*a64 + - a12*a26*a35*a51*a64 + - a15*a22*a36*a51*a64 + + a12*a25*a36*a51*a64 + + a16*a25*a31*a52*a64 + - a15*a26*a31*a52*a64 + - a16*a21*a35*a52*a64 + + a11*a26*a35*a52*a64 + + a15*a21*a36*a52*a64 + - a11*a25*a36*a52*a64 + - a16*a22*a31*a55*a64 + + a12*a26*a31*a55*a64 + + a16*a21*a32*a55*a64 + - a11*a26*a32*a55*a64 + - a12*a21*a36*a55*a64 + + a11*a22*a36*a55*a64 + + a15*a22*a31*a56*a64 + - a12*a25*a31*a56*a64 + - a15*a21*a32*a56*a64 + + a11*a25*a32*a56*a64 + + a12*a21*a35*a56*a64 + - a11*a22*a35*a56*a64 + + a16*a24*a32*a51*a65 + - a14*a26*a32*a51*a65 + - a16*a22*a34*a51*a65 + + a12*a26*a34*a51*a65 + + a14*a22*a36*a51*a65 + - a12*a24*a36*a51*a65 + - a16*a24*a31*a52*a65 + + a14*a26*a31*a52*a65 + + a16*a21*a34*a52*a65 + - a11*a26*a34*a52*a65 + - a14*a21*a36*a52*a65 + + a11*a24*a36*a52*a65 + + a16*a22*a31*a54*a65 + - a12*a26*a31*a54*a65 + - a16*a21*a32*a54*a65 + + a11*a26*a32*a54*a65 + + a12*a21*a36*a54*a65 + - a11*a22*a36*a54*a65 + - a14*a22*a31*a56*a65 + + a12*a24*a31*a56*a65 + + a14*a21*a32*a56*a65 + - a11*a24*a32*a56*a65 + - a12*a21*a34*a56*a65 + + a11*a22*a34*a56*a65 + - a15*a24*a32*a51*a66 + + a14*a25*a32*a51*a66 + + a15*a22*a34*a51*a66 + - a12*a25*a34*a51*a66 + - a14*a22*a35*a51*a66 + + a12*a24*a35*a51*a66 + + a15*a24*a31*a52*a66 + - a14*a25*a31*a52*a66 + - a15*a21*a34*a52*a66 + + a11*a25*a34*a52*a66 + + a14*a21*a35*a52*a66 + - a11*a24*a35*a52*a66 + - a15*a22*a31*a54*a66 + + a12*a25*a31*a54*a66 + + a15*a21*a32*a54*a66 + - a11*a25*a32*a54*a66 + - a12*a21*a35*a54*a66 + + a11*a22*a35*a54*a66 + + a14*a22*a31*a55*a66 + - a12*a24*a31*a55*a66 + - a14*a21*a32*a55*a66 + + a11*a24*a32*a55*a66 + + a12*a21*a34*a55*a66 + - a11*a22*a34*a55*a66; + cofactor[16] = a16*a25*a34*a42*a61 + - a15*a26*a34*a42*a61 + - a16*a24*a35*a42*a61 + + a14*a26*a35*a42*a61 + + a15*a24*a36*a42*a61 + - a14*a25*a36*a42*a61 + - a16*a25*a32*a44*a61 + + a15*a26*a32*a44*a61 + + a16*a22*a35*a44*a61 + - a12*a26*a35*a44*a61 + - a15*a22*a36*a44*a61 + + a12*a25*a36*a44*a61 + + a16*a24*a32*a45*a61 + - a14*a26*a32*a45*a61 + - a16*a22*a34*a45*a61 + + a12*a26*a34*a45*a61 + + a14*a22*a36*a45*a61 + - a12*a24*a36*a45*a61 + - a15*a24*a32*a46*a61 + + a14*a25*a32*a46*a61 + + a15*a22*a34*a46*a61 + - a12*a25*a34*a46*a61 + - a14*a22*a35*a46*a61 + + a12*a24*a35*a46*a61 + - a16*a25*a34*a41*a62 + + a15*a26*a34*a41*a62 + + a16*a24*a35*a41*a62 + - a14*a26*a35*a41*a62 + - a15*a24*a36*a41*a62 + + a14*a25*a36*a41*a62 + + a16*a25*a31*a44*a62 + - a15*a26*a31*a44*a62 + - a16*a21*a35*a44*a62 + + a11*a26*a35*a44*a62 + + a15*a21*a36*a44*a62 + - a11*a25*a36*a44*a62 + - a16*a24*a31*a45*a62 + + a14*a26*a31*a45*a62 + + a16*a21*a34*a45*a62 + - a11*a26*a34*a45*a62 + - a14*a21*a36*a45*a62 + + a11*a24*a36*a45*a62 + + a15*a24*a31*a46*a62 + - a14*a25*a31*a46*a62 + - a15*a21*a34*a46*a62 + + a11*a25*a34*a46*a62 + + a14*a21*a35*a46*a62 + - a11*a24*a35*a46*a62 + + a16*a25*a32*a41*a64 + - a15*a26*a32*a41*a64 + - a16*a22*a35*a41*a64 + + a12*a26*a35*a41*a64 + + a15*a22*a36*a41*a64 + - a12*a25*a36*a41*a64 + - a16*a25*a31*a42*a64 + + a15*a26*a31*a42*a64 + + a16*a21*a35*a42*a64 + - a11*a26*a35*a42*a64 + - a15*a21*a36*a42*a64 + + a11*a25*a36*a42*a64 + + a16*a22*a31*a45*a64 + - a12*a26*a31*a45*a64 + - a16*a21*a32*a45*a64 + + a11*a26*a32*a45*a64 + + a12*a21*a36*a45*a64 + - a11*a22*a36*a45*a64 + - a15*a22*a31*a46*a64 + + a12*a25*a31*a46*a64 + + a15*a21*a32*a46*a64 + - a11*a25*a32*a46*a64 + - a12*a21*a35*a46*a64 + + a11*a22*a35*a46*a64 + - a16*a24*a32*a41*a65 + + a14*a26*a32*a41*a65 + + a16*a22*a34*a41*a65 + - a12*a26*a34*a41*a65 + - a14*a22*a36*a41*a65 + + a12*a24*a36*a41*a65 + + a16*a24*a31*a42*a65 + - a14*a26*a31*a42*a65 + - a16*a21*a34*a42*a65 + + a11*a26*a34*a42*a65 + + a14*a21*a36*a42*a65 + - a11*a24*a36*a42*a65 + - a16*a22*a31*a44*a65 + + a12*a26*a31*a44*a65 + + a16*a21*a32*a44*a65 + - a11*a26*a32*a44*a65 + - a12*a21*a36*a44*a65 + + a11*a22*a36*a44*a65 + + a14*a22*a31*a46*a65 + - a12*a24*a31*a46*a65 + - a14*a21*a32*a46*a65 + + a11*a24*a32*a46*a65 + + a12*a21*a34*a46*a65 + - a11*a22*a34*a46*a65 + + a15*a24*a32*a41*a66 + - a14*a25*a32*a41*a66 + - a15*a22*a34*a41*a66 + + a12*a25*a34*a41*a66 + + a14*a22*a35*a41*a66 + - a12*a24*a35*a41*a66 + - a15*a24*a31*a42*a66 + + a14*a25*a31*a42*a66 + + a15*a21*a34*a42*a66 + - a11*a25*a34*a42*a66 + - a14*a21*a35*a42*a66 + + a11*a24*a35*a42*a66 + + a15*a22*a31*a44*a66 + - a12*a25*a31*a44*a66 + - a15*a21*a32*a44*a66 + + a11*a25*a32*a44*a66 + + a12*a21*a35*a44*a66 + - a11*a22*a35*a44*a66 + - a14*a22*a31*a45*a66 + + a12*a24*a31*a45*a66 + + a14*a21*a32*a45*a66 + - a11*a24*a32*a45*a66 + - a12*a21*a34*a45*a66 + + a11*a22*a34*a45*a66; + cofactor[17] = -a16*a25*a34*a42*a51 + + a15*a26*a34*a42*a51 + + a16*a24*a35*a42*a51 + - a14*a26*a35*a42*a51 + - a15*a24*a36*a42*a51 + + a14*a25*a36*a42*a51 + + a16*a25*a32*a44*a51 + - a15*a26*a32*a44*a51 + - a16*a22*a35*a44*a51 + + a12*a26*a35*a44*a51 + + a15*a22*a36*a44*a51 + - a12*a25*a36*a44*a51 + - a16*a24*a32*a45*a51 + + a14*a26*a32*a45*a51 + + a16*a22*a34*a45*a51 + - a12*a26*a34*a45*a51 + - a14*a22*a36*a45*a51 + + a12*a24*a36*a45*a51 + + a15*a24*a32*a46*a51 + - a14*a25*a32*a46*a51 + - a15*a22*a34*a46*a51 + + a12*a25*a34*a46*a51 + + a14*a22*a35*a46*a51 + - a12*a24*a35*a46*a51 + + a16*a25*a34*a41*a52 + - a15*a26*a34*a41*a52 + - a16*a24*a35*a41*a52 + + a14*a26*a35*a41*a52 + + a15*a24*a36*a41*a52 + - a14*a25*a36*a41*a52 + - a16*a25*a31*a44*a52 + + a15*a26*a31*a44*a52 + + a16*a21*a35*a44*a52 + - a11*a26*a35*a44*a52 + - a15*a21*a36*a44*a52 + + a11*a25*a36*a44*a52 + + a16*a24*a31*a45*a52 + - a14*a26*a31*a45*a52 + - a16*a21*a34*a45*a52 + + a11*a26*a34*a45*a52 + + a14*a21*a36*a45*a52 + - a11*a24*a36*a45*a52 + - a15*a24*a31*a46*a52 + + a14*a25*a31*a46*a52 + + a15*a21*a34*a46*a52 + - a11*a25*a34*a46*a52 + - a14*a21*a35*a46*a52 + + a11*a24*a35*a46*a52 + - a16*a25*a32*a41*a54 + + a15*a26*a32*a41*a54 + + a16*a22*a35*a41*a54 + - a12*a26*a35*a41*a54 + - a15*a22*a36*a41*a54 + + a12*a25*a36*a41*a54 + + a16*a25*a31*a42*a54 + - a15*a26*a31*a42*a54 + - a16*a21*a35*a42*a54 + + a11*a26*a35*a42*a54 + + a15*a21*a36*a42*a54 + - a11*a25*a36*a42*a54 + - a16*a22*a31*a45*a54 + + a12*a26*a31*a45*a54 + + a16*a21*a32*a45*a54 + - a11*a26*a32*a45*a54 + - a12*a21*a36*a45*a54 + + a11*a22*a36*a45*a54 + + a15*a22*a31*a46*a54 + - a12*a25*a31*a46*a54 + - a15*a21*a32*a46*a54 + + a11*a25*a32*a46*a54 + + a12*a21*a35*a46*a54 + - a11*a22*a35*a46*a54 + + a16*a24*a32*a41*a55 + - a14*a26*a32*a41*a55 + - a16*a22*a34*a41*a55 + + a12*a26*a34*a41*a55 + + a14*a22*a36*a41*a55 + - a12*a24*a36*a41*a55 + - a16*a24*a31*a42*a55 + + a14*a26*a31*a42*a55 + + a16*a21*a34*a42*a55 + - a11*a26*a34*a42*a55 + - a14*a21*a36*a42*a55 + + a11*a24*a36*a42*a55 + + a16*a22*a31*a44*a55 + - a12*a26*a31*a44*a55 + - a16*a21*a32*a44*a55 + + a11*a26*a32*a44*a55 + + a12*a21*a36*a44*a55 + - a11*a22*a36*a44*a55 + - a14*a22*a31*a46*a55 + + a12*a24*a31*a46*a55 + + a14*a21*a32*a46*a55 + - a11*a24*a32*a46*a55 + - a12*a21*a34*a46*a55 + + a11*a22*a34*a46*a55 + - a15*a24*a32*a41*a56 + + a14*a25*a32*a41*a56 + + a15*a22*a34*a41*a56 + - a12*a25*a34*a41*a56 + - a14*a22*a35*a41*a56 + + a12*a24*a35*a41*a56 + + a15*a24*a31*a42*a56 + - a14*a25*a31*a42*a56 + - a15*a21*a34*a42*a56 + + a11*a25*a34*a42*a56 + + a14*a21*a35*a42*a56 + - a11*a24*a35*a42*a56 + - a15*a22*a31*a44*a56 + + a12*a25*a31*a44*a56 + + a15*a21*a32*a44*a56 + - a11*a25*a32*a44*a56 + - a12*a21*a35*a44*a56 + + a11*a22*a35*a44*a56 + + a14*a22*a31*a45*a56 + - a12*a24*a31*a45*a56 + - a14*a21*a32*a45*a56 + + a11*a24*a32*a45*a56 + + a12*a21*a34*a45*a56 + - a11*a22*a34*a45*a56; + cofactor[18] = -a26*a35*a43*a52*a61 + + a25*a36*a43*a52*a61 + + a26*a33*a45*a52*a61 + - a23*a36*a45*a52*a61 + - a25*a33*a46*a52*a61 + + a23*a35*a46*a52*a61 + + a26*a35*a42*a53*a61 + - a25*a36*a42*a53*a61 + - a26*a32*a45*a53*a61 + + a22*a36*a45*a53*a61 + + a25*a32*a46*a53*a61 + - a22*a35*a46*a53*a61 + - a26*a33*a42*a55*a61 + + a23*a36*a42*a55*a61 + + a26*a32*a43*a55*a61 + - a22*a36*a43*a55*a61 + - a23*a32*a46*a55*a61 + + a22*a33*a46*a55*a61 + + a25*a33*a42*a56*a61 + - a23*a35*a42*a56*a61 + - a25*a32*a43*a56*a61 + + a22*a35*a43*a56*a61 + + a23*a32*a45*a56*a61 + - a22*a33*a45*a56*a61 + + a26*a35*a43*a51*a62 + - a25*a36*a43*a51*a62 + - a26*a33*a45*a51*a62 + + a23*a36*a45*a51*a62 + + a25*a33*a46*a51*a62 + - a23*a35*a46*a51*a62 + - a26*a35*a41*a53*a62 + + a25*a36*a41*a53*a62 + + a26*a31*a45*a53*a62 + - a21*a36*a45*a53*a62 + - a25*a31*a46*a53*a62 + + a21*a35*a46*a53*a62 + + a26*a33*a41*a55*a62 + - a23*a36*a41*a55*a62 + - a26*a31*a43*a55*a62 + + a21*a36*a43*a55*a62 + + a23*a31*a46*a55*a62 + - a21*a33*a46*a55*a62 + - a25*a33*a41*a56*a62 + + a23*a35*a41*a56*a62 + + a25*a31*a43*a56*a62 + - a21*a35*a43*a56*a62 + - a23*a31*a45*a56*a62 + + a21*a33*a45*a56*a62 + - a26*a35*a42*a51*a63 + + a25*a36*a42*a51*a63 + + a26*a32*a45*a51*a63 + - a22*a36*a45*a51*a63 + - a25*a32*a46*a51*a63 + + a22*a35*a46*a51*a63 + + a26*a35*a41*a52*a63 + - a25*a36*a41*a52*a63 + - a26*a31*a45*a52*a63 + + a21*a36*a45*a52*a63 + + a25*a31*a46*a52*a63 + - a21*a35*a46*a52*a63 + - a26*a32*a41*a55*a63 + + a22*a36*a41*a55*a63 + + a26*a31*a42*a55*a63 + - a21*a36*a42*a55*a63 + - a22*a31*a46*a55*a63 + + a21*a32*a46*a55*a63 + + a25*a32*a41*a56*a63 + - a22*a35*a41*a56*a63 + - a25*a31*a42*a56*a63 + + a21*a35*a42*a56*a63 + + a22*a31*a45*a56*a63 + - a21*a32*a45*a56*a63 + + a26*a33*a42*a51*a65 + - a23*a36*a42*a51*a65 + - a26*a32*a43*a51*a65 + + a22*a36*a43*a51*a65 + + a23*a32*a46*a51*a65 + - a22*a33*a46*a51*a65 + - a26*a33*a41*a52*a65 + + a23*a36*a41*a52*a65 + + a26*a31*a43*a52*a65 + - a21*a36*a43*a52*a65 + - a23*a31*a46*a52*a65 + + a21*a33*a46*a52*a65 + + a26*a32*a41*a53*a65 + - a22*a36*a41*a53*a65 + - a26*a31*a42*a53*a65 + + a21*a36*a42*a53*a65 + + a22*a31*a46*a53*a65 + - a21*a32*a46*a53*a65 + - a23*a32*a41*a56*a65 + + a22*a33*a41*a56*a65 + + a23*a31*a42*a56*a65 + - a21*a33*a42*a56*a65 + - a22*a31*a43*a56*a65 + + a21*a32*a43*a56*a65 + - a25*a33*a42*a51*a66 + + a23*a35*a42*a51*a66 + + a25*a32*a43*a51*a66 + - a22*a35*a43*a51*a66 + - a23*a32*a45*a51*a66 + + a22*a33*a45*a51*a66 + + a25*a33*a41*a52*a66 + - a23*a35*a41*a52*a66 + - a25*a31*a43*a52*a66 + + a21*a35*a43*a52*a66 + + a23*a31*a45*a52*a66 + - a21*a33*a45*a52*a66 + - a25*a32*a41*a53*a66 + + a22*a35*a41*a53*a66 + + a25*a31*a42*a53*a66 + - a21*a35*a42*a53*a66 + - a22*a31*a45*a53*a66 + + a21*a32*a45*a53*a66 + + a23*a32*a41*a55*a66 + - a22*a33*a41*a55*a66 + - a23*a31*a42*a55*a66 + + a21*a33*a42*a55*a66 + + a22*a31*a43*a55*a66 + - a21*a32*a43*a55*a66; + cofactor[19] = a16*a35*a43*a52*a61 + - a15*a36*a43*a52*a61 + - a16*a33*a45*a52*a61 + + a13*a36*a45*a52*a61 + + a15*a33*a46*a52*a61 + - a13*a35*a46*a52*a61 + - a16*a35*a42*a53*a61 + + a15*a36*a42*a53*a61 + + a16*a32*a45*a53*a61 + - a12*a36*a45*a53*a61 + - a15*a32*a46*a53*a61 + + a12*a35*a46*a53*a61 + + a16*a33*a42*a55*a61 + - a13*a36*a42*a55*a61 + - a16*a32*a43*a55*a61 + + a12*a36*a43*a55*a61 + + a13*a32*a46*a55*a61 + - a12*a33*a46*a55*a61 + - a15*a33*a42*a56*a61 + + a13*a35*a42*a56*a61 + + a15*a32*a43*a56*a61 + - a12*a35*a43*a56*a61 + - a13*a32*a45*a56*a61 + + a12*a33*a45*a56*a61 + - a16*a35*a43*a51*a62 + + a15*a36*a43*a51*a62 + + a16*a33*a45*a51*a62 + - a13*a36*a45*a51*a62 + - a15*a33*a46*a51*a62 + + a13*a35*a46*a51*a62 + + a16*a35*a41*a53*a62 + - a15*a36*a41*a53*a62 + - a16*a31*a45*a53*a62 + + a11*a36*a45*a53*a62 + + a15*a31*a46*a53*a62 + - a11*a35*a46*a53*a62 + - a16*a33*a41*a55*a62 + + a13*a36*a41*a55*a62 + + a16*a31*a43*a55*a62 + - a11*a36*a43*a55*a62 + - a13*a31*a46*a55*a62 + + a11*a33*a46*a55*a62 + + a15*a33*a41*a56*a62 + - a13*a35*a41*a56*a62 + - a15*a31*a43*a56*a62 + + a11*a35*a43*a56*a62 + + a13*a31*a45*a56*a62 + - a11*a33*a45*a56*a62 + + a16*a35*a42*a51*a63 + - a15*a36*a42*a51*a63 + - a16*a32*a45*a51*a63 + + a12*a36*a45*a51*a63 + + a15*a32*a46*a51*a63 + - a12*a35*a46*a51*a63 + - a16*a35*a41*a52*a63 + + a15*a36*a41*a52*a63 + + a16*a31*a45*a52*a63 + - a11*a36*a45*a52*a63 + - a15*a31*a46*a52*a63 + + a11*a35*a46*a52*a63 + + a16*a32*a41*a55*a63 + - a12*a36*a41*a55*a63 + - a16*a31*a42*a55*a63 + + a11*a36*a42*a55*a63 + + a12*a31*a46*a55*a63 + - a11*a32*a46*a55*a63 + - a15*a32*a41*a56*a63 + + a12*a35*a41*a56*a63 + + a15*a31*a42*a56*a63 + - a11*a35*a42*a56*a63 + - a12*a31*a45*a56*a63 + + a11*a32*a45*a56*a63 + - a16*a33*a42*a51*a65 + + a13*a36*a42*a51*a65 + + a16*a32*a43*a51*a65 + - a12*a36*a43*a51*a65 + - a13*a32*a46*a51*a65 + + a12*a33*a46*a51*a65 + + a16*a33*a41*a52*a65 + - a13*a36*a41*a52*a65 + - a16*a31*a43*a52*a65 + + a11*a36*a43*a52*a65 + + a13*a31*a46*a52*a65 + - a11*a33*a46*a52*a65 + - a16*a32*a41*a53*a65 + + a12*a36*a41*a53*a65 + + a16*a31*a42*a53*a65 + - a11*a36*a42*a53*a65 + - a12*a31*a46*a53*a65 + + a11*a32*a46*a53*a65 + + a13*a32*a41*a56*a65 + - a12*a33*a41*a56*a65 + - a13*a31*a42*a56*a65 + + a11*a33*a42*a56*a65 + + a12*a31*a43*a56*a65 + - a11*a32*a43*a56*a65 + + a15*a33*a42*a51*a66 + - a13*a35*a42*a51*a66 + - a15*a32*a43*a51*a66 + + a12*a35*a43*a51*a66 + + a13*a32*a45*a51*a66 + - a12*a33*a45*a51*a66 + - a15*a33*a41*a52*a66 + + a13*a35*a41*a52*a66 + + a15*a31*a43*a52*a66 + - a11*a35*a43*a52*a66 + - a13*a31*a45*a52*a66 + + a11*a33*a45*a52*a66 + + a15*a32*a41*a53*a66 + - a12*a35*a41*a53*a66 + - a15*a31*a42*a53*a66 + + a11*a35*a42*a53*a66 + + a12*a31*a45*a53*a66 + - a11*a32*a45*a53*a66 + - a13*a32*a41*a55*a66 + + a12*a33*a41*a55*a66 + + a13*a31*a42*a55*a66 + - a11*a33*a42*a55*a66 + - a12*a31*a43*a55*a66 + + a11*a32*a43*a55*a66; + cofactor[20] = -a16*a25*a43*a52*a61 + + a15*a26*a43*a52*a61 + + a16*a23*a45*a52*a61 + - a13*a26*a45*a52*a61 + - a15*a23*a46*a52*a61 + + a13*a25*a46*a52*a61 + + a16*a25*a42*a53*a61 + - a15*a26*a42*a53*a61 + - a16*a22*a45*a53*a61 + + a12*a26*a45*a53*a61 + + a15*a22*a46*a53*a61 + - a12*a25*a46*a53*a61 + - a16*a23*a42*a55*a61 + + a13*a26*a42*a55*a61 + + a16*a22*a43*a55*a61 + - a12*a26*a43*a55*a61 + - a13*a22*a46*a55*a61 + + a12*a23*a46*a55*a61 + + a15*a23*a42*a56*a61 + - a13*a25*a42*a56*a61 + - a15*a22*a43*a56*a61 + + a12*a25*a43*a56*a61 + + a13*a22*a45*a56*a61 + - a12*a23*a45*a56*a61 + + a16*a25*a43*a51*a62 + - a15*a26*a43*a51*a62 + - a16*a23*a45*a51*a62 + + a13*a26*a45*a51*a62 + + a15*a23*a46*a51*a62 + - a13*a25*a46*a51*a62 + - a16*a25*a41*a53*a62 + + a15*a26*a41*a53*a62 + + a16*a21*a45*a53*a62 + - a11*a26*a45*a53*a62 + - a15*a21*a46*a53*a62 + + a11*a25*a46*a53*a62 + + a16*a23*a41*a55*a62 + - a13*a26*a41*a55*a62 + - a16*a21*a43*a55*a62 + + a11*a26*a43*a55*a62 + + a13*a21*a46*a55*a62 + - a11*a23*a46*a55*a62 + - a15*a23*a41*a56*a62 + + a13*a25*a41*a56*a62 + + a15*a21*a43*a56*a62 + - a11*a25*a43*a56*a62 + - a13*a21*a45*a56*a62 + + a11*a23*a45*a56*a62 + - a16*a25*a42*a51*a63 + + a15*a26*a42*a51*a63 + + a16*a22*a45*a51*a63 + - a12*a26*a45*a51*a63 + - a15*a22*a46*a51*a63 + + a12*a25*a46*a51*a63 + + a16*a25*a41*a52*a63 + - a15*a26*a41*a52*a63 + - a16*a21*a45*a52*a63 + + a11*a26*a45*a52*a63 + + a15*a21*a46*a52*a63 + - a11*a25*a46*a52*a63 + - a16*a22*a41*a55*a63 + + a12*a26*a41*a55*a63 + + a16*a21*a42*a55*a63 + - a11*a26*a42*a55*a63 + - a12*a21*a46*a55*a63 + + a11*a22*a46*a55*a63 + + a15*a22*a41*a56*a63 + - a12*a25*a41*a56*a63 + - a15*a21*a42*a56*a63 + + a11*a25*a42*a56*a63 + + a12*a21*a45*a56*a63 + - a11*a22*a45*a56*a63 + + a16*a23*a42*a51*a65 + - a13*a26*a42*a51*a65 + - a16*a22*a43*a51*a65 + + a12*a26*a43*a51*a65 + + a13*a22*a46*a51*a65 + - a12*a23*a46*a51*a65 + - a16*a23*a41*a52*a65 + + a13*a26*a41*a52*a65 + + a16*a21*a43*a52*a65 + - a11*a26*a43*a52*a65 + - a13*a21*a46*a52*a65 + + a11*a23*a46*a52*a65 + + a16*a22*a41*a53*a65 + - a12*a26*a41*a53*a65 + - a16*a21*a42*a53*a65 + + a11*a26*a42*a53*a65 + + a12*a21*a46*a53*a65 + - a11*a22*a46*a53*a65 + - a13*a22*a41*a56*a65 + + a12*a23*a41*a56*a65 + + a13*a21*a42*a56*a65 + - a11*a23*a42*a56*a65 + - a12*a21*a43*a56*a65 + + a11*a22*a43*a56*a65 + - a15*a23*a42*a51*a66 + + a13*a25*a42*a51*a66 + + a15*a22*a43*a51*a66 + - a12*a25*a43*a51*a66 + - a13*a22*a45*a51*a66 + + a12*a23*a45*a51*a66 + + a15*a23*a41*a52*a66 + - a13*a25*a41*a52*a66 + - a15*a21*a43*a52*a66 + + a11*a25*a43*a52*a66 + + a13*a21*a45*a52*a66 + - a11*a23*a45*a52*a66 + - a15*a22*a41*a53*a66 + + a12*a25*a41*a53*a66 + + a15*a21*a42*a53*a66 + - a11*a25*a42*a53*a66 + - a12*a21*a45*a53*a66 + + a11*a22*a45*a53*a66 + + a13*a22*a41*a55*a66 + - a12*a23*a41*a55*a66 + - a13*a21*a42*a55*a66 + + a11*a23*a42*a55*a66 + + a12*a21*a43*a55*a66 + - a11*a22*a43*a55*a66; + cofactor[21] = a16*a25*a33*a52*a61 + - a15*a26*a33*a52*a61 + - a16*a23*a35*a52*a61 + + a13*a26*a35*a52*a61 + + a15*a23*a36*a52*a61 + - a13*a25*a36*a52*a61 + - a16*a25*a32*a53*a61 + + a15*a26*a32*a53*a61 + + a16*a22*a35*a53*a61 + - a12*a26*a35*a53*a61 + - a15*a22*a36*a53*a61 + + a12*a25*a36*a53*a61 + + a16*a23*a32*a55*a61 + - a13*a26*a32*a55*a61 + - a16*a22*a33*a55*a61 + + a12*a26*a33*a55*a61 + + a13*a22*a36*a55*a61 + - a12*a23*a36*a55*a61 + - a15*a23*a32*a56*a61 + + a13*a25*a32*a56*a61 + + a15*a22*a33*a56*a61 + - a12*a25*a33*a56*a61 + - a13*a22*a35*a56*a61 + + a12*a23*a35*a56*a61 + - a16*a25*a33*a51*a62 + + a15*a26*a33*a51*a62 + + a16*a23*a35*a51*a62 + - a13*a26*a35*a51*a62 + - a15*a23*a36*a51*a62 + + a13*a25*a36*a51*a62 + + a16*a25*a31*a53*a62 + - a15*a26*a31*a53*a62 + - a16*a21*a35*a53*a62 + + a11*a26*a35*a53*a62 + + a15*a21*a36*a53*a62 + - a11*a25*a36*a53*a62 + - a16*a23*a31*a55*a62 + + a13*a26*a31*a55*a62 + + a16*a21*a33*a55*a62 + - a11*a26*a33*a55*a62 + - a13*a21*a36*a55*a62 + + a11*a23*a36*a55*a62 + + a15*a23*a31*a56*a62 + - a13*a25*a31*a56*a62 + - a15*a21*a33*a56*a62 + + a11*a25*a33*a56*a62 + + a13*a21*a35*a56*a62 + - a11*a23*a35*a56*a62 + + a16*a25*a32*a51*a63 + - a15*a26*a32*a51*a63 + - a16*a22*a35*a51*a63 + + a12*a26*a35*a51*a63 + + a15*a22*a36*a51*a63 + - a12*a25*a36*a51*a63 + - a16*a25*a31*a52*a63 + + a15*a26*a31*a52*a63 + + a16*a21*a35*a52*a63 + - a11*a26*a35*a52*a63 + - a15*a21*a36*a52*a63 + + a11*a25*a36*a52*a63 + + a16*a22*a31*a55*a63 + - a12*a26*a31*a55*a63 + - a16*a21*a32*a55*a63 + + a11*a26*a32*a55*a63 + + a12*a21*a36*a55*a63 + - a11*a22*a36*a55*a63 + - a15*a22*a31*a56*a63 + + a12*a25*a31*a56*a63 + + a15*a21*a32*a56*a63 + - a11*a25*a32*a56*a63 + - a12*a21*a35*a56*a63 + + a11*a22*a35*a56*a63 + - a16*a23*a32*a51*a65 + + a13*a26*a32*a51*a65 + + a16*a22*a33*a51*a65 + - a12*a26*a33*a51*a65 + - a13*a22*a36*a51*a65 + + a12*a23*a36*a51*a65 + + a16*a23*a31*a52*a65 + - a13*a26*a31*a52*a65 + - a16*a21*a33*a52*a65 + + a11*a26*a33*a52*a65 + + a13*a21*a36*a52*a65 + - a11*a23*a36*a52*a65 + - a16*a22*a31*a53*a65 + + a12*a26*a31*a53*a65 + + a16*a21*a32*a53*a65 + - a11*a26*a32*a53*a65 + - a12*a21*a36*a53*a65 + + a11*a22*a36*a53*a65 + + a13*a22*a31*a56*a65 + - a12*a23*a31*a56*a65 + - a13*a21*a32*a56*a65 + + a11*a23*a32*a56*a65 + + a12*a21*a33*a56*a65 + - a11*a22*a33*a56*a65 + + a15*a23*a32*a51*a66 + - a13*a25*a32*a51*a66 + - a15*a22*a33*a51*a66 + + a12*a25*a33*a51*a66 + + a13*a22*a35*a51*a66 + - a12*a23*a35*a51*a66 + - a15*a23*a31*a52*a66 + + a13*a25*a31*a52*a66 + + a15*a21*a33*a52*a66 + - a11*a25*a33*a52*a66 + - a13*a21*a35*a52*a66 + + a11*a23*a35*a52*a66 + + a15*a22*a31*a53*a66 + - a12*a25*a31*a53*a66 + - a15*a21*a32*a53*a66 + + a11*a25*a32*a53*a66 + + a12*a21*a35*a53*a66 + - a11*a22*a35*a53*a66 + - a13*a22*a31*a55*a66 + + a12*a23*a31*a55*a66 + + a13*a21*a32*a55*a66 + - a11*a23*a32*a55*a66 + - a12*a21*a33*a55*a66 + + a11*a22*a33*a55*a66; + cofactor[22] = -a16*a25*a33*a42*a61 + + a15*a26*a33*a42*a61 + + a16*a23*a35*a42*a61 + - a13*a26*a35*a42*a61 + - a15*a23*a36*a42*a61 + + a13*a25*a36*a42*a61 + + a16*a25*a32*a43*a61 + - a15*a26*a32*a43*a61 + - a16*a22*a35*a43*a61 + + a12*a26*a35*a43*a61 + + a15*a22*a36*a43*a61 + - a12*a25*a36*a43*a61 + - a16*a23*a32*a45*a61 + + a13*a26*a32*a45*a61 + + a16*a22*a33*a45*a61 + - a12*a26*a33*a45*a61 + - a13*a22*a36*a45*a61 + + a12*a23*a36*a45*a61 + + a15*a23*a32*a46*a61 + - a13*a25*a32*a46*a61 + - a15*a22*a33*a46*a61 + + a12*a25*a33*a46*a61 + + a13*a22*a35*a46*a61 + - a12*a23*a35*a46*a61 + + a16*a25*a33*a41*a62 + - a15*a26*a33*a41*a62 + - a16*a23*a35*a41*a62 + + a13*a26*a35*a41*a62 + + a15*a23*a36*a41*a62 + - a13*a25*a36*a41*a62 + - a16*a25*a31*a43*a62 + + a15*a26*a31*a43*a62 + + a16*a21*a35*a43*a62 + - a11*a26*a35*a43*a62 + - a15*a21*a36*a43*a62 + + a11*a25*a36*a43*a62 + + a16*a23*a31*a45*a62 + - a13*a26*a31*a45*a62 + - a16*a21*a33*a45*a62 + + a11*a26*a33*a45*a62 + + a13*a21*a36*a45*a62 + - a11*a23*a36*a45*a62 + - a15*a23*a31*a46*a62 + + a13*a25*a31*a46*a62 + + a15*a21*a33*a46*a62 + - a11*a25*a33*a46*a62 + - a13*a21*a35*a46*a62 + + a11*a23*a35*a46*a62 + - a16*a25*a32*a41*a63 + + a15*a26*a32*a41*a63 + + a16*a22*a35*a41*a63 + - a12*a26*a35*a41*a63 + - a15*a22*a36*a41*a63 + + a12*a25*a36*a41*a63 + + a16*a25*a31*a42*a63 + - a15*a26*a31*a42*a63 + - a16*a21*a35*a42*a63 + + a11*a26*a35*a42*a63 + + a15*a21*a36*a42*a63 + - a11*a25*a36*a42*a63 + - a16*a22*a31*a45*a63 + + a12*a26*a31*a45*a63 + + a16*a21*a32*a45*a63 + - a11*a26*a32*a45*a63 + - a12*a21*a36*a45*a63 + + a11*a22*a36*a45*a63 + + a15*a22*a31*a46*a63 + - a12*a25*a31*a46*a63 + - a15*a21*a32*a46*a63 + + a11*a25*a32*a46*a63 + + a12*a21*a35*a46*a63 + - a11*a22*a35*a46*a63 + + a16*a23*a32*a41*a65 + - a13*a26*a32*a41*a65 + - a16*a22*a33*a41*a65 + + a12*a26*a33*a41*a65 + + a13*a22*a36*a41*a65 + - a12*a23*a36*a41*a65 + - a16*a23*a31*a42*a65 + + a13*a26*a31*a42*a65 + + a16*a21*a33*a42*a65 + - a11*a26*a33*a42*a65 + - a13*a21*a36*a42*a65 + + a11*a23*a36*a42*a65 + + a16*a22*a31*a43*a65 + - a12*a26*a31*a43*a65 + - a16*a21*a32*a43*a65 + + a11*a26*a32*a43*a65 + + a12*a21*a36*a43*a65 + - a11*a22*a36*a43*a65 + - a13*a22*a31*a46*a65 + + a12*a23*a31*a46*a65 + + a13*a21*a32*a46*a65 + - a11*a23*a32*a46*a65 + - a12*a21*a33*a46*a65 + + a11*a22*a33*a46*a65 + - a15*a23*a32*a41*a66 + + a13*a25*a32*a41*a66 + + a15*a22*a33*a41*a66 + - a12*a25*a33*a41*a66 + - a13*a22*a35*a41*a66 + + a12*a23*a35*a41*a66 + + a15*a23*a31*a42*a66 + - a13*a25*a31*a42*a66 + - a15*a21*a33*a42*a66 + + a11*a25*a33*a42*a66 + + a13*a21*a35*a42*a66 + - a11*a23*a35*a42*a66 + - a15*a22*a31*a43*a66 + + a12*a25*a31*a43*a66 + + a15*a21*a32*a43*a66 + - a11*a25*a32*a43*a66 + - a12*a21*a35*a43*a66 + + a11*a22*a35*a43*a66 + + a13*a22*a31*a45*a66 + - a12*a23*a31*a45*a66 + - a13*a21*a32*a45*a66 + + a11*a23*a32*a45*a66 + + a12*a21*a33*a45*a66 + - a11*a22*a33*a45*a66; + cofactor[23] = a16*a25*a33*a42*a51 + - a15*a26*a33*a42*a51 + - a16*a23*a35*a42*a51 + + a13*a26*a35*a42*a51 + + a15*a23*a36*a42*a51 + - a13*a25*a36*a42*a51 + - a16*a25*a32*a43*a51 + + a15*a26*a32*a43*a51 + + a16*a22*a35*a43*a51 + - a12*a26*a35*a43*a51 + - a15*a22*a36*a43*a51 + + a12*a25*a36*a43*a51 + + a16*a23*a32*a45*a51 + - a13*a26*a32*a45*a51 + - a16*a22*a33*a45*a51 + + a12*a26*a33*a45*a51 + + a13*a22*a36*a45*a51 + - a12*a23*a36*a45*a51 + - a15*a23*a32*a46*a51 + + a13*a25*a32*a46*a51 + + a15*a22*a33*a46*a51 + - a12*a25*a33*a46*a51 + - a13*a22*a35*a46*a51 + + a12*a23*a35*a46*a51 + - a16*a25*a33*a41*a52 + + a15*a26*a33*a41*a52 + + a16*a23*a35*a41*a52 + - a13*a26*a35*a41*a52 + - a15*a23*a36*a41*a52 + + a13*a25*a36*a41*a52 + + a16*a25*a31*a43*a52 + - a15*a26*a31*a43*a52 + - a16*a21*a35*a43*a52 + + a11*a26*a35*a43*a52 + + a15*a21*a36*a43*a52 + - a11*a25*a36*a43*a52 + - a16*a23*a31*a45*a52 + + a13*a26*a31*a45*a52 + + a16*a21*a33*a45*a52 + - a11*a26*a33*a45*a52 + - a13*a21*a36*a45*a52 + + a11*a23*a36*a45*a52 + + a15*a23*a31*a46*a52 + - a13*a25*a31*a46*a52 + - a15*a21*a33*a46*a52 + + a11*a25*a33*a46*a52 + + a13*a21*a35*a46*a52 + - a11*a23*a35*a46*a52 + + a16*a25*a32*a41*a53 + - a15*a26*a32*a41*a53 + - a16*a22*a35*a41*a53 + + a12*a26*a35*a41*a53 + + a15*a22*a36*a41*a53 + - a12*a25*a36*a41*a53 + - a16*a25*a31*a42*a53 + + a15*a26*a31*a42*a53 + + a16*a21*a35*a42*a53 + - a11*a26*a35*a42*a53 + - a15*a21*a36*a42*a53 + + a11*a25*a36*a42*a53 + + a16*a22*a31*a45*a53 + - a12*a26*a31*a45*a53 + - a16*a21*a32*a45*a53 + + a11*a26*a32*a45*a53 + + a12*a21*a36*a45*a53 + - a11*a22*a36*a45*a53 + - a15*a22*a31*a46*a53 + + a12*a25*a31*a46*a53 + + a15*a21*a32*a46*a53 + - a11*a25*a32*a46*a53 + - a12*a21*a35*a46*a53 + + a11*a22*a35*a46*a53 + - a16*a23*a32*a41*a55 + + a13*a26*a32*a41*a55 + + a16*a22*a33*a41*a55 + - a12*a26*a33*a41*a55 + - a13*a22*a36*a41*a55 + + a12*a23*a36*a41*a55 + + a16*a23*a31*a42*a55 + - a13*a26*a31*a42*a55 + - a16*a21*a33*a42*a55 + + a11*a26*a33*a42*a55 + + a13*a21*a36*a42*a55 + - a11*a23*a36*a42*a55 + - a16*a22*a31*a43*a55 + + a12*a26*a31*a43*a55 + + a16*a21*a32*a43*a55 + - a11*a26*a32*a43*a55 + - a12*a21*a36*a43*a55 + + a11*a22*a36*a43*a55 + + a13*a22*a31*a46*a55 + - a12*a23*a31*a46*a55 + - a13*a21*a32*a46*a55 + + a11*a23*a32*a46*a55 + + a12*a21*a33*a46*a55 + - a11*a22*a33*a46*a55 + + a15*a23*a32*a41*a56 + - a13*a25*a32*a41*a56 + - a15*a22*a33*a41*a56 + + a12*a25*a33*a41*a56 + + a13*a22*a35*a41*a56 + - a12*a23*a35*a41*a56 + - a15*a23*a31*a42*a56 + + a13*a25*a31*a42*a56 + + a15*a21*a33*a42*a56 + - a11*a25*a33*a42*a56 + - a13*a21*a35*a42*a56 + + a11*a23*a35*a42*a56 + + a15*a22*a31*a43*a56 + - a12*a25*a31*a43*a56 + - a15*a21*a32*a43*a56 + + a11*a25*a32*a43*a56 + + a12*a21*a35*a43*a56 + - a11*a22*a35*a43*a56 + - a13*a22*a31*a45*a56 + + a12*a23*a31*a45*a56 + + a13*a21*a32*a45*a56 + - a11*a23*a32*a45*a56 + - a12*a21*a33*a45*a56 + + a11*a22*a33*a45*a56; + cofactor[24] = a26*a34*a43*a52*a61 + - a24*a36*a43*a52*a61 + - a26*a33*a44*a52*a61 + + a23*a36*a44*a52*a61 + + a24*a33*a46*a52*a61 + - a23*a34*a46*a52*a61 + - a26*a34*a42*a53*a61 + + a24*a36*a42*a53*a61 + + a26*a32*a44*a53*a61 + - a22*a36*a44*a53*a61 + - a24*a32*a46*a53*a61 + + a22*a34*a46*a53*a61 + + a26*a33*a42*a54*a61 + - a23*a36*a42*a54*a61 + - a26*a32*a43*a54*a61 + + a22*a36*a43*a54*a61 + + a23*a32*a46*a54*a61 + - a22*a33*a46*a54*a61 + - a24*a33*a42*a56*a61 + + a23*a34*a42*a56*a61 + + a24*a32*a43*a56*a61 + - a22*a34*a43*a56*a61 + - a23*a32*a44*a56*a61 + + a22*a33*a44*a56*a61 + - a26*a34*a43*a51*a62 + + a24*a36*a43*a51*a62 + + a26*a33*a44*a51*a62 + - a23*a36*a44*a51*a62 + - a24*a33*a46*a51*a62 + + a23*a34*a46*a51*a62 + + a26*a34*a41*a53*a62 + - a24*a36*a41*a53*a62 + - a26*a31*a44*a53*a62 + + a21*a36*a44*a53*a62 + + a24*a31*a46*a53*a62 + - a21*a34*a46*a53*a62 + - a26*a33*a41*a54*a62 + + a23*a36*a41*a54*a62 + + a26*a31*a43*a54*a62 + - a21*a36*a43*a54*a62 + - a23*a31*a46*a54*a62 + + a21*a33*a46*a54*a62 + + a24*a33*a41*a56*a62 + - a23*a34*a41*a56*a62 + - a24*a31*a43*a56*a62 + + a21*a34*a43*a56*a62 + + a23*a31*a44*a56*a62 + - a21*a33*a44*a56*a62 + + a26*a34*a42*a51*a63 + - a24*a36*a42*a51*a63 + - a26*a32*a44*a51*a63 + + a22*a36*a44*a51*a63 + + a24*a32*a46*a51*a63 + - a22*a34*a46*a51*a63 + - a26*a34*a41*a52*a63 + + a24*a36*a41*a52*a63 + + a26*a31*a44*a52*a63 + - a21*a36*a44*a52*a63 + - a24*a31*a46*a52*a63 + + a21*a34*a46*a52*a63 + + a26*a32*a41*a54*a63 + - a22*a36*a41*a54*a63 + - a26*a31*a42*a54*a63 + + a21*a36*a42*a54*a63 + + a22*a31*a46*a54*a63 + - a21*a32*a46*a54*a63 + - a24*a32*a41*a56*a63 + + a22*a34*a41*a56*a63 + + a24*a31*a42*a56*a63 + - a21*a34*a42*a56*a63 + - a22*a31*a44*a56*a63 + + a21*a32*a44*a56*a63 + - a26*a33*a42*a51*a64 + + a23*a36*a42*a51*a64 + + a26*a32*a43*a51*a64 + - a22*a36*a43*a51*a64 + - a23*a32*a46*a51*a64 + + a22*a33*a46*a51*a64 + + a26*a33*a41*a52*a64 + - a23*a36*a41*a52*a64 + - a26*a31*a43*a52*a64 + + a21*a36*a43*a52*a64 + + a23*a31*a46*a52*a64 + - a21*a33*a46*a52*a64 + - a26*a32*a41*a53*a64 + + a22*a36*a41*a53*a64 + + a26*a31*a42*a53*a64 + - a21*a36*a42*a53*a64 + - a22*a31*a46*a53*a64 + + a21*a32*a46*a53*a64 + + a23*a32*a41*a56*a64 + - a22*a33*a41*a56*a64 + - a23*a31*a42*a56*a64 + + a21*a33*a42*a56*a64 + + a22*a31*a43*a56*a64 + - a21*a32*a43*a56*a64 + + a24*a33*a42*a51*a66 + - a23*a34*a42*a51*a66 + - a24*a32*a43*a51*a66 + + a22*a34*a43*a51*a66 + + a23*a32*a44*a51*a66 + - a22*a33*a44*a51*a66 + - a24*a33*a41*a52*a66 + + a23*a34*a41*a52*a66 + + a24*a31*a43*a52*a66 + - a21*a34*a43*a52*a66 + - a23*a31*a44*a52*a66 + + a21*a33*a44*a52*a66 + + a24*a32*a41*a53*a66 + - a22*a34*a41*a53*a66 + - a24*a31*a42*a53*a66 + + a21*a34*a42*a53*a66 + + a22*a31*a44*a53*a66 + - a21*a32*a44*a53*a66 + - a23*a32*a41*a54*a66 + + a22*a33*a41*a54*a66 + + a23*a31*a42*a54*a66 + - a21*a33*a42*a54*a66 + - a22*a31*a43*a54*a66 + + a21*a32*a43*a54*a66; + cofactor[25] = -a16*a34*a43*a52*a61 + + a14*a36*a43*a52*a61 + + a16*a33*a44*a52*a61 + - a13*a36*a44*a52*a61 + - a14*a33*a46*a52*a61 + + a13*a34*a46*a52*a61 + + a16*a34*a42*a53*a61 + - a14*a36*a42*a53*a61 + - a16*a32*a44*a53*a61 + + a12*a36*a44*a53*a61 + + a14*a32*a46*a53*a61 + - a12*a34*a46*a53*a61 + - a16*a33*a42*a54*a61 + + a13*a36*a42*a54*a61 + + a16*a32*a43*a54*a61 + - a12*a36*a43*a54*a61 + - a13*a32*a46*a54*a61 + + a12*a33*a46*a54*a61 + + a14*a33*a42*a56*a61 + - a13*a34*a42*a56*a61 + - a14*a32*a43*a56*a61 + + a12*a34*a43*a56*a61 + + a13*a32*a44*a56*a61 + - a12*a33*a44*a56*a61 + + a16*a34*a43*a51*a62 + - a14*a36*a43*a51*a62 + - a16*a33*a44*a51*a62 + + a13*a36*a44*a51*a62 + + a14*a33*a46*a51*a62 + - a13*a34*a46*a51*a62 + - a16*a34*a41*a53*a62 + + a14*a36*a41*a53*a62 + + a16*a31*a44*a53*a62 + - a11*a36*a44*a53*a62 + - a14*a31*a46*a53*a62 + + a11*a34*a46*a53*a62 + + a16*a33*a41*a54*a62 + - a13*a36*a41*a54*a62 + - a16*a31*a43*a54*a62 + + a11*a36*a43*a54*a62 + + a13*a31*a46*a54*a62 + - a11*a33*a46*a54*a62 + - a14*a33*a41*a56*a62 + + a13*a34*a41*a56*a62 + + a14*a31*a43*a56*a62 + - a11*a34*a43*a56*a62 + - a13*a31*a44*a56*a62 + + a11*a33*a44*a56*a62 + - a16*a34*a42*a51*a63 + + a14*a36*a42*a51*a63 + + a16*a32*a44*a51*a63 + - a12*a36*a44*a51*a63 + - a14*a32*a46*a51*a63 + + a12*a34*a46*a51*a63 + + a16*a34*a41*a52*a63 + - a14*a36*a41*a52*a63 + - a16*a31*a44*a52*a63 + + a11*a36*a44*a52*a63 + + a14*a31*a46*a52*a63 + - a11*a34*a46*a52*a63 + - a16*a32*a41*a54*a63 + + a12*a36*a41*a54*a63 + + a16*a31*a42*a54*a63 + - a11*a36*a42*a54*a63 + - a12*a31*a46*a54*a63 + + a11*a32*a46*a54*a63 + + a14*a32*a41*a56*a63 + - a12*a34*a41*a56*a63 + - a14*a31*a42*a56*a63 + + a11*a34*a42*a56*a63 + + a12*a31*a44*a56*a63 + - a11*a32*a44*a56*a63 + + a16*a33*a42*a51*a64 + - a13*a36*a42*a51*a64 + - a16*a32*a43*a51*a64 + + a12*a36*a43*a51*a64 + + a13*a32*a46*a51*a64 + - a12*a33*a46*a51*a64 + - a16*a33*a41*a52*a64 + + a13*a36*a41*a52*a64 + + a16*a31*a43*a52*a64 + - a11*a36*a43*a52*a64 + - a13*a31*a46*a52*a64 + + a11*a33*a46*a52*a64 + + a16*a32*a41*a53*a64 + - a12*a36*a41*a53*a64 + - a16*a31*a42*a53*a64 + + a11*a36*a42*a53*a64 + + a12*a31*a46*a53*a64 + - a11*a32*a46*a53*a64 + - a13*a32*a41*a56*a64 + + a12*a33*a41*a56*a64 + + a13*a31*a42*a56*a64 + - a11*a33*a42*a56*a64 + - a12*a31*a43*a56*a64 + + a11*a32*a43*a56*a64 + - a14*a33*a42*a51*a66 + + a13*a34*a42*a51*a66 + + a14*a32*a43*a51*a66 + - a12*a34*a43*a51*a66 + - a13*a32*a44*a51*a66 + + a12*a33*a44*a51*a66 + + a14*a33*a41*a52*a66 + - a13*a34*a41*a52*a66 + - a14*a31*a43*a52*a66 + + a11*a34*a43*a52*a66 + + a13*a31*a44*a52*a66 + - a11*a33*a44*a52*a66 + - a14*a32*a41*a53*a66 + + a12*a34*a41*a53*a66 + + a14*a31*a42*a53*a66 + - a11*a34*a42*a53*a66 + - a12*a31*a44*a53*a66 + + a11*a32*a44*a53*a66 + + a13*a32*a41*a54*a66 + - a12*a33*a41*a54*a66 + - a13*a31*a42*a54*a66 + + a11*a33*a42*a54*a66 + + a12*a31*a43*a54*a66 + - a11*a32*a43*a54*a66; + cofactor[26] = a16*a24*a43*a52*a61 + - a14*a26*a43*a52*a61 + - a16*a23*a44*a52*a61 + + a13*a26*a44*a52*a61 + + a14*a23*a46*a52*a61 + - a13*a24*a46*a52*a61 + - a16*a24*a42*a53*a61 + + a14*a26*a42*a53*a61 + + a16*a22*a44*a53*a61 + - a12*a26*a44*a53*a61 + - a14*a22*a46*a53*a61 + + a12*a24*a46*a53*a61 + + a16*a23*a42*a54*a61 + - a13*a26*a42*a54*a61 + - a16*a22*a43*a54*a61 + + a12*a26*a43*a54*a61 + + a13*a22*a46*a54*a61 + - a12*a23*a46*a54*a61 + - a14*a23*a42*a56*a61 + + a13*a24*a42*a56*a61 + + a14*a22*a43*a56*a61 + - a12*a24*a43*a56*a61 + - a13*a22*a44*a56*a61 + + a12*a23*a44*a56*a61 + - a16*a24*a43*a51*a62 + + a14*a26*a43*a51*a62 + + a16*a23*a44*a51*a62 + - a13*a26*a44*a51*a62 + - a14*a23*a46*a51*a62 + + a13*a24*a46*a51*a62 + + a16*a24*a41*a53*a62 + - a14*a26*a41*a53*a62 + - a16*a21*a44*a53*a62 + + a11*a26*a44*a53*a62 + + a14*a21*a46*a53*a62 + - a11*a24*a46*a53*a62 + - a16*a23*a41*a54*a62 + + a13*a26*a41*a54*a62 + + a16*a21*a43*a54*a62 + - a11*a26*a43*a54*a62 + - a13*a21*a46*a54*a62 + + a11*a23*a46*a54*a62 + + a14*a23*a41*a56*a62 + - a13*a24*a41*a56*a62 + - a14*a21*a43*a56*a62 + + a11*a24*a43*a56*a62 + + a13*a21*a44*a56*a62 + - a11*a23*a44*a56*a62 + + a16*a24*a42*a51*a63 + - a14*a26*a42*a51*a63 + - a16*a22*a44*a51*a63 + + a12*a26*a44*a51*a63 + + a14*a22*a46*a51*a63 + - a12*a24*a46*a51*a63 + - a16*a24*a41*a52*a63 + + a14*a26*a41*a52*a63 + + a16*a21*a44*a52*a63 + - a11*a26*a44*a52*a63 + - a14*a21*a46*a52*a63 + + a11*a24*a46*a52*a63 + + a16*a22*a41*a54*a63 + - a12*a26*a41*a54*a63 + - a16*a21*a42*a54*a63 + + a11*a26*a42*a54*a63 + + a12*a21*a46*a54*a63 + - a11*a22*a46*a54*a63 + - a14*a22*a41*a56*a63 + + a12*a24*a41*a56*a63 + + a14*a21*a42*a56*a63 + - a11*a24*a42*a56*a63 + - a12*a21*a44*a56*a63 + + a11*a22*a44*a56*a63 + - a16*a23*a42*a51*a64 + + a13*a26*a42*a51*a64 + + a16*a22*a43*a51*a64 + - a12*a26*a43*a51*a64 + - a13*a22*a46*a51*a64 + + a12*a23*a46*a51*a64 + + a16*a23*a41*a52*a64 + - a13*a26*a41*a52*a64 + - a16*a21*a43*a52*a64 + + a11*a26*a43*a52*a64 + + a13*a21*a46*a52*a64 + - a11*a23*a46*a52*a64 + - a16*a22*a41*a53*a64 + + a12*a26*a41*a53*a64 + + a16*a21*a42*a53*a64 + - a11*a26*a42*a53*a64 + - a12*a21*a46*a53*a64 + + a11*a22*a46*a53*a64 + + a13*a22*a41*a56*a64 + - a12*a23*a41*a56*a64 + - a13*a21*a42*a56*a64 + + a11*a23*a42*a56*a64 + + a12*a21*a43*a56*a64 + - a11*a22*a43*a56*a64 + + a14*a23*a42*a51*a66 + - a13*a24*a42*a51*a66 + - a14*a22*a43*a51*a66 + + a12*a24*a43*a51*a66 + + a13*a22*a44*a51*a66 + - a12*a23*a44*a51*a66 + - a14*a23*a41*a52*a66 + + a13*a24*a41*a52*a66 + + a14*a21*a43*a52*a66 + - a11*a24*a43*a52*a66 + - a13*a21*a44*a52*a66 + + a11*a23*a44*a52*a66 + + a14*a22*a41*a53*a66 + - a12*a24*a41*a53*a66 + - a14*a21*a42*a53*a66 + + a11*a24*a42*a53*a66 + + a12*a21*a44*a53*a66 + - a11*a22*a44*a53*a66 + - a13*a22*a41*a54*a66 + + a12*a23*a41*a54*a66 + + a13*a21*a42*a54*a66 + - a11*a23*a42*a54*a66 + - a12*a21*a43*a54*a66 + + a11*a22*a43*a54*a66; + cofactor[27] = -a16*a24*a33*a52*a61 + + a14*a26*a33*a52*a61 + + a16*a23*a34*a52*a61 + - a13*a26*a34*a52*a61 + - a14*a23*a36*a52*a61 + + a13*a24*a36*a52*a61 + + a16*a24*a32*a53*a61 + - a14*a26*a32*a53*a61 + - a16*a22*a34*a53*a61 + + a12*a26*a34*a53*a61 + + a14*a22*a36*a53*a61 + - a12*a24*a36*a53*a61 + - a16*a23*a32*a54*a61 + + a13*a26*a32*a54*a61 + + a16*a22*a33*a54*a61 + - a12*a26*a33*a54*a61 + - a13*a22*a36*a54*a61 + + a12*a23*a36*a54*a61 + + a14*a23*a32*a56*a61 + - a13*a24*a32*a56*a61 + - a14*a22*a33*a56*a61 + + a12*a24*a33*a56*a61 + + a13*a22*a34*a56*a61 + - a12*a23*a34*a56*a61 + + a16*a24*a33*a51*a62 + - a14*a26*a33*a51*a62 + - a16*a23*a34*a51*a62 + + a13*a26*a34*a51*a62 + + a14*a23*a36*a51*a62 + - a13*a24*a36*a51*a62 + - a16*a24*a31*a53*a62 + + a14*a26*a31*a53*a62 + + a16*a21*a34*a53*a62 + - a11*a26*a34*a53*a62 + - a14*a21*a36*a53*a62 + + a11*a24*a36*a53*a62 + + a16*a23*a31*a54*a62 + - a13*a26*a31*a54*a62 + - a16*a21*a33*a54*a62 + + a11*a26*a33*a54*a62 + + a13*a21*a36*a54*a62 + - a11*a23*a36*a54*a62 + - a14*a23*a31*a56*a62 + + a13*a24*a31*a56*a62 + + a14*a21*a33*a56*a62 + - a11*a24*a33*a56*a62 + - a13*a21*a34*a56*a62 + + a11*a23*a34*a56*a62 + - a16*a24*a32*a51*a63 + + a14*a26*a32*a51*a63 + + a16*a22*a34*a51*a63 + - a12*a26*a34*a51*a63 + - a14*a22*a36*a51*a63 + + a12*a24*a36*a51*a63 + + a16*a24*a31*a52*a63 + - a14*a26*a31*a52*a63 + - a16*a21*a34*a52*a63 + + a11*a26*a34*a52*a63 + + a14*a21*a36*a52*a63 + - a11*a24*a36*a52*a63 + - a16*a22*a31*a54*a63 + + a12*a26*a31*a54*a63 + + a16*a21*a32*a54*a63 + - a11*a26*a32*a54*a63 + - a12*a21*a36*a54*a63 + + a11*a22*a36*a54*a63 + + a14*a22*a31*a56*a63 + - a12*a24*a31*a56*a63 + - a14*a21*a32*a56*a63 + + a11*a24*a32*a56*a63 + + a12*a21*a34*a56*a63 + - a11*a22*a34*a56*a63 + + a16*a23*a32*a51*a64 + - a13*a26*a32*a51*a64 + - a16*a22*a33*a51*a64 + + a12*a26*a33*a51*a64 + + a13*a22*a36*a51*a64 + - a12*a23*a36*a51*a64 + - a16*a23*a31*a52*a64 + + a13*a26*a31*a52*a64 + + a16*a21*a33*a52*a64 + - a11*a26*a33*a52*a64 + - a13*a21*a36*a52*a64 + + a11*a23*a36*a52*a64 + + a16*a22*a31*a53*a64 + - a12*a26*a31*a53*a64 + - a16*a21*a32*a53*a64 + + a11*a26*a32*a53*a64 + + a12*a21*a36*a53*a64 + - a11*a22*a36*a53*a64 + - a13*a22*a31*a56*a64 + + a12*a23*a31*a56*a64 + + a13*a21*a32*a56*a64 + - a11*a23*a32*a56*a64 + - a12*a21*a33*a56*a64 + + a11*a22*a33*a56*a64 + - a14*a23*a32*a51*a66 + + a13*a24*a32*a51*a66 + + a14*a22*a33*a51*a66 + - a12*a24*a33*a51*a66 + - a13*a22*a34*a51*a66 + + a12*a23*a34*a51*a66 + + a14*a23*a31*a52*a66 + - a13*a24*a31*a52*a66 + - a14*a21*a33*a52*a66 + + a11*a24*a33*a52*a66 + + a13*a21*a34*a52*a66 + - a11*a23*a34*a52*a66 + - a14*a22*a31*a53*a66 + + a12*a24*a31*a53*a66 + + a14*a21*a32*a53*a66 + - a11*a24*a32*a53*a66 + - a12*a21*a34*a53*a66 + + a11*a22*a34*a53*a66 + + a13*a22*a31*a54*a66 + - a12*a23*a31*a54*a66 + - a13*a21*a32*a54*a66 + + a11*a23*a32*a54*a66 + + a12*a21*a33*a54*a66 + - a11*a22*a33*a54*a66; + cofactor[28] = a16*a24*a33*a42*a61 + - a14*a26*a33*a42*a61 + - a16*a23*a34*a42*a61 + + a13*a26*a34*a42*a61 + + a14*a23*a36*a42*a61 + - a13*a24*a36*a42*a61 + - a16*a24*a32*a43*a61 + + a14*a26*a32*a43*a61 + + a16*a22*a34*a43*a61 + - a12*a26*a34*a43*a61 + - a14*a22*a36*a43*a61 + + a12*a24*a36*a43*a61 + + a16*a23*a32*a44*a61 + - a13*a26*a32*a44*a61 + - a16*a22*a33*a44*a61 + + a12*a26*a33*a44*a61 + + a13*a22*a36*a44*a61 + - a12*a23*a36*a44*a61 + - a14*a23*a32*a46*a61 + + a13*a24*a32*a46*a61 + + a14*a22*a33*a46*a61 + - a12*a24*a33*a46*a61 + - a13*a22*a34*a46*a61 + + a12*a23*a34*a46*a61 + - a16*a24*a33*a41*a62 + + a14*a26*a33*a41*a62 + + a16*a23*a34*a41*a62 + - a13*a26*a34*a41*a62 + - a14*a23*a36*a41*a62 + + a13*a24*a36*a41*a62 + + a16*a24*a31*a43*a62 + - a14*a26*a31*a43*a62 + - a16*a21*a34*a43*a62 + + a11*a26*a34*a43*a62 + + a14*a21*a36*a43*a62 + - a11*a24*a36*a43*a62 + - a16*a23*a31*a44*a62 + + a13*a26*a31*a44*a62 + + a16*a21*a33*a44*a62 + - a11*a26*a33*a44*a62 + - a13*a21*a36*a44*a62 + + a11*a23*a36*a44*a62 + + a14*a23*a31*a46*a62 + - a13*a24*a31*a46*a62 + - a14*a21*a33*a46*a62 + + a11*a24*a33*a46*a62 + + a13*a21*a34*a46*a62 + - a11*a23*a34*a46*a62 + + a16*a24*a32*a41*a63 + - a14*a26*a32*a41*a63 + - a16*a22*a34*a41*a63 + + a12*a26*a34*a41*a63 + + a14*a22*a36*a41*a63 + - a12*a24*a36*a41*a63 + - a16*a24*a31*a42*a63 + + a14*a26*a31*a42*a63 + + a16*a21*a34*a42*a63 + - a11*a26*a34*a42*a63 + - a14*a21*a36*a42*a63 + + a11*a24*a36*a42*a63 + + a16*a22*a31*a44*a63 + - a12*a26*a31*a44*a63 + - a16*a21*a32*a44*a63 + + a11*a26*a32*a44*a63 + + a12*a21*a36*a44*a63 + - a11*a22*a36*a44*a63 + - a14*a22*a31*a46*a63 + + a12*a24*a31*a46*a63 + + a14*a21*a32*a46*a63 + - a11*a24*a32*a46*a63 + - a12*a21*a34*a46*a63 + + a11*a22*a34*a46*a63 + - a16*a23*a32*a41*a64 + + a13*a26*a32*a41*a64 + + a16*a22*a33*a41*a64 + - a12*a26*a33*a41*a64 + - a13*a22*a36*a41*a64 + + a12*a23*a36*a41*a64 + + a16*a23*a31*a42*a64 + - a13*a26*a31*a42*a64 + - a16*a21*a33*a42*a64 + + a11*a26*a33*a42*a64 + + a13*a21*a36*a42*a64 + - a11*a23*a36*a42*a64 + - a16*a22*a31*a43*a64 + + a12*a26*a31*a43*a64 + + a16*a21*a32*a43*a64 + - a11*a26*a32*a43*a64 + - a12*a21*a36*a43*a64 + + a11*a22*a36*a43*a64 + + a13*a22*a31*a46*a64 + - a12*a23*a31*a46*a64 + - a13*a21*a32*a46*a64 + + a11*a23*a32*a46*a64 + + a12*a21*a33*a46*a64 + - a11*a22*a33*a46*a64 + + a14*a23*a32*a41*a66 + - a13*a24*a32*a41*a66 + - a14*a22*a33*a41*a66 + + a12*a24*a33*a41*a66 + + a13*a22*a34*a41*a66 + - a12*a23*a34*a41*a66 + - a14*a23*a31*a42*a66 + + a13*a24*a31*a42*a66 + + a14*a21*a33*a42*a66 + - a11*a24*a33*a42*a66 + - a13*a21*a34*a42*a66 + + a11*a23*a34*a42*a66 + + a14*a22*a31*a43*a66 + - a12*a24*a31*a43*a66 + - a14*a21*a32*a43*a66 + + a11*a24*a32*a43*a66 + + a12*a21*a34*a43*a66 + - a11*a22*a34*a43*a66 + - a13*a22*a31*a44*a66 + + a12*a23*a31*a44*a66 + + a13*a21*a32*a44*a66 + - a11*a23*a32*a44*a66 + - a12*a21*a33*a44*a66 + + a11*a22*a33*a44*a66; + cofactor[29] = -a16*a24*a33*a42*a51 + + a14*a26*a33*a42*a51 + + a16*a23*a34*a42*a51 + - a13*a26*a34*a42*a51 + - a14*a23*a36*a42*a51 + + a13*a24*a36*a42*a51 + + a16*a24*a32*a43*a51 + - a14*a26*a32*a43*a51 + - a16*a22*a34*a43*a51 + + a12*a26*a34*a43*a51 + + a14*a22*a36*a43*a51 + - a12*a24*a36*a43*a51 + - a16*a23*a32*a44*a51 + + a13*a26*a32*a44*a51 + + a16*a22*a33*a44*a51 + - a12*a26*a33*a44*a51 + - a13*a22*a36*a44*a51 + + a12*a23*a36*a44*a51 + + a14*a23*a32*a46*a51 + - a13*a24*a32*a46*a51 + - a14*a22*a33*a46*a51 + + a12*a24*a33*a46*a51 + + a13*a22*a34*a46*a51 + - a12*a23*a34*a46*a51 + + a16*a24*a33*a41*a52 + - a14*a26*a33*a41*a52 + - a16*a23*a34*a41*a52 + + a13*a26*a34*a41*a52 + + a14*a23*a36*a41*a52 + - a13*a24*a36*a41*a52 + - a16*a24*a31*a43*a52 + + a14*a26*a31*a43*a52 + + a16*a21*a34*a43*a52 + - a11*a26*a34*a43*a52 + - a14*a21*a36*a43*a52 + + a11*a24*a36*a43*a52 + + a16*a23*a31*a44*a52 + - a13*a26*a31*a44*a52 + - a16*a21*a33*a44*a52 + + a11*a26*a33*a44*a52 + + a13*a21*a36*a44*a52 + - a11*a23*a36*a44*a52 + - a14*a23*a31*a46*a52 + + a13*a24*a31*a46*a52 + + a14*a21*a33*a46*a52 + - a11*a24*a33*a46*a52 + - a13*a21*a34*a46*a52 + + a11*a23*a34*a46*a52 + - a16*a24*a32*a41*a53 + + a14*a26*a32*a41*a53 + + a16*a22*a34*a41*a53 + - a12*a26*a34*a41*a53 + - a14*a22*a36*a41*a53 + + a12*a24*a36*a41*a53 + + a16*a24*a31*a42*a53 + - a14*a26*a31*a42*a53 + - a16*a21*a34*a42*a53 + + a11*a26*a34*a42*a53 + + a14*a21*a36*a42*a53 + - a11*a24*a36*a42*a53 + - a16*a22*a31*a44*a53 + + a12*a26*a31*a44*a53 + + a16*a21*a32*a44*a53 + - a11*a26*a32*a44*a53 + - a12*a21*a36*a44*a53 + + a11*a22*a36*a44*a53 + + a14*a22*a31*a46*a53 + - a12*a24*a31*a46*a53 + - a14*a21*a32*a46*a53 + + a11*a24*a32*a46*a53 + + a12*a21*a34*a46*a53 + - a11*a22*a34*a46*a53 + + a16*a23*a32*a41*a54 + - a13*a26*a32*a41*a54 + - a16*a22*a33*a41*a54 + + a12*a26*a33*a41*a54 + + a13*a22*a36*a41*a54 + - a12*a23*a36*a41*a54 + - a16*a23*a31*a42*a54 + + a13*a26*a31*a42*a54 + + a16*a21*a33*a42*a54 + - a11*a26*a33*a42*a54 + - a13*a21*a36*a42*a54 + + a11*a23*a36*a42*a54 + + a16*a22*a31*a43*a54 + - a12*a26*a31*a43*a54 + - a16*a21*a32*a43*a54 + + a11*a26*a32*a43*a54 + + a12*a21*a36*a43*a54 + - a11*a22*a36*a43*a54 + - a13*a22*a31*a46*a54 + + a12*a23*a31*a46*a54 + + a13*a21*a32*a46*a54 + - a11*a23*a32*a46*a54 + - a12*a21*a33*a46*a54 + + a11*a22*a33*a46*a54 + - a14*a23*a32*a41*a56 + + a13*a24*a32*a41*a56 + + a14*a22*a33*a41*a56 + - a12*a24*a33*a41*a56 + - a13*a22*a34*a41*a56 + + a12*a23*a34*a41*a56 + + a14*a23*a31*a42*a56 + - a13*a24*a31*a42*a56 + - a14*a21*a33*a42*a56 + + a11*a24*a33*a42*a56 + + a13*a21*a34*a42*a56 + - a11*a23*a34*a42*a56 + - a14*a22*a31*a43*a56 + + a12*a24*a31*a43*a56 + + a14*a21*a32*a43*a56 + - a11*a24*a32*a43*a56 + - a12*a21*a34*a43*a56 + + a11*a22*a34*a43*a56 + + a13*a22*a31*a44*a56 + - a12*a23*a31*a44*a56 + - a13*a21*a32*a44*a56 + + a11*a23*a32*a44*a56 + + a12*a21*a33*a44*a56 + - a11*a22*a33*a44*a56; + cofactor[30] = -a25*a34*a43*a52*a61 + + a24*a35*a43*a52*a61 + + a25*a33*a44*a52*a61 + - a23*a35*a44*a52*a61 + - a24*a33*a45*a52*a61 + + a23*a34*a45*a52*a61 + + a25*a34*a42*a53*a61 + - a24*a35*a42*a53*a61 + - a25*a32*a44*a53*a61 + + a22*a35*a44*a53*a61 + + a24*a32*a45*a53*a61 + - a22*a34*a45*a53*a61 + - a25*a33*a42*a54*a61 + + a23*a35*a42*a54*a61 + + a25*a32*a43*a54*a61 + - a22*a35*a43*a54*a61 + - a23*a32*a45*a54*a61 + + a22*a33*a45*a54*a61 + + a24*a33*a42*a55*a61 + - a23*a34*a42*a55*a61 + - a24*a32*a43*a55*a61 + + a22*a34*a43*a55*a61 + + a23*a32*a44*a55*a61 + - a22*a33*a44*a55*a61 + + a25*a34*a43*a51*a62 + - a24*a35*a43*a51*a62 + - a25*a33*a44*a51*a62 + + a23*a35*a44*a51*a62 + + a24*a33*a45*a51*a62 + - a23*a34*a45*a51*a62 + - a25*a34*a41*a53*a62 + + a24*a35*a41*a53*a62 + + a25*a31*a44*a53*a62 + - a21*a35*a44*a53*a62 + - a24*a31*a45*a53*a62 + + a21*a34*a45*a53*a62 + + a25*a33*a41*a54*a62 + - a23*a35*a41*a54*a62 + - a25*a31*a43*a54*a62 + + a21*a35*a43*a54*a62 + + a23*a31*a45*a54*a62 + - a21*a33*a45*a54*a62 + - a24*a33*a41*a55*a62 + + a23*a34*a41*a55*a62 + + a24*a31*a43*a55*a62 + - a21*a34*a43*a55*a62 + - a23*a31*a44*a55*a62 + + a21*a33*a44*a55*a62 + - a25*a34*a42*a51*a63 + + a24*a35*a42*a51*a63 + + a25*a32*a44*a51*a63 + - a22*a35*a44*a51*a63 + - a24*a32*a45*a51*a63 + + a22*a34*a45*a51*a63 + + a25*a34*a41*a52*a63 + - a24*a35*a41*a52*a63 + - a25*a31*a44*a52*a63 + + a21*a35*a44*a52*a63 + + a24*a31*a45*a52*a63 + - a21*a34*a45*a52*a63 + - a25*a32*a41*a54*a63 + + a22*a35*a41*a54*a63 + + a25*a31*a42*a54*a63 + - a21*a35*a42*a54*a63 + - a22*a31*a45*a54*a63 + + a21*a32*a45*a54*a63 + + a24*a32*a41*a55*a63 + - a22*a34*a41*a55*a63 + - a24*a31*a42*a55*a63 + + a21*a34*a42*a55*a63 + + a22*a31*a44*a55*a63 + - a21*a32*a44*a55*a63 + + a25*a33*a42*a51*a64 + - a23*a35*a42*a51*a64 + - a25*a32*a43*a51*a64 + + a22*a35*a43*a51*a64 + + a23*a32*a45*a51*a64 + - a22*a33*a45*a51*a64 + - a25*a33*a41*a52*a64 + + a23*a35*a41*a52*a64 + + a25*a31*a43*a52*a64 + - a21*a35*a43*a52*a64 + - a23*a31*a45*a52*a64 + + a21*a33*a45*a52*a64 + + a25*a32*a41*a53*a64 + - a22*a35*a41*a53*a64 + - a25*a31*a42*a53*a64 + + a21*a35*a42*a53*a64 + + a22*a31*a45*a53*a64 + - a21*a32*a45*a53*a64 + - a23*a32*a41*a55*a64 + + a22*a33*a41*a55*a64 + + a23*a31*a42*a55*a64 + - a21*a33*a42*a55*a64 + - a22*a31*a43*a55*a64 + + a21*a32*a43*a55*a64 + - a24*a33*a42*a51*a65 + + a23*a34*a42*a51*a65 + + a24*a32*a43*a51*a65 + - a22*a34*a43*a51*a65 + - a23*a32*a44*a51*a65 + + a22*a33*a44*a51*a65 + + a24*a33*a41*a52*a65 + - a23*a34*a41*a52*a65 + - a24*a31*a43*a52*a65 + + a21*a34*a43*a52*a65 + + a23*a31*a44*a52*a65 + - a21*a33*a44*a52*a65 + - a24*a32*a41*a53*a65 + + a22*a34*a41*a53*a65 + + a24*a31*a42*a53*a65 + - a21*a34*a42*a53*a65 + - a22*a31*a44*a53*a65 + + a21*a32*a44*a53*a65 + + a23*a32*a41*a54*a65 + - a22*a33*a41*a54*a65 + - a23*a31*a42*a54*a65 + + a21*a33*a42*a54*a65 + + a22*a31*a43*a54*a65 + - a21*a32*a43*a54*a65; + cofactor[31] = a15*a34*a43*a52*a61 + - a14*a35*a43*a52*a61 + - a15*a33*a44*a52*a61 + + a13*a35*a44*a52*a61 + + a14*a33*a45*a52*a61 + - a13*a34*a45*a52*a61 + - a15*a34*a42*a53*a61 + + a14*a35*a42*a53*a61 + + a15*a32*a44*a53*a61 + - a12*a35*a44*a53*a61 + - a14*a32*a45*a53*a61 + + a12*a34*a45*a53*a61 + + a15*a33*a42*a54*a61 + - a13*a35*a42*a54*a61 + - a15*a32*a43*a54*a61 + + a12*a35*a43*a54*a61 + + a13*a32*a45*a54*a61 + - a12*a33*a45*a54*a61 + - a14*a33*a42*a55*a61 + + a13*a34*a42*a55*a61 + + a14*a32*a43*a55*a61 + - a12*a34*a43*a55*a61 + - a13*a32*a44*a55*a61 + + a12*a33*a44*a55*a61 + - a15*a34*a43*a51*a62 + + a14*a35*a43*a51*a62 + + a15*a33*a44*a51*a62 + - a13*a35*a44*a51*a62 + - a14*a33*a45*a51*a62 + + a13*a34*a45*a51*a62 + + a15*a34*a41*a53*a62 + - a14*a35*a41*a53*a62 + - a15*a31*a44*a53*a62 + + a11*a35*a44*a53*a62 + + a14*a31*a45*a53*a62 + - a11*a34*a45*a53*a62 + - a15*a33*a41*a54*a62 + + a13*a35*a41*a54*a62 + + a15*a31*a43*a54*a62 + - a11*a35*a43*a54*a62 + - a13*a31*a45*a54*a62 + + a11*a33*a45*a54*a62 + + a14*a33*a41*a55*a62 + - a13*a34*a41*a55*a62 + - a14*a31*a43*a55*a62 + + a11*a34*a43*a55*a62 + + a13*a31*a44*a55*a62 + - a11*a33*a44*a55*a62 + + a15*a34*a42*a51*a63 + - a14*a35*a42*a51*a63 + - a15*a32*a44*a51*a63 + + a12*a35*a44*a51*a63 + + a14*a32*a45*a51*a63 + - a12*a34*a45*a51*a63 + - a15*a34*a41*a52*a63 + + a14*a35*a41*a52*a63 + + a15*a31*a44*a52*a63 + - a11*a35*a44*a52*a63 + - a14*a31*a45*a52*a63 + + a11*a34*a45*a52*a63 + + a15*a32*a41*a54*a63 + - a12*a35*a41*a54*a63 + - a15*a31*a42*a54*a63 + + a11*a35*a42*a54*a63 + + a12*a31*a45*a54*a63 + - a11*a32*a45*a54*a63 + - a14*a32*a41*a55*a63 + + a12*a34*a41*a55*a63 + + a14*a31*a42*a55*a63 + - a11*a34*a42*a55*a63 + - a12*a31*a44*a55*a63 + + a11*a32*a44*a55*a63 + - a15*a33*a42*a51*a64 + + a13*a35*a42*a51*a64 + + a15*a32*a43*a51*a64 + - a12*a35*a43*a51*a64 + - a13*a32*a45*a51*a64 + + a12*a33*a45*a51*a64 + + a15*a33*a41*a52*a64 + - a13*a35*a41*a52*a64 + - a15*a31*a43*a52*a64 + + a11*a35*a43*a52*a64 + + a13*a31*a45*a52*a64 + - a11*a33*a45*a52*a64 + - a15*a32*a41*a53*a64 + + a12*a35*a41*a53*a64 + + a15*a31*a42*a53*a64 + - a11*a35*a42*a53*a64 + - a12*a31*a45*a53*a64 + + a11*a32*a45*a53*a64 + + a13*a32*a41*a55*a64 + - a12*a33*a41*a55*a64 + - a13*a31*a42*a55*a64 + + a11*a33*a42*a55*a64 + + a12*a31*a43*a55*a64 + - a11*a32*a43*a55*a64 + + a14*a33*a42*a51*a65 + - a13*a34*a42*a51*a65 + - a14*a32*a43*a51*a65 + + a12*a34*a43*a51*a65 + + a13*a32*a44*a51*a65 + - a12*a33*a44*a51*a65 + - a14*a33*a41*a52*a65 + + a13*a34*a41*a52*a65 + + a14*a31*a43*a52*a65 + - a11*a34*a43*a52*a65 + - a13*a31*a44*a52*a65 + + a11*a33*a44*a52*a65 + + a14*a32*a41*a53*a65 + - a12*a34*a41*a53*a65 + - a14*a31*a42*a53*a65 + + a11*a34*a42*a53*a65 + + a12*a31*a44*a53*a65 + - a11*a32*a44*a53*a65 + - a13*a32*a41*a54*a65 + + a12*a33*a41*a54*a65 + + a13*a31*a42*a54*a65 + - a11*a33*a42*a54*a65 + - a12*a31*a43*a54*a65 + + a11*a32*a43*a54*a65; + + cofactor[32] = -a15*a24*a43*a52*a61 + + a14*a25*a43*a52*a61 + + a15*a23*a44*a52*a61 + - a13*a25*a44*a52*a61 + - a14*a23*a45*a52*a61 + + a13*a24*a45*a52*a61 + + a15*a24*a42*a53*a61 + - a14*a25*a42*a53*a61 + - a15*a22*a44*a53*a61 + + a12*a25*a44*a53*a61 + + a14*a22*a45*a53*a61 + - a12*a24*a45*a53*a61 + - a15*a23*a42*a54*a61 + + a13*a25*a42*a54*a61 + + a15*a22*a43*a54*a61 + - a12*a25*a43*a54*a61 + - a13*a22*a45*a54*a61 + + a12*a23*a45*a54*a61 + + a14*a23*a42*a55*a61 + - a13*a24*a42*a55*a61 + - a14*a22*a43*a55*a61 + + a12*a24*a43*a55*a61 + + a13*a22*a44*a55*a61 + - a12*a23*a44*a55*a61 + + a15*a24*a43*a51*a62 + - a14*a25*a43*a51*a62 + - a15*a23*a44*a51*a62 + + a13*a25*a44*a51*a62 + + a14*a23*a45*a51*a62 + - a13*a24*a45*a51*a62 + - a15*a24*a41*a53*a62 + + a14*a25*a41*a53*a62 + + a15*a21*a44*a53*a62 + - a11*a25*a44*a53*a62 + - a14*a21*a45*a53*a62 + + a11*a24*a45*a53*a62 + + a15*a23*a41*a54*a62 + - a13*a25*a41*a54*a62 + - a15*a21*a43*a54*a62 + + a11*a25*a43*a54*a62 + + a13*a21*a45*a54*a62 + - a11*a23*a45*a54*a62 + - a14*a23*a41*a55*a62 + + a13*a24*a41*a55*a62 + + a14*a21*a43*a55*a62 + - a11*a24*a43*a55*a62 + - a13*a21*a44*a55*a62 + + a11*a23*a44*a55*a62 + - a15*a24*a42*a51*a63 + + a14*a25*a42*a51*a63 + + a15*a22*a44*a51*a63 + - a12*a25*a44*a51*a63 + - a14*a22*a45*a51*a63 + + a12*a24*a45*a51*a63 + + a15*a24*a41*a52*a63 + - a14*a25*a41*a52*a63 + - a15*a21*a44*a52*a63 + + a11*a25*a44*a52*a63 + + a14*a21*a45*a52*a63 + - a11*a24*a45*a52*a63 + - a15*a22*a41*a54*a63 + + a12*a25*a41*a54*a63 + + a15*a21*a42*a54*a63 + - a11*a25*a42*a54*a63 + - a12*a21*a45*a54*a63 + + a11*a22*a45*a54*a63 + + a14*a22*a41*a55*a63 + - a12*a24*a41*a55*a63 + - a14*a21*a42*a55*a63 + + a11*a24*a42*a55*a63 + + a12*a21*a44*a55*a63 + - a11*a22*a44*a55*a63 + + a15*a23*a42*a51*a64 + - a13*a25*a42*a51*a64 + - a15*a22*a43*a51*a64 + + a12*a25*a43*a51*a64 + + a13*a22*a45*a51*a64 + - a12*a23*a45*a51*a64 + - a15*a23*a41*a52*a64 + + a13*a25*a41*a52*a64 + + a15*a21*a43*a52*a64 + - a11*a25*a43*a52*a64 + - a13*a21*a45*a52*a64 + + a11*a23*a45*a52*a64 + + a15*a22*a41*a53*a64 + - a12*a25*a41*a53*a64 + - a15*a21*a42*a53*a64 + + a11*a25*a42*a53*a64 + + a12*a21*a45*a53*a64 + - a11*a22*a45*a53*a64 + - a13*a22*a41*a55*a64 + + a12*a23*a41*a55*a64 + + a13*a21*a42*a55*a64 + - a11*a23*a42*a55*a64 + - a12*a21*a43*a55*a64 + + a11*a22*a43*a55*a64 + + - a14*a23*a42*a51*a65 + + a13*a24*a42*a51*a65 + + a14*a22*a43*a51*a65 + - a12*a24*a43*a51*a65 + - a13*a22*a44*a51*a65 + + a12*a23*a44*a51*a65 + + a14*a23*a41*a52*a65 + - a13*a24*a41*a52*a65 + - a14*a21*a43*a52*a65 + + a11*a24*a43*a52*a65 + + a13*a21*a44*a52*a65 + - a11*a23*a44*a52*a65 + - a14*a22*a41*a53*a65 + + a12*a24*a41*a53*a65 + + a14*a21*a42*a53*a65 + - a11*a24*a42*a53*a65 + - a12*a21*a44*a53*a65 + + a11*a22*a44*a53*a65 + + a13*a22*a41*a54*a65 + - a12*a23*a41*a54*a65 + - a13*a21*a42*a54*a65 + + a11*a23*a42*a54*a65 + + a12*a21*a43*a54*a65 + - a11*a22*a43*a54*a65; + cofactor[33] = a15*a24*a33*a52*a61 + - a14*a25*a33*a52*a61 + - a15*a23*a34*a52*a61 + + a13*a25*a34*a52*a61 + + a14*a23*a35*a52*a61 + - a13*a24*a35*a52*a61 + - a15*a24*a32*a53*a61 + + a14*a25*a32*a53*a61 + + a15*a22*a34*a53*a61 + - a12*a25*a34*a53*a61 + - a14*a22*a35*a53*a61 + + a12*a24*a35*a53*a61 + + a15*a23*a32*a54*a61 + - a13*a25*a32*a54*a61 + - a15*a22*a33*a54*a61 + + a12*a25*a33*a54*a61 + + a13*a22*a35*a54*a61 + - a12*a23*a35*a54*a61 + - a14*a23*a32*a55*a61 + + a13*a24*a32*a55*a61 + + a14*a22*a33*a55*a61 + - a12*a24*a33*a55*a61 + - a13*a22*a34*a55*a61 + + a12*a23*a34*a55*a61 + - a15*a24*a33*a51*a62 + + a14*a25*a33*a51*a62 + + a15*a23*a34*a51*a62 + - a13*a25*a34*a51*a62 + - a14*a23*a35*a51*a62 + + a13*a24*a35*a51*a62 + + a15*a24*a31*a53*a62 + - a14*a25*a31*a53*a62 + - a15*a21*a34*a53*a62 + + a11*a25*a34*a53*a62 + + a14*a21*a35*a53*a62 + - a11*a24*a35*a53*a62 + - a15*a23*a31*a54*a62 + + a13*a25*a31*a54*a62 + + a15*a21*a33*a54*a62 + - a11*a25*a33*a54*a62 + - a13*a21*a35*a54*a62 + + a11*a23*a35*a54*a62 + + a14*a23*a31*a55*a62 + - a13*a24*a31*a55*a62 + - a14*a21*a33*a55*a62 + + a11*a24*a33*a55*a62 + + a13*a21*a34*a55*a62 + - a11*a23*a34*a55*a62 + + a15*a24*a32*a51*a63 + - a14*a25*a32*a51*a63 + - a15*a22*a34*a51*a63 + + a12*a25*a34*a51*a63 + + a14*a22*a35*a51*a63 + - a12*a24*a35*a51*a63 + - a15*a24*a31*a52*a63 + + a14*a25*a31*a52*a63 + + a15*a21*a34*a52*a63 + - a11*a25*a34*a52*a63 + - a14*a21*a35*a52*a63 + + a11*a24*a35*a52*a63 + + a15*a22*a31*a54*a63 + - a12*a25*a31*a54*a63 + - a15*a21*a32*a54*a63 + + a11*a25*a32*a54*a63 + + a12*a21*a35*a54*a63 + - a11*a22*a35*a54*a63 + - a14*a22*a31*a55*a63 + + a12*a24*a31*a55*a63 + + a14*a21*a32*a55*a63 + - a11*a24*a32*a55*a63 + - a12*a21*a34*a55*a63 + + a11*a22*a34*a55*a63 + - a15*a23*a32*a51*a64 + + a13*a25*a32*a51*a64 + + a15*a22*a33*a51*a64 + - a12*a25*a33*a51*a64 + - a13*a22*a35*a51*a64 + + a12*a23*a35*a51*a64 + + a15*a23*a31*a52*a64 + - a13*a25*a31*a52*a64 + - a15*a21*a33*a52*a64 + + a11*a25*a33*a52*a64 + + a13*a21*a35*a52*a64 + - a11*a23*a35*a52*a64 + - a15*a22*a31*a53*a64 + + a12*a25*a31*a53*a64 + + a15*a21*a32*a53*a64 + - a11*a25*a32*a53*a64 + - a12*a21*a35*a53*a64 + + a11*a22*a35*a53*a64 + + a13*a22*a31*a55*a64 + - a12*a23*a31*a55*a64 + - a13*a21*a32*a55*a64 + + a11*a23*a32*a55*a64 + + a12*a21*a33*a55*a64 + - a11*a22*a33*a55*a64 + + a14*a23*a32*a51*a65 + - a13*a24*a32*a51*a65 + - a14*a22*a33*a51*a65 + + a12*a24*a33*a51*a65 + + a13*a22*a34*a51*a65 + - a12*a23*a34*a51*a65 + - a14*a23*a31*a52*a65 + + a13*a24*a31*a52*a65 + + a14*a21*a33*a52*a65 + - a11*a24*a33*a52*a65 + - a13*a21*a34*a52*a65 + + a11*a23*a34*a52*a65 + + a14*a22*a31*a53*a65 + - a12*a24*a31*a53*a65 + - a14*a21*a32*a53*a65 + + a11*a24*a32*a53*a65 + + a12*a21*a34*a53*a65 + - a11*a22*a34*a53*a65 + - a13*a22*a31*a54*a65 + + a12*a23*a31*a54*a65 + + a13*a21*a32*a54*a65 + - a11*a23*a32*a54*a65 + - a12*a21*a33*a54*a65 + + a11*a22*a33*a54*a65; + cofactor[34] = -a15*a24*a33*a42*a61 + + a14*a25*a33*a42*a61 + + a15*a23*a34*a42*a61 + - a13*a25*a34*a42*a61 + - a14*a23*a35*a42*a61 + + a13*a24*a35*a42*a61 + + a15*a24*a32*a43*a61 + - a14*a25*a32*a43*a61 + - a15*a22*a34*a43*a61 + + a12*a25*a34*a43*a61 + + a14*a22*a35*a43*a61 + - a12*a24*a35*a43*a61 + - a15*a23*a32*a44*a61 + + a13*a25*a32*a44*a61 + + a15*a22*a33*a44*a61 + - a12*a25*a33*a44*a61 + - a13*a22*a35*a44*a61 + + a12*a23*a35*a44*a61 + + a14*a23*a32*a45*a61 + - a13*a24*a32*a45*a61 + - a14*a22*a33*a45*a61 + + a12*a24*a33*a45*a61 + + a13*a22*a34*a45*a61 + - a12*a23*a34*a45*a61 + + a15*a24*a33*a41*a62 + - a14*a25*a33*a41*a62 + - a15*a23*a34*a41*a62 + + a13*a25*a34*a41*a62 + + a14*a23*a35*a41*a62 + - a13*a24*a35*a41*a62 + - a15*a24*a31*a43*a62 + + a14*a25*a31*a43*a62 + + a15*a21*a34*a43*a62 + - a11*a25*a34*a43*a62 + - a14*a21*a35*a43*a62 + + a11*a24*a35*a43*a62 + + a15*a23*a31*a44*a62 + - a13*a25*a31*a44*a62 + - a15*a21*a33*a44*a62 + + a11*a25*a33*a44*a62 + + a13*a21*a35*a44*a62 + - a11*a23*a35*a44*a62 + - a14*a23*a31*a45*a62 + + a13*a24*a31*a45*a62 + + a14*a21*a33*a45*a62 + - a11*a24*a33*a45*a62 + - a13*a21*a34*a45*a62 + + a11*a23*a34*a45*a62 + - a15*a24*a32*a41*a63 + + a14*a25*a32*a41*a63 + + a15*a22*a34*a41*a63 + - a12*a25*a34*a41*a63 + - a14*a22*a35*a41*a63 + + a12*a24*a35*a41*a63 + + a15*a24*a31*a42*a63 + - a14*a25*a31*a42*a63 + - a15*a21*a34*a42*a63 + + a11*a25*a34*a42*a63 + + a14*a21*a35*a42*a63 + - a11*a24*a35*a42*a63 + - a15*a22*a31*a44*a63 + + a12*a25*a31*a44*a63 + + a15*a21*a32*a44*a63 + - a11*a25*a32*a44*a63 + - a12*a21*a35*a44*a63 + + a11*a22*a35*a44*a63 + + a14*a22*a31*a45*a63 + - a12*a24*a31*a45*a63 + - a14*a21*a32*a45*a63 + + a11*a24*a32*a45*a63 + + a12*a21*a34*a45*a63 + - a11*a22*a34*a45*a63 + + a15*a23*a32*a41*a64 + - a13*a25*a32*a41*a64 + - a15*a22*a33*a41*a64 + + a12*a25*a33*a41*a64 + + a13*a22*a35*a41*a64 + - a12*a23*a35*a41*a64 + - a15*a23*a31*a42*a64 + + a13*a25*a31*a42*a64 + + a15*a21*a33*a42*a64 + - a11*a25*a33*a42*a64 + - a13*a21*a35*a42*a64 + + a11*a23*a35*a42*a64 + + a15*a22*a31*a43*a64 + - a12*a25*a31*a43*a64 + - a15*a21*a32*a43*a64 + + a11*a25*a32*a43*a64 + + a12*a21*a35*a43*a64 + - a11*a22*a35*a43*a64 + - a13*a22*a31*a45*a64 + + a12*a23*a31*a45*a64 + + a13*a21*a32*a45*a64 + - a11*a23*a32*a45*a64 + - a12*a21*a33*a45*a64 + + a11*a22*a33*a45*a64 + - a14*a23*a32*a41*a65 + + a13*a24*a32*a41*a65 + + a14*a22*a33*a41*a65 + - a12*a24*a33*a41*a65 + - a13*a22*a34*a41*a65 + + a12*a23*a34*a41*a65 + + a14*a23*a31*a42*a65 + - a13*a24*a31*a42*a65 + - a14*a21*a33*a42*a65 + + a11*a24*a33*a42*a65 + + a13*a21*a34*a42*a65 + - a11*a23*a34*a42*a65 + - a14*a22*a31*a43*a65 + + a12*a24*a31*a43*a65 + + a14*a21*a32*a43*a65 + - a11*a24*a32*a43*a65 + - a12*a21*a34*a43*a65 + + a11*a22*a34*a43*a65 + + a13*a22*a31*a44*a65 + - a12*a23*a31*a44*a65 + - a13*a21*a32*a44*a65 + + a11*a23*a32*a44*a65 + + a12*a21*a33*a44*a65 + - a11*a22*a33*a44*a65; + cofactor[35] = a15*a24*a33*a42*a51 + - a14*a25*a33*a42*a51 + - a15*a23*a34*a42*a51 + + a13*a25*a34*a42*a51 + + a14*a23*a35*a42*a51 + - a13*a24*a35*a42*a51 + - a15*a24*a32*a43*a51 + + a14*a25*a32*a43*a51 + + a15*a22*a34*a43*a51 + - a12*a25*a34*a43*a51 + - a14*a22*a35*a43*a51 + + a12*a24*a35*a43*a51 + + a15*a23*a32*a44*a51 + - a13*a25*a32*a44*a51 + - a15*a22*a33*a44*a51 + + a12*a25*a33*a44*a51 + + a13*a22*a35*a44*a51 + - a12*a23*a35*a44*a51 + - a14*a23*a32*a45*a51 + + a13*a24*a32*a45*a51 + + a14*a22*a33*a45*a51 + - a12*a24*a33*a45*a51 + - a13*a22*a34*a45*a51 + + a12*a23*a34*a45*a51 + - a15*a24*a33*a41*a52 + + a14*a25*a33*a41*a52 + + a15*a23*a34*a41*a52 + - a13*a25*a34*a41*a52 + - a14*a23*a35*a41*a52 + + a13*a24*a35*a41*a52 + + a15*a24*a31*a43*a52 + - a14*a25*a31*a43*a52 + - a15*a21*a34*a43*a52 + + a11*a25*a34*a43*a52 + + a14*a21*a35*a43*a52 + - a11*a24*a35*a43*a52 + - a15*a23*a31*a44*a52 + + a13*a25*a31*a44*a52 + + a15*a21*a33*a44*a52 + - a11*a25*a33*a44*a52 + - a13*a21*a35*a44*a52 + + a11*a23*a35*a44*a52 + + a14*a23*a31*a45*a52 + - a13*a24*a31*a45*a52 + - a14*a21*a33*a45*a52 + + a11*a24*a33*a45*a52 + + a13*a21*a34*a45*a52 + - a11*a23*a34*a45*a52 + + a15*a24*a32*a41*a53 + - a14*a25*a32*a41*a53 + - a15*a22*a34*a41*a53 + + a12*a25*a34*a41*a53 + + a14*a22*a35*a41*a53 + - a12*a24*a35*a41*a53 + - a15*a24*a31*a42*a53 + + a14*a25*a31*a42*a53 + + a15*a21*a34*a42*a53 + - a11*a25*a34*a42*a53 + - a14*a21*a35*a42*a53 + + a11*a24*a35*a42*a53 + + a15*a22*a31*a44*a53 + - a12*a25*a31*a44*a53 + - a15*a21*a32*a44*a53 + + a11*a25*a32*a44*a53 + + a12*a21*a35*a44*a53 + - a11*a22*a35*a44*a53 + - a14*a22*a31*a45*a53 + + a12*a24*a31*a45*a53 + + a14*a21*a32*a45*a53 + - a11*a24*a32*a45*a53 + - a12*a21*a34*a45*a53 + + a11*a22*a34*a45*a53 + - a15*a23*a32*a41*a54 + + a13*a25*a32*a41*a54 + + a15*a22*a33*a41*a54 + - a12*a25*a33*a41*a54 + - a13*a22*a35*a41*a54 + + a12*a23*a35*a41*a54 + + a15*a23*a31*a42*a54 + - a13*a25*a31*a42*a54 + - a15*a21*a33*a42*a54 + + a11*a25*a33*a42*a54 + + a13*a21*a35*a42*a54 + - a11*a23*a35*a42*a54 + - a15*a22*a31*a43*a54 + + a12*a25*a31*a43*a54 + + a15*a21*a32*a43*a54 + - a11*a25*a32*a43*a54 + - a12*a21*a35*a43*a54 + + a11*a22*a35*a43*a54 + + a13*a22*a31*a45*a54 + - a12*a23*a31*a45*a54 + - a13*a21*a32*a45*a54 + + a11*a23*a32*a45*a54 + + a12*a21*a33*a45*a54 + - a11*a22*a33*a45*a54 + + a14*a23*a32*a41*a55 + - a13*a24*a32*a41*a55 + - a14*a22*a33*a41*a55 + + a12*a24*a33*a41*a55 + + a13*a22*a34*a41*a55 + - a12*a23*a34*a41*a55 + - a14*a23*a31*a42*a55 + + a13*a24*a31*a42*a55 + + a14*a21*a33*a42*a55 + - a11*a24*a33*a42*a55 + - a13*a21*a34*a42*a55 + + a11*a23*a34*a42*a55 + + a14*a22*a31*a43*a55 + - a12*a24*a31*a43*a55 + - a14*a21*a32*a43*a55 + + a11*a24*a32*a43*a55 + + a12*a21*a34*a43*a55 + - a11*a22*a34*a43*a55 + - a13*a22*a31*a44*a55 + + a12*a23*a31*a44*a55 + + a13*a21*a32*a44*a55 + - a11*a23*a32*a44*a55 + - a12*a21*a33*a44*a55 + + a11*a22*a33*a44*a55; + +/* ainv = transpose(cofactor) ! / det */ + const double jinv = 1/det; + ainv[0] = cofactor[0]*jinv; + ainv[1] = cofactor[6]*jinv; + ainv[2] = cofactor[12]*jinv; + ainv[3] = cofactor[18]*jinv; + ainv[4] = cofactor[24]*jinv; + ainv[5] = cofactor[30]*jinv; + ainv[6] = cofactor[1]*jinv; + ainv[7] = cofactor[7]*jinv; + ainv[8] = cofactor[13]*jinv; + ainv[9] = cofactor[19]*jinv; + ainv[10] = cofactor[25]*jinv; + ainv[11] = cofactor[31]*jinv; + ainv[12] = cofactor[2]*jinv; + ainv[13] = cofactor[8]*jinv; + ainv[14] = cofactor[14]*jinv; + ainv[15] = cofactor[20]*jinv; + ainv[16] = cofactor[26]*jinv; + ainv[17] = cofactor[32]*jinv; + ainv[18] = cofactor[3]*jinv; + ainv[19] = cofactor[9]*jinv; + ainv[20] = cofactor[15]*jinv; + ainv[21] = cofactor[21]*jinv; + ainv[22] = cofactor[27]*jinv; + ainv[23] = cofactor[33]*jinv; + ainv[24] = cofactor[4]*jinv; + ainv[25] = cofactor[10]*jinv; + ainv[26] = cofactor[16]*jinv; + ainv[27] = cofactor[22]*jinv; + ainv[28] = cofactor[28]*jinv; + ainv[29] = cofactor[34]*jinv; + ainv[30] = cofactor[5]*jinv; + ainv[31] = cofactor[11]*jinv; + ainv[32] = cofactor[17]*jinv; + ainv[33] = cofactor[23]*jinv; + ainv[34] = cofactor[29]*jinv; + ainv[35] = cofactor[35]*jinv; + + *ok_flag__ = 0; + return 0; +} diff --git a/SRC/matrix/routines/xblas.h b/SRC/matrix/routines/xblas.h new file mode 100644 index 0000000000..a55aa90a4d --- /dev/null +++ b/SRC/matrix/routines/xblas.h @@ -0,0 +1,102 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +#ifndef blasdecl_H +#define blasdecl_H + +#ifndef _WIN32 +# define DAXPY daxpy_ +# define DSCAL dscal_ +# define DGEMV dgemv_ +// Level 3 +# define DGETRF dgetrf_ +# define DGETRI dgetri_ +# define DGEMM dgemm_ +// Lapack +# define DGESV dgesv_ +# define DGETRS dgetrs_ +# define DGBSV dgbsv_ +# define DGBTRS dgbtrs_ +# define DPBSV dpbsv_ +# define DPBTRS dpbtrs_ +#endif + +extern "C" { + // Level 1 + // x = alpha * x + beta * y + void DAXPY (int*, double*, double*, const int*, double*, const int*); + void DSCAL (int*, double*, double*, const int*); + void DGEMV (const char* trans, int* M, int* N, + double* alpha, + const double* A, int* lda, + double* X, int* incX, + double* beta, + double* Y, int* incY); +// Level 3 +#if 0 + void DGESV(int *N, int *NRHS, double *A, int *LDA, + int *iPiv, double *B, int *LDB, int *INFO); + void DGETRS(char *TRANS, unsigned int sizeT, + int *N, int *NRHS, double *A, int *LDA, + int *iPiv, double *B, int *LDB, int *INFO); +#endif + + void DGETRF(int *M, int *N, double *A, int *LDA, + int *iPiv, int *INFO); + + void DGETRI(int *N, double *A, int *LDA, + int *iPiv, double *Work, int *WORKL, int *INFO); + + void DGEMM(const char* transA, const char* transB, int* M, int* N, int* K, + double* alpha, + double* A, const int* lda, + double* B, const int* ldb, + double* beta, + double* C, const int* ldc); + +// +// Lapack +// +// FullGen +int DGESV(int *N, int *NRHS, double *A, int *LDA, + int *iPiv, double *B, int *LDB, int *INFO); + +int DGETRS(char *TRANS, + int *N, int *NRHS, double *A, int *LDA, + int *iPiv, double *B, int *LDB, int *INFO); + +// BandGen +int DGBSV(int *N, int *KL, int *KU, int *NRHS, double *A, + int *LDA, int *iPiv, double *B, int *LDB, + int *INFO); + +int DGBTRS(char *TRANS, + int *N, int *KL, int *KU, int *NRHS, + double *A, int *LDA, int *iPiv, + double *B, int *LDB, int *INFO); + +// BandSPD +int DPBSV(char *UPLO, + int *N, int *KD, int *NRHS, + double *A, int *LDA, double *B, int *LDB, + int *INFO); + +int DPBTRS(char *UPLO, + int *N, int *KD, int *NRHS, + double *A, int *LDA, double *B, int *LDB, + int *INFO); +} + +#endif // blasdecl_H diff --git a/SRC/recorder/CMakeLists.txt b/SRC/recorder/CMakeLists.txt index 1d5410c1da..6234f73649 100644 --- a/SRC/recorder/CMakeLists.txt +++ b/SRC/recorder/CMakeLists.txt @@ -56,8 +56,10 @@ if(HDF5_FOUND) target_sources(OPS_Recorder PRIVATE MPCORecorder.cpp + VTKHDF_Recorder.cpp PUBLIC MPCORecorder.h + VTKHDF_Recorder.h ) endif() endif() diff --git a/SRC/recorder/MPCORecorder.cpp b/SRC/recorder/MPCORecorder.cpp index 1d9bf4ebda..ed678f5835 100755 --- a/SRC/recorder/MPCORecorder.cpp +++ b/SRC/recorder/MPCORecorder.cpp @@ -3995,7 +3995,8 @@ namespace mpco { else if ( // ./mvlem elem_class_tag == ELE_TAG_MVLEM_3D || - elem_class_tag == ELE_TAG_SFI_MVLEM_3D + elem_class_tag == ELE_TAG_SFI_MVLEM_3D || + elem_class_tag == ELE_TAG_E_SFI_MVLEM_3D ) { geom_type = ElementGeometryType::Quadrilateral_CohesiveBand_4N; int_type = ElementIntegrationRuleType::CustomIntegrationRule; @@ -4173,7 +4174,8 @@ namespace mpco { bool done = false; std::string request1 = "section"; if (elem->getClassTag() == ELE_TAG_MVLEM_3D || - elem->getClassTag() == ELE_TAG_SFI_MVLEM_3D) { + elem->getClassTag() == ELE_TAG_SFI_MVLEM_3D || + elem->getClassTag() == ELE_TAG_E_SFI_MVLEM_3D) { request1 = "material"; } std::string request3 = "dummy"; diff --git a/SRC/recorder/TclRecorderCommands.cpp b/SRC/recorder/TclRecorderCommands.cpp index 8f4375f623..e8cf1fb11a 100644 --- a/SRC/recorder/TclRecorderCommands.cpp +++ b/SRC/recorder/TclRecorderCommands.cpp @@ -66,6 +66,7 @@ extern void* OPS_PVDRecorder(); extern void* OPS_GmshRecorder(); #ifdef _HDF5 extern void* OPS_MPCORecorder(); +extern void* OPS_VTKHDF_Recorder(); #endif // _HDF5 extern void* OPS_VTK_Recorder(); extern void* OPS_ElementRecorderRMS(); @@ -1934,6 +1935,10 @@ enum outputMode {STANDARD_STREAM, DATA_STREAM, XML_STREAM, DATABASE_STREAM, BIN OPS_ResetInputNoBuilder(clientData, interp, 2, argc, argv, &theDomain); (*theRecorder) = (Recorder*)OPS_MPCORecorder(); } + else if (strcmp(argv[1], "vtkhdf") == 0 || strcmp(argv[1], "VTKHDF") == 0) { + OPS_ResetInputNoBuilder(clientData, interp, 2, argc, argv, &theDomain); + (*theRecorder) = (Recorder*)OPS_VTKHDF_Recorder(); + } #endif // _HDF5 else if (strcmp(argv[1],"gmsh") == 0 || strcmp(argv[1],"GMSH") == 0) { OPS_ResetInputNoBuilder(clientData, interp, 2, argc, argv, &theDomain); diff --git a/SRC/recorder/VTKHDF_Recorder.cpp b/SRC/recorder/VTKHDF_Recorder.cpp new file mode 100644 index 0000000000..09931775f6 --- /dev/null +++ b/SRC/recorder/VTKHDF_Recorder.cpp @@ -0,0 +1,3651 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +#include "VTKHDF_Recorder.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hdf5.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + + +// Static variable initialization +std::map VTKHDF_Recorder::vtktypes; + + + +// Constructor +SilentStream::SilentStream() : OPS_Stream(0) {} + +// Destructor +SilentStream::~SilentStream() {} + + + + +OutputDataHDF::OutputDataHDF() +{ + disp = false; vel = false; accel = false; + reaction = false; mass = false; unbalancedLoad = false; + stress3D6 = false; strain3D6 = false; + stress2D3 = false; strain2D3 = false; +} + +OutputDataHDF &OutputDataHDF::operator=(const OutputDataHDF &other) +{ + // Guard against self-assignment + if (this == &other) { + return *this; + } + // Copy all members + disp = other.disp; + vel = other.vel; + accel = other.accel; + reaction = other.reaction; + mass = other.mass; + unbalancedLoad = other.unbalancedLoad; + stress3D6 = other.stress3D6; + strain3D6 = other.strain3D6; + stress2D3 = other.stress2D3; + strain2D3 = other.strain2D3; + + + return *this; +} + + + +void* OPS_VTKHDF_Recorder() +{ + // Check minimum arguments + int numdata = OPS_GetNumRemainingInputArgs(); + if(numdata < 1) { + opserr << "WARNING: insufficient number of arguments\n"; + return 0; + } + + // Get filename + const char* name = OPS_GetString(); + + // Initialize default values + OutputDataHDF outputData; + std::vector eledata; + double dT = 0.0; + double rTolDt = 0.00001; + + // Parse remaining arguments + numdata = OPS_GetNumRemainingInputArgs(); + while(numdata > 0) { + const char* type = OPS_GetString(); + + // Displacement options + if(strcmp(type, "disp") == 0) { + outputData.disp = true; + } + // Velocity options + else if(strcmp(type, "vel") == 0) { + outputData.vel = true; + } + // Acceleration options + else if(strcmp(type, "accel") == 0) { + outputData.accel = true; + } + // Reaction options + else if(strcmp(type, "reaction") == 0) { + outputData.reaction = true; + } + // Other response options + else if(strcmp(type, "mass") == 0) { + outputData.mass = true; + } else if(strcmp(type, "unbalancedLoad") == 0) { + outputData.unbalancedLoad = true; + } + + else if (strcmp(type, "stress3D6") == 0) { + outputData.stress3D6 = true; + } else if (strcmp(type, "strain3D6") == 0) { + outputData.strain3D6 = true; + } + else if (strcmp(type, "stress2D3") == 0) { + outputData.stress2D3 = true; + } else if(strcmp(type, "strain2D3") == 0) { + outputData.strain2D3 = true; + } + // Time step options + else if(strcmp(type, "-dT") == 0) { + if(OPS_GetNumRemainingInputArgs() < 1) { + opserr << "WARNING: needs dT\n"; + return 0; + } + numdata = 1; + if(OPS_GetDoubleInput(&numdata, &dT) < 0) { + opserr << "WARNING: failed to read dT\n"; + return 0; + } + dT = (dT < 0) ? 0 : dT; + } + else if(strcmp(type, "-rTolDt") == 0) { + if(OPS_GetNumRemainingInputArgs() < 1) { + opserr << "WARNING: needs rTolDt\n"; + return 0; + } + numdata = 1; + if(OPS_GetDoubleInput(&numdata, &rTolDt) < 0) { + opserr << "WARNING: failed to read rTolDt\n"; + return 0; + } + rTolDt = (rTolDt < 0) ? 0 : rTolDt; + } + + numdata = OPS_GetNumRemainingInputArgs(); + } + // // print summary of parmeters for the user + // opserr << "VTKHDF_Recorder: " << name << " -dT " << dT << " -rTolDt " << rTolDt << endln; + // opserr << "disp " << (outputData.disp ? "true" : "false") << endln; + // opserr << "vel " << (outputData.vel ? "true" : "false") << endln; + // opserr << "accel " << (outputData.accel ? "true" : "false") << endln; + // opserr << "reaction " << (outputData.reaction ? "true" : "false") << endln; + // opserr << "mass " << (outputData.mass ? "true" : "false") << endln; + // opserr << "unbalancedLoad " << (outputData.unbalancedLoad ? "true" : "false") << endln; + // opserr << "stress3D6 " << (outputData.stress3D6 ? "true" : "false") << endln; + // opserr << "strain3D6 " << (outputData.strain3D6 ? "true" : "false") << endln; + // opserr << "stress2D3 " << (outputData.stress2D3 ? "true" : "false") << endln; + // opserr << "strain2D3 " << (outputData.strain2D3 ? "true" : "false") << endln; + + // Create the recorder + return new VTKHDF_Recorder(name, outputData, eledata, dT, rTolDt); +} + +VTKHDF_Recorder::VTKHDF_Recorder(const char *inputName, + const OutputDataHDF& outData, + const std::vector& edata, + double dt, double rTolDt) + :Recorder(RECORDER_TAGS_VTKHDF_Recorder), + // Initialize member variables + name(nullptr), + outputData(outData), + theDomain(0), + nextTimeStampToRecord(0.0), + deltaT(dt), + relDeltaTTol(rTolDt), + counter(0), + initializationDone(false), + initDone(false) +{ + + + name = new char[strlen(inputName) + 1]; + strcpy(name, inputName); + + + VTKHDF_Recorder::setVTKType(); // ----------------------- + // 1) Create (or overwrite) the HDF5 file using the C API with SWMR support + // ----------------------- + // Create file access property list for SWMR (Single Writer Multiple Reader) + hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS); + if (fapl_id < 0) { + opserr << "Error: Could not create file access property list for " << name << endln; + return; + } + + // Enable latest version of the library format (required for SWMR) + herr_t ret = H5Pset_libver_bounds(fapl_id, H5F_LIBVER_LATEST, H5F_LIBVER_LATEST); + if (ret < 0) { + opserr << "Error: Could not set library version bounds for " << name << endln; + H5Pclose(fapl_id); + return; + } + + // Create the file with SWMR-compatible settings + file_id = H5Fcreate(name, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + if (file_id < 0) { + opserr << "Error: Could not create HDF5 file " << name << endln; + H5Pclose(fapl_id); + return; + } + + // Close the file temporarily to reopen it in SWMR write mode + H5Fclose(file_id); + + // Reopen the file in SWMR write mode + file_id = H5Fopen(name, H5F_ACC_RDWR | H5F_ACC_SWMR_WRITE, fapl_id); + if (file_id < 0) { + opserr << "Error: Could not reopen HDF5 file in SWMR write mode " << name << endln; + H5Pclose(fapl_id); + return; + } + + // Close the file access property list + H5Pclose(fapl_id); + + // 4) Create the group "/VTKHDF" + group_id = H5Gcreate(file_id, "/VTKHDF", + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (group_id < 0) { + opserr << "Error: Could not create group '/VTKHDF' in HDF5 file " << name << endln; + H5Fclose(file_id); + return; + } + + // ----------------------- + // 2) Write the "Version" attribute (two integers [2, 3]) + // ----------------------- + // Create a simple 1D dataspace for two integers + hsize_t dims[1] = {2}; + hid_t version_dataspace_id = H5Screate_simple(1, dims, nullptr); + if (version_dataspace_id < 0) { + opserr << "Error: Could not create dataspace for 'Version' attribute in " + << name << endln; + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + + hid_t version_attr_id = H5Acreate(group_id, + "Version", + H5T_NATIVE_INT, + version_dataspace_id, + H5P_DEFAULT, + H5P_DEFAULT); + if (version_attr_id < 0) { + opserr << "Error: Could not create attribute 'Version' in group '/VTKHDF' in file " + << name << endln; + H5Sclose(version_dataspace_id); + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + + int version_data[2] = {2, 3}; + herr_t status = H5Awrite(version_attr_id, H5T_NATIVE_INT, version_data); + if (status < 0) { + opserr << "Error: Could not write 'Version' attribute in file " << name << endln; + H5Aclose(version_attr_id); + H5Sclose(version_dataspace_id); + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + + // Close version attribute and dataspace + H5Aclose(version_attr_id); + H5Sclose(version_dataspace_id); + + // ----------------------- + // 3) Write the "Type" attribute: "UnstructuredGrid" + // ----------------------- + // Create a dataspace for a single (scalar) string + hid_t type_dataspace_id = H5Screate(H5S_SCALAR); + if (type_dataspace_id < 0) { + opserr << "Error: Could not create dataspace for 'Type' attribute in file " + << name << endln; + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + + // Create a string datatype (fixed-length or variable-length). + // Here we use a fixed-length approach with the length of the string. + const char *typeStr = "UnstructuredGrid"; + size_t typeLen = strlen(typeStr); + + hid_t str_type_id = H5Tcopy(H5T_C_S1); + if (str_type_id < 0) { + opserr << "Error: Could not copy H5T_C_S1 for attribute 'Type' in file " + << name << endln; + H5Sclose(type_dataspace_id); + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + // Set the size of the string type (including space for '\0', if desired) + status = H5Tset_size(str_type_id, typeLen); + if (status < 0) { + opserr << "Error: Could not set size for 'Type' string in file " << name << endln; + H5Tclose(str_type_id); + H5Sclose(type_dataspace_id); + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + // Decide how to handle strings shorter than typeLen (null-pad, etc.) + // For example: + H5Tset_strpad(str_type_id, H5T_STR_NULLTERM); + + // Create the attribute + hid_t type_attr_id = H5Acreate(group_id, + "Type", + str_type_id, + type_dataspace_id, + H5P_DEFAULT, + H5P_DEFAULT); + if (type_attr_id < 0) { + opserr << "Error: Could not create attribute 'Type' in group '/VTKHDF' in file " + << name << endln; + H5Tclose(str_type_id); + H5Sclose(type_dataspace_id); + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + + // Write the string + status = H5Awrite(type_attr_id, str_type_id, typeStr); + if (status < 0) { + opserr << "Error: Could not write attribute 'Type' in file " << name << endln; + H5Aclose(type_attr_id); + H5Tclose(str_type_id); + H5Sclose(type_dataspace_id); + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + + // Close all resources + H5Aclose(type_attr_id); + H5Tclose(str_type_id); + H5Sclose(type_dataspace_id); + + // ----------------------- + // 4) create pointData group "/VTKHDF/pointData" + // ----------------------- + + point_data_group = H5Gcreate(group_id, "/VTKHDF/PointData", + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (point_data_group < 0) { + opserr << "Error: Could not create group '/VTKHDF/pointData' in HDF5 file " << name << endln; + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + + // ----------------------- + // 5) create Cells group "/VTKHDF/CellData" + // ----------------------- + cell_data_group = H5Gcreate(group_id, "/VTKHDF/CellData", + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (cell_data_group < 0) { + opserr << "Error: Could not create group '/VTKHDF/CellData' in HDF5 file " << name << endln; + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + + // ----------------------- + // 6) create Points dataset "/VTKHDF/Points" with shape (0,3) and resizable (unlimited,3) + // ----------------------- + { + hsize_t dims[2] = {0, 3}; + hsize_t maxdims[2] = {H5S_UNLIMITED, 3}; + hid_t space_id = H5Screate_simple(2, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'Points'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[2] = {100, 3}; + H5Pset_chunk(plist_id, 2, chunk_dims); + + hid_t dset_id = H5Dcreate( + group_id, "Points", + H5T_NATIVE_DOUBLE, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'Points'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + + } + + // ----------------------- + // 7) create Connectivity dataset "/VTKHDF/Connectivity" with shape (0,) and resizable (unlimited) + // ----------------------- + { + hsize_t dims[1] = {0}; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + hid_t space_id = H5Screate_simple(1, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'Connectivity'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[1] = {100}; + H5Pset_chunk(plist_id, 1, chunk_dims); + + hid_t dset_id = H5Dcreate( + group_id, "Connectivity", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'Connectivity'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + + } + + + // ----------------------- + // 8) create Offset dataset "/VTKHDF/Offsets" with shape (0,) and resizable (unlimited) + // ----------------------- + { + hsize_t dims[1] = {0}; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + hid_t space_id = H5Screate_simple(1, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'Offset'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[1] = {100}; + H5Pset_chunk(plist_id, 1, chunk_dims); + + hid_t dset_id = H5Dcreate( + group_id, "Offsets", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'Offset'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + + } + + // -------------------------------- + // 9) create the dataset VTKHDF/Types with shape (0,) and resizable (unlimited) + // -------------------------------- + { + hsize_t dims[1] = {0}; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + hid_t space_id = H5Screate_simple(1, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'Types'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[1] = {100}; + H5Pset_chunk(plist_id, 1, chunk_dims); + + hid_t dset_id = H5Dcreate( + group_id, "Types", + H5T_NATIVE_UCHAR, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'Types'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + + } + + + // -------------------------------- + // 10) create a steps group "/VTKHDF/steps" + // -------------------------------- + steps_group = H5Gcreate(group_id, "/VTKHDF/Steps", + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (steps_group < 0) { + opserr << "Error: Could not create group '/VTKHDF/steps' in HDF5 file " << name << endln; + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + + // -------------------------------- + // 11) create NSteps attribute for steps group and set it zero + // -------------------------------- + // Create a dataspace for a single integer + { + // Create NSteps attribute + const char* attr_name = "NSteps"; + hsize_t dims[1] = {1}; + hid_t nsteps_dataspace_id = H5Screate_simple(1, dims, nullptr); + hid_t nsteps_attr_id = H5Acreate(steps_group, + attr_name, + H5T_NATIVE_INT, + nsteps_dataspace_id, + H5P_DEFAULT, + H5P_DEFAULT); + + int nsteps_data = 0; + herr_t status = H5Awrite(nsteps_attr_id, H5T_NATIVE_INT, &nsteps_data); + + // Check overall success and cleanup + if (nsteps_dataspace_id < 0 || nsteps_attr_id < 0 || status < 0) { + opserr << "Error: Failed to initialize 'NSteps' attribute in file " << name << endln; + if (nsteps_attr_id >= 0) H5Aclose(nsteps_attr_id); + if (nsteps_dataspace_id >= 0) H5Sclose(nsteps_dataspace_id); + if (steps_group >= 0) H5Gclose(steps_group); + if (group_id >= 0) H5Gclose(group_id); + if (file_id >= 0) H5Fclose(file_id); + return; + } + + // Clean up handles + H5Aclose(nsteps_attr_id); + H5Sclose(nsteps_dataspace_id); + } + + // -------------------------------- + // 12) + // create groups NumberOfPoints and NumberOfCells + // and NumberOfConnectivityIds with + // resizable length zero shape + // Create NumberOfPoints dataset + // -------------------------------- + { + hsize_t dims[1] = {0}; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + hid_t space_id = H5Screate_simple(1, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'NumberOfPoints'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[1] = {1}; + H5Pset_chunk(plist_id, 1, chunk_dims); + + hid_t dset_id = H5Dcreate( + group_id, "NumberOfPoints", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'NumberOfPoints'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + } + + // Create NumberOfCells dataset + { + hsize_t dims[1] = {0}; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + hid_t space_id = H5Screate_simple(1, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'NumberOfCells'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[1] = {1}; + H5Pset_chunk(plist_id, 1, chunk_dims); + + hid_t dset_id = H5Dcreate( + group_id, "NumberOfCells", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'NumberOfCells'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + } + + // Create NumberOfConnectivityIds dataset + { + hsize_t dims[1] = {0}; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + hid_t space_id = H5Screate_simple(1, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'NumberOfConnectivityIds'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[1] = {1}; + H5Pset_chunk(plist_id, 1, chunk_dims); + + hid_t dset_id = H5Dcreate( + group_id, "NumberOfConnectivityIds", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'NumberOfConnectivityIds'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + } + + + // ----------------------- + // 13) + // create the dataset VTKHDF/Steps/PointOffsets with shape (0) and resizable + // create the dataset VTKHDF/Steps/Values with shape (0) and resizable + // create the dataset VTKHDF/Steps/PartOffsets with shape (0) and resizable + // create the dataset VTKHDF/Steps/NumberOfParts with shape (0) and resizable + // ----------------------- + // Create PointOffsets dataset + { + hsize_t dims[1] = {0}; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + hid_t space_id = H5Screate_simple(1, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'PointOffsets'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[1] = {1}; + H5Pset_chunk(plist_id, 1, chunk_dims); + + hid_t dset_id = H5Dcreate( + steps_group, "PointOffsets", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'PointOffsets'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + } + + // Create Values dataset + { + hsize_t dims[1] = {0}; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + hid_t space_id = H5Screate_simple(1, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'Values'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[1] = {1}; + H5Pset_chunk(plist_id, 1, chunk_dims); + + hid_t dset_id = H5Dcreate( + steps_group, "Values", + H5T_NATIVE_DOUBLE, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'Values'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + } + + // Create PartOffsets dataset + { + hsize_t dims[1] = {0}; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + hid_t space_id = H5Screate_simple(1, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'PartOffsets'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[1] = {1}; + H5Pset_chunk(plist_id, 1, chunk_dims); + + hid_t dset_id = H5Dcreate( + steps_group, "PartOffsets", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'PartOffsets'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + } + + // Create NumberOfParts dataset + { + hsize_t dims[1] = {0}; + hsize_t maxdims[1] = {H5S_UNLIMITED}; + hid_t space_id = H5Screate_simple(1, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'NumberOfParts'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[1] = {100}; + H5Pset_chunk(plist_id, 1, chunk_dims); + + hid_t dset_id = H5Dcreate( + steps_group, "NumberOfParts", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'NumberOfParts'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + } + + // -------------------------------- + // 14) + // create dataset VTKHDF/Steps/CellOffsets with shape (0,1) and resizable (unlimited,1) + // create dataset VTKHDF/Steps/ConnectivityIdOffsets with shape (0,1) and resizable (unlimited,1) + // -------------------------------- + // Create CellOffsets dataset + { + hsize_t dims[2] = {0, 1}; + hsize_t maxdims[2] = {H5S_UNLIMITED, 1}; + hid_t space_id = H5Screate_simple(2, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'CellOffsets'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[2] = {1, 1}; + H5Pset_chunk(plist_id, 2, chunk_dims); + + hid_t dset_id = H5Dcreate( + steps_group, "CellOffsets", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'CellOffsets'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + } + + + // Create ConnectivityIdOffsets dataset + { + hsize_t dims[2] = {0, 1}; + hsize_t maxdims[2] = {H5S_UNLIMITED, 1}; + hid_t space_id = H5Screate_simple(2, dims, maxdims); + if (space_id < 0) { + opserr << "Error creating dataspace for 'ConnectivityIdOffsets'\n"; + return; + } + + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + hsize_t chunk_dims[2] = {1, 1}; + H5Pset_chunk(plist_id, 2, chunk_dims); + + hid_t dset_id = H5Dcreate( + steps_group, "ConnectivityIdOffsets", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + if (dset_id < 0) { + opserr << "Error creating dataset 'ConnectivityIdOffsets'\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + H5Pclose(plist_id); + H5Dclose(dset_id); + } + + // -------------------------------- + // 15) + // create group VTKHDF/Steps/PointDataOffsets + // create group VTKHDF/Steps/CellDataOffsets + // create group VTKHDF/Steps/FieldDataOffsets + // create group VTKHDF/Steps/FieldDataSizes + // -------------------------------- + // Create PointDataOffsets group + { + point_data_offsets_group = H5Gcreate(steps_group, "PointDataOffsets", + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (point_data_offsets_group < 0) { + opserr << "Error: Could not create group '/VTKHDF/Steps/PointDataOffsets' in HDF5 file " << name << endln; + H5Gclose(steps_group); + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + } + + // Create CellDataOffsets group + { + cell_data_offsets_group = H5Gcreate(steps_group, "CellDataOffsets", + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (cell_data_offsets_group < 0) { + opserr << "Error: Could not create group '/VTKHDF/Steps/CellDataOffsets' in HDF5 file " << name << endln; + H5Gclose(steps_group); + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + } + + // Create FieldDataOffsets group + { + hid_t field_data_offsets_group = H5Gcreate(steps_group, "FieldDataOffsets", + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (field_data_offsets_group < 0) { + opserr << "Error: Could not create group '/VTKHDF/Steps/FieldDataOffsets' in HDF5 file " << name << endln; + H5Gclose(steps_group); + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + } + + // Create FieldDataSizes group + { + hid_t field_data_sizes_group = H5Gcreate(steps_group, "FieldDataSizes", + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (field_data_sizes_group < 0) { + opserr << "Error: Could not create group '/VTKHDF/Steps/FieldDataSizes' in HDF5 file " << name << endln; + H5Gclose(steps_group); + H5Gclose(group_id); + H5Fclose(file_id); + return; + } + } + + // -------------------------------- + // 16) + // check if displacement is requested create displacement dataset under PointDataOffsets + // Create dataset for displacement if requested + // -------------------------------- + if (outputData.disp) { + // Define initial dimensions as 0 since we don't know the number of nodes yet + hsize_t dims[1] = {0}; // Initial size (0 rows) + hsize_t max_dims[1] = {H5S_UNLIMITED}; // Maximum size (unlimited rows) + + // Create a dataspace with these dimensions + hid_t space_id = H5Screate_simple(1, dims, max_dims); + if (space_id < 0) { + opserr << "Error creating dataspace for displacement data\n"; + return; + } + + // Create a property list for chunked storage + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + if (plist_id < 0) { + opserr << "Error creating property list for displacement dataset\n"; + H5Sclose(space_id); + return; + } + + // Define the chunk size (e.g., 100 rows per chunk) + hsize_t chunk_dims[1] = {100}; + if (H5Pset_chunk(plist_id, 1, chunk_dims) < 0) { + opserr << "Error setting chunk size for displacement dataset\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Create the dataset with chunked storage + hid_t dset_id = H5Dcreate( + point_data_offsets_group, "displacement", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + + if (dset_id < 0) { + opserr << "Error creating dataset for displacement\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Clean up + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + } + + // check if displacement is requested create pointData group for displacement + // Create group for displacement if requested + if (outputData.disp) { + + // Define initial dimensions as 0 since we don't know the number of nodes yet + hsize_t dims[2] = {0, 3}; // Initial size (0 rows, 3 columns) + hsize_t max_dims[2] = {H5S_UNLIMITED, 3}; // Maximum size (unlimited rows, fixed 3 columns) + + // Create a dataspace with these dimensions + hid_t space_id = H5Screate_simple(2, dims, max_dims); + if (space_id < 0) { + opserr << "Error creating dataspace for displacement data\n"; + return; + } + + // Create a property list for chunked storage + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + if (plist_id < 0) { + opserr << "Error creating property list for displacement dataset\n"; + H5Sclose(space_id); + return; + } + + // Define the chunk size (e.g., 100 rows per chunk) + hsize_t chunk_dims[2] = {100, 3}; + if (H5Pset_chunk(plist_id, 2, chunk_dims) < 0) { + opserr << "Error setting chunk size for displacement dataset\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Create the dataset with chunked storage + hid_t dset_id = H5Dcreate( + point_data_group, "displacement", + H5T_NATIVE_DOUBLE, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + + if (dset_id < 0) { + opserr << "Error creating dataset for displacement\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Clean up + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + } + + // check if the acceleration is requested create offset dataset under PointDataOffsets + // Create dataset for acceleration if requested + if (outputData.accel) { + // Define initial dimensions as 0 since we don't know the number of nodes yet + hsize_t dims[1] = {0}; // Initial size (0 rows) + hsize_t max_dims[1] = {H5S_UNLIMITED}; // Maximum size (unlimited rows) + + // Create a dataspace with these dimensions + hid_t space_id = H5Screate_simple(1, dims, max_dims); + if (space_id < 0) { + opserr << "Error creating dataspace for acceleration data\n"; + return; + } + + // Create a property list for chunked storage + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + if (plist_id < 0) { + opserr << "Error creating property list for acceleration dataset\n"; + H5Sclose(space_id); + return; + } + + // Define the chunk size (e.g., 100 rows per chunk) + hsize_t chunk_dims[1] = {100}; + if (H5Pset_chunk(plist_id, 1, chunk_dims) < 0) { + opserr << "Error setting chunk size for acceleration dataset\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Create the dataset with chunked storage + hid_t dset_id = H5Dcreate( + point_data_offsets_group, "acceleration", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + + if (dset_id < 0) { + opserr << "Error creating dataset for acceleration\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Clean up + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + } + + // check if the acceleration is requested create pointData group for acceleration + // Create group for acceleration if requested + if (outputData.accel) { + + // Define initial dimensions as 0 since we don't know the number of nodes yet + hsize_t dims[2] = {0, 3}; // Initial size (0 rows, 3 columns) + hsize_t max_dims[2] = {H5S_UNLIMITED, 3}; // Maximum size (unlimited rows, fixed 3 columns) + + // Create a dataspace with these dimensions + hid_t space_id = H5Screate_simple(2, dims, max_dims); + if (space_id < 0) { + opserr << "Error creating dataspace for acceleration data\n"; + return; + } + + // Create a property list for chunked storage + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + if (plist_id < 0) { + opserr << "Error creating property list for acceleration dataset\n"; + H5Sclose(space_id); + return; + } + + // Define the chunk size (e.g., 100 rows per chunk) + hsize_t chunk_dims[2] = {100, 3}; + if (H5Pset_chunk(plist_id, 2, chunk_dims) < 0) { + opserr << "Error setting chunk size for acceleration dataset\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Create the dataset with chunked storage + hid_t dset_id = H5Dcreate( + point_data_group, "acceleration", + H5T_NATIVE_DOUBLE, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + + if (dset_id < 0) { + opserr << "Error creating dataset for acceleration\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Clean up + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + } + + // check if the velocity is requested create offset dataset under PointDataOffsets + // Create dataset for velocity if requested + if (outputData.vel) { + // Define initial dimensions as 0 since we don't know the number of nodes yet + hsize_t dims[1] = {0}; // Initial size (0 rows) + hsize_t max_dims[1] = {H5S_UNLIMITED}; // Maximum size (unlimited rows) + + // Create a dataspace with these dimensions + hid_t space_id = H5Screate_simple(1, dims, max_dims); + if (space_id < 0) { + opserr << "Error creating dataspace for velocity data\n"; + return; + } + + // Create a property list for chunked storage + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + if (plist_id < 0) { + opserr << "Error creating property list for velocity dataset\n"; + H5Sclose(space_id); + return; + } + + // Define the chunk size (e.g., 100 rows per chunk) + hsize_t chunk_dims[1] = {100}; + if (H5Pset_chunk(plist_id, 1, chunk_dims) < 0) { + opserr << "Error setting chunk size for velocity dataset\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Create the dataset with chunked storage + hid_t dset_id = H5Dcreate( + point_data_offsets_group, "velocity", + H5T_NATIVE_INT, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + + if (dset_id < 0) { + opserr << "Error creating dataset for velocity\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Clean up + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + } + + // check if the velocity is requested create pointData group for velocity + // Create group for velocity if requested + if (outputData.vel) { + + // Define initial dimensions as 0 since we don't know the number of nodes yet + hsize_t dims[2] = {0, 3}; // Initial size (0 rows, 3 columns) + hsize_t max_dims[2] = {H5S_UNLIMITED, 3}; // Maximum size (unlimited rows, fixed 3 columns) + + // Create a dataspace with these dimensions + hid_t space_id = H5Screate_simple(2, dims, max_dims); + if (space_id < 0) { + opserr << "Error creating dataspace for velocity data\n"; + return; + } + + // Create a property list for chunked storage + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + if (plist_id < 0) { + opserr << "Error creating property list for velocity dataset\n"; + H5Sclose(space_id); + return; + } + + // Define the chunk size (e.g., 100 rows per chunk) + hsize_t chunk_dims[2] = {100, 3}; + if (H5Pset_chunk(plist_id, 2, chunk_dims) < 0) { + opserr << "Error setting chunk size for velocity dataset\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Create the dataset with chunked storage + hid_t dset_id = H5Dcreate( + point_data_group, "velocity", + H5T_NATIVE_DOUBLE, + space_id, + H5P_DEFAULT, plist_id, H5P_DEFAULT + ); + + if (dset_id < 0) { + opserr << "Error creating dataset for velocity\n"; + H5Pclose(plist_id); + H5Sclose(space_id); + return; + } + + // Clean up + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id); + } + + + + if (outputData.stress3D6) { + int res = 0; + // Create 3DStress6 dataset + const char* dataset_name = "stress3D6"; + hsize_t ncols = 6; + hsize_t chunk_rows = 500; + hid_t type_id = H5T_NATIVE_DOUBLE; + hsize_t max_rows = H5S_UNLIMITED; + res = this->createDataset(cell_data_group, dataset_name, ncols, chunk_rows, type_id, max_rows); + + + // Create 3DStress6 offset dataset + dataset_name = "stress3D6"; + ncols = 1; + chunk_rows = 500; + type_id = H5T_NATIVE_INT; + max_rows = H5S_UNLIMITED; + // res += this->createDataset(cell_data_offsets_group, dataset_name, ncols, chunk_rows, type_id, max_rows); + res += this->createOffsetDataset(cell_data_offsets_group, dataset_name, chunk_rows, type_id, max_rows); + + current_Stress3D6Offset = 0; + if (res < 0) { + opserr << "Error creating 3DStress6 datasets\n"; + return; + } + } + + + if (outputData.strain3D6) { + int res = 0; + // Create 3DStrain6 dataset + const char* dataset_name = "strain3D6"; + hsize_t ncols = 6; + hsize_t chunk_rows = 500; + hid_t type_id = H5T_NATIVE_DOUBLE; + hsize_t max_rows = H5S_UNLIMITED; + res = this->createDataset(cell_data_group, dataset_name, ncols, chunk_rows, type_id, max_rows); + + // Create 3DStrain6 offset dataset + dataset_name = "strain3D6"; + ncols = 1; + chunk_rows = 500; + type_id = H5T_NATIVE_INT; + max_rows = H5S_UNLIMITED; + // res += this->createDataset(cell_data_offsets_group, dataset_name, ncols, chunk_rows, type_id, max_rows); + res += this->createOffsetDataset(cell_data_offsets_group, dataset_name, chunk_rows, type_id, max_rows); + + current_Strain3D6Offset = 0; + if (res < 0) { + opserr << "Error creating 3DStrain6 datasets\n"; + return; + } + } + if (outputData.stress2D3) { + int res = 0; + // Create 2DStress3 dataset + const char* dataset_name = "stress2D3"; + hsize_t ncols = 3; + hsize_t chunk_rows = 500; + hid_t type_id = H5T_NATIVE_DOUBLE; + hsize_t max_rows = H5S_UNLIMITED; + res = this->createDataset(cell_data_group, dataset_name, ncols, chunk_rows, type_id, max_rows); + + // Create 2DStress3 offset dataset + dataset_name = "stress2D3"; + ncols = 1; + chunk_rows = 500; + type_id = H5T_NATIVE_INT; + max_rows = H5S_UNLIMITED; + res += this->createOffsetDataset(cell_data_offsets_group, dataset_name, chunk_rows, type_id, max_rows); + + + current_Stress2D3Offset = 0; + if (res < 0) { + opserr << "Error creating 2DStress3 datasets\n"; + return; + } + } + + if (outputData.strain2D3) { + int res = 0; + // Create 2DStrain3 dataset + const char* dataset_name = "strain2D3"; + hsize_t ncols = 3; + hsize_t chunk_rows = 500; + hid_t type_id = H5T_NATIVE_DOUBLE; + hsize_t max_rows = H5S_UNLIMITED; + res = this->createDataset(cell_data_group, dataset_name, ncols, chunk_rows, type_id, max_rows); + + // Create 2DStrain3 offset dataset + dataset_name = "strain2D3"; + ncols = 1; + chunk_rows = 500; + type_id = H5T_NATIVE_INT; + max_rows = H5S_UNLIMITED; + res += this->createOffsetDataset(cell_data_offsets_group, dataset_name, chunk_rows, type_id, max_rows); + + current_Strain2D3Offset = 0; + if (res < 0) { + opserr << "Error creating 2DStrain3 datasets\n"; + return; + } + } + + + + + + current_PointOffset = 0; + current_CellOffset = 0; + current_ConnectivityIdOffset = 0; + current_PartOffset = 0; + + next_PointOffset = 0; + next_CellOffset = 0; + next_ConnectivityIdOffset = 0; + next_PartOffset = 0; + + + initDone = false; + numSteps = 0; // opserr << "initilization done\n"; + CurrentDispOffset = 0; + CurrentVelOffset = 0; + CurrentAccelOffset = 0; + + // Enable SWMR mode for concurrent reading + if (H5Fstart_swmr_write(file_id) < 0) { + opserr << "Warning: Could not enable SWMR write mode for " << name << endln; + opserr << " File will still be created but concurrent reading may not work optimally" << endln; + } + +} + + + + + +VTKHDF_Recorder::VTKHDF_Recorder() + :Recorder(RECORDER_TAGS_VTKHDF_Recorder), + theDomain(0), + nextTimeStampToRecord(0.0), + deltaT(0.0), + relDeltaTTol(0.00001), + counter(0), + initializationDone(false) +{ + name = NULL; + VTKHDF_Recorder::setVTKType(); + initDone = false; + +} + + +int VTKHDF_Recorder::writeMesh() { + // 1) Check domain + if (theDomain == nullptr) { + opserr << "WARNING: No domain found -- VTKHDF_Recorder::writeMesh\n"; + return -1; + } + + // Clear old data structures (if you store them as class members) + theNodeMapping.clear(); + theEleMapping.clear(); + theNodeTags.clear(); + theEleTags.clear(); + theEleClassTags.clear(); + theEleVtkTags.clear(); + theEleVtkOffsets.clear(); + + // 2) Gather node info + NodeIter &theNodes = theDomain->getNodes(); + Node *theNode; + numNode = 0; + maxNDM = 0; // max spatial dimension + maxNDF = 0; // max degrees of freedom + + while ((theNode = theNodes()) != nullptr) { + int nodeTag = theNode->getTag(); + + const Vector &crd = theNode->getCrds(); + if (crd.Size() > maxNDM) { + maxNDM = crd.Size(); + } + + const Vector &disp = theNode->getTrialDisp(); + if (disp.Size() > maxNDF) { + maxNDF = disp.Size(); + } + + // Build mapping (nodeTag -> index) + theNodeMapping[nodeTag] = numNode; + theNodeTags.push_back(nodeTag); + numNode++; + } + + // 3) Gather element info + ElementIter &theElements = theDomain->getElements(); + Element *theElement; + numElement = 0; + numConnectivityIds = 0; + + theEleVtkOffsets.push_back(numConnectivityIds); + while ((theElement = theElements()) != nullptr) { + int eleTag = theElement->getTag(); + int classTag = theElement->getClassTag(); + + // Check if recognized by our VTK type map + auto it = vtktypes.find(classTag); + if (it != vtktypes.end()) { + int vtkType = it->second; + + theEleMapping[eleTag] = numElement; + theEleTags.push_back(eleTag); + theEleClassTags.push_back(classTag); + theEleVtkTags.push_back(vtkType); + + const ID &extNodes = theElement->getExternalNodes(); + int nN = extNodes.Size(); + + // Offsets array is cumulative + numConnectivityIds += nN; + theEleVtkOffsets.push_back(numConnectivityIds); + + numElement++; + } else { + // Possibly skip subdomains or warn for unrecognized element + if (classTag != ELE_TAG_Subdomain) { + opserr << "VTKHDF_Recorder::writeMesh - unknown vtk type for element " + << eleTag << " (classTag=" << classTag << ")" << endln; + } + } + } + + // ------------------------------------------------------------- + // 4) Build arrays for HDF5 + // ------------------------------------------------------------- + + // (A) Points => shape (numNode,3) + std::vector pointsData(numNode * 3, 0.0); + { + NodeIter &theNodes2 = theDomain->getNodes(); + while ((theNode = theNodes2()) != nullptr) { + int nodeTag = theNode->getTag(); + int mappedIndex = theNodeMapping[nodeTag]; + const Vector &crd = theNode->getCrds(); + + pointsData[3 * mappedIndex + 0] = (crd.Size() > 0) ? crd(0) : 0.0; + pointsData[3 * mappedIndex + 1] = (crd.Size() > 1) ? crd(1) : 0.0; + pointsData[3 * mappedIndex + 2] = (crd.Size() > 2) ? crd(2) : 0.0; + } + } + + // (B) Connectivity => shape (numConnectivityIds) + std::vector connectivity(numConnectivityIds); + { + ElementIter &theElements2 = theDomain->getElements(); + int idx = 0; + while ((theElement = theElements2()) != nullptr) { + int classTag = theElement->getClassTag(); + if (vtktypes.find(classTag) != vtktypes.end()) { + const ID &extNodes = theElement->getExternalNodes(); + for (int i = 0; i < extNodes.Size(); i++) { + int nodeTag = extNodes(i); + connectivity[idx++] = static_cast(theNodeMapping[nodeTag]); + } + } + } + } + + // (C) Offsets => shape (numElement+1,1) so that ParaView can read it + std::vector offsets(theEleVtkOffsets.begin(), theEleVtkOffsets.end()); + + + // (D) Types => shape (numElement) + std::vector types(theEleVtkTags.begin(), theEleVtkTags.end()); + + // opserr << " Gathering data done\n"; + // ------------------------------------------------------------- + // 5) Open group "/VTKHDF" from the already opened file_id + // ------------------------------------------------------------- + // Make sure file_id is still valid (i.e., not closed in constructor). + hid_t vtkhdfGroup = H5Gopen(file_id, "/VTKHDF", H5P_DEFAULT); + if (vtkhdfGroup < 0) { + opserr << "Error: Could not open group '/VTKHDF' in file to write mesh.\n"; + return -1; + } + + // ------------------------------------------------------------- + // 6) resize the Point and add the points data + // ------------------------------------------------------------- + { + // Open the existing dataset + hid_t dset_id = H5Dopen(vtkhdfGroup, "Points", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset 'Points'\n"; + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for 'Points'\n"; + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the current dimensions + hsize_t current_dims[2]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Calculate new dimensions (current rows + new rows, same columns) + hsize_t new_dims[2] = {current_dims[0] + static_cast(numNode), 3}; + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for 'Points'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for 'Points'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Select the hyperslab where we want to write new data + hsize_t offset[2] = {current_dims[0], 0}; // Start from the end of existing data + hsize_t count[2] = {static_cast(numNode), 3}; // Size of new data + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(2, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for 'Points'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Write only the new data + if (H5Dwrite(dset_id, H5T_NATIVE_DOUBLE, mem_space_id, new_space_id, H5P_DEFAULT, pointsData.data()) < 0) { + opserr << "Error writing data to 'Points'\n"; + } + + // Close all resources + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + + } + // opserr << "Points done\n"; + + + // ------------------------------------------------------------- + // 7) resize the Connectivity and add the connectivity data + // ------------------------------------------------------------- + { + // Open the existing dataset + hid_t dset_id = H5Dopen(vtkhdfGroup, "Connectivity", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset 'Connectivity'\n"; + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for 'Connectivity'\n"; + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the current dimensions + hsize_t current_dims[1]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Calculate new dimensions (current rows + new rows, same columns) + hsize_t new_dims[1] = {current_dims[0] + static_cast(numConnectivityIds)}; + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for 'Connectivity'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for 'Connectivity'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Select the hyperslab where we want to write new data + hsize_t offset[1] = {current_dims[0]}; // Start from the end of existing data + hsize_t count[1] = {static_cast(numConnectivityIds)}; // Size of new data + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(1, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for 'Connectivity'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Write only the new data + if (H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space_id, new_space_id, H5P_DEFAULT, connectivity.data()) < 0) { + opserr << "Error writing data to 'Connectivity'\n"; + } + + // Close all resources + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + } + // opserr << "Connectivity done\n"; + + // ------------------------------------------------------------- + // 8) resize the Offsets and add the offsets data + // ------------------------------------------------------------- + { + // Open the existing dataset + hid_t dset_id = H5Dopen(vtkhdfGroup, "Offsets", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset 'Offsets'\n"; + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for 'Offsets'\n"; + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the current dimensions + hsize_t current_dims[1]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Calculate new dimensions (current rows + new rows, same columns) + hsize_t new_dims[1] = {current_dims[0] + static_cast(numElement+1)}; + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for 'Offsets'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for 'Offsets'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Select the hyperslab where we want to write new data + hsize_t offset[1] = {current_dims[0]}; // Start from the end of existing data + hsize_t count[1] = {static_cast(numElement+1)}; // Size of new data + + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(1, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for 'Offsets'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Write only the new data + if (H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space_id, new_space_id, H5P_DEFAULT, offsets.data()) < 0) { + opserr << "Error writing data to 'Offsets'\n"; + } + + // Close all resources + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + } + // opserr << "Offsets done\n"; + + + // ------------------------------------------------------------- + // 9) resize the Types and add the types data + // ------------------------------------------------------------- + { + // Open the existing dataset + hid_t dset_id = H5Dopen(vtkhdfGroup, "Types", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset 'Types'\n"; + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for 'Types'\n"; + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the current dimensions + hsize_t current_dims[1]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Calculate new dimensions (current rows + new rows, same columns) + hsize_t new_dims[1] = {current_dims[0] + static_cast(numElement)}; + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for 'Types'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for 'Types'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Select the hyperslab where we want to write new data + hsize_t offset[1] = {current_dims[0]}; // Start from the end of existing data + hsize_t count[1] = {static_cast(numElement)}; // Size of new data + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(1, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for 'Types'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + H5Gclose(vtkhdfGroup); + return -1; + } + + // Write only the new data + if (H5Dwrite(dset_id, H5T_NATIVE_UCHAR, mem_space_id, new_space_id, H5P_DEFAULT, types.data()) < 0) { + opserr << "Error writing data to 'Types'\n"; + } + + // Close all resources + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + } + // opserr << "Types done\n"; + H5Gclose(vtkhdfGroup); + + // ------------------------------------------------------------- + // 10 ) update the current offsets + // ------------------------------------------------------------- + // for having a changing mesh you may need to adjust this ofsset + // espically current_ConnectivityIdOffset and current_CellOffset + // right now we are assuming that the mesh is not changing + + + current_PointOffset = next_PointOffset; + current_CellOffset = next_CellOffset; + current_ConnectivityIdOffset = next_ConnectivityIdOffset; + current_PartOffset = next_PartOffset; + + next_PointOffset = current_PointOffset + numNode; + next_CellOffset = current_CellOffset + 0; + next_ConnectivityIdOffset = current_ConnectivityIdOffset + 0; + next_PartOffset = current_PartOffset + 0; + + + // ------------------------------------------------------------- + // 11 ) Edit specific recorders information + // ------------------------------------------------------------- + // 3DStress6 + + if (outputData.stress3D6) { + opserr << "Setting up stress3D6 responses\n"; + stress3D6Responses.clear(); + stress3D6Responses.reserve(numElement); + for (auto i: theEleTags) { + Element *theElement = theDomain->getElement(i); + SilentStream theOutputHandler; + const char* args[] = {"stress3D6"}; + Response *theResponse = theElement->setResponse(args, 1, theOutputHandler); + stress3D6Responses.push_back(theResponse); + } + } + + // 3DStrain6 + if (outputData.strain3D6) { + opserr << "Setting up strain3D6 responses\n"; + strain3D6Responses.clear(); + strain3D6Responses.reserve(numElement); + for (auto i: theEleTags) { + Element *theElement = theDomain->getElement(i); + SilentStream theOutputHandler; + const char* args[] = {"strain3D6"}; + Response *theResponse = theElement->setResponse(args, 1, theOutputHandler); + strain3D6Responses.push_back(theResponse); + } + } + + // 2DStress3 + if (outputData.stress2D3) { + opserr << "Setting up stress2D3 responses\n"; + stress2D3Responses.clear(); + stress2D3Responses.reserve(numElement); + for (auto i: theEleTags) { + // const char* istring = std::to_string(i).c_str(); + // opserr << istring << endln; + Element *theElement = theDomain->getElement(i); + SilentStream theOutputHandler; + const char* args[] = {"stress2D3"}; + Response *theResponse = theElement->setResponse(args, 1, theOutputHandler); + stress2D3Responses.push_back(theResponse); + } + } + + // 2DStrain3 + if (outputData.strain2D3) { + opserr << "Setting up strain2D3 responses\n"; + strain2D3Responses.clear(); + strain2D3Responses.reserve(numElement); + for (auto i: theEleTags) { + Element *theElement = theDomain->getElement(i); + SilentStream theOutputHandler; + const char* args[] = {"strain2D3"}; + Response *theResponse = theElement->setResponse(args, 1, theOutputHandler); + strain2D3Responses.push_back(theResponse); + } + } + + + + // ------------------------------------------------------------- + // Mark that we've(re)written the mesh + // ------------------------------------------------------------- + initDone = true; + return 0; +} + + +int VTKHDF_Recorder::record(int commitTag, double timeStamp) +{ + H5Fflush(file_id, H5F_SCOPE_GLOBAL); + if (!initDone) { + this->writeMesh(); + } + + if (deltaT == 0.0 || timeStamp - nextTimeStampToRecord >= -deltaT * relDeltaTTol) { + if (this->writeStep(timeStamp) < 0) { + opserr << "VTKHDF_Recorder::record() - writeStep() failed\n"; + return -1; + } + + // // displacment + if (outputData.disp) { + // opserr<<"writeDisp"<writeDisp() < 0) { + opserr << "VTKHDF_Recorder::record() - writeDisp() failed\n"; + return -1; + } + } + + // // velocity + if (outputData.vel) { + // opserr<<"writeVel"<writeVel() < 0) { + opserr << "VTKHDF_Recorder::record() - writeVel() failed\n"; + return -1; + } + } + + // // acceleration + if (outputData.accel) { + // opserr<<"writeAccel"<writeAccel() < 0) { + opserr << "VTKHDF_Recorder::record() - writeAccel() failed\n"; + return -1; + } + } + + if (outputData.stress3D6) { + // opserr<<"writeStress3D"<writeStrees3D6() < 0) { + opserr << "VTKHDF_Recorder::record() - writeStress3D() failed\n"; + return -1; + } + } + + if (outputData.strain3D6) { + // opserr<<"writeStrain3D"<writeStrain3D6() < 0) { + opserr << "VTKHDF_Recorder::record() - writeStrain3D() failed\n"; + return -1; + } + } + + if (outputData.stress2D3) { + // opserr<<"writeStress2D"<writeStress2D3() < 0) { + opserr << "VTKHDF_Recorder::record() - writeStress2D() failed\n"; + return -1; + } + } + + if (outputData.strain2D3) { + // opserr<<"writeStrain2D"<writeStrain2D3() < 0) { + opserr << "VTKHDF_Recorder::record() - writeStrain2D() failed\n"; + return -1; + } + } + + if (deltaT != 0.0) { + nextTimeStampToRecord = timeStamp + deltaT; + } + } + H5Fflush(file_id, H5F_SCOPE_GLOBAL); + return 0; +} + + +int VTKHDF_Recorder::writeStress2D3(void) { + + std::vector stressData(numElement * 3, 0.0); + for (auto i: theEleTags) { + Element *theEle = theDomain->getElement(i); + int MappedIndex = theEleMapping[i]; + if (stress2D3Responses[MappedIndex] == 0) { + continue; + } + stress2D3Responses[MappedIndex]->getResponse(); + Information &info = stress2D3Responses[MappedIndex]->getInformation(); + const Vector &stress = info.getData(); + for (int j = 0; j < 3; j++) { + stressData[3 * MappedIndex + j] = stress(j); + } + } + + int res = 0; + res += this->extendDataset(cell_data_group, "stress2D3", stressData.data(), H5T_NATIVE_DOUBLE, numElement, 3); + res += this->extendOffsetDataset(cell_data_offsets_group, "stress2D3", ¤t_Stress2D3Offset, H5T_NATIVE_INT, 1); + current_Stress2D3Offset += numElement; + return res; +} + +int VTKHDF_Recorder::writeStrain2D3(void) { + + std::vector strainData(numElement * 3, 0.0); + for (auto i: theEleTags) { + Element *theEle = theDomain->getElement(i); + int MappedIndex = theEleMapping[i]; + if (strain2D3Responses[MappedIndex] == 0) { + continue; + } + strain2D3Responses[MappedIndex]->getResponse(); + Information &info = strain2D3Responses[MappedIndex]->getInformation(); + const Vector &strain = info.getData(); + for (int j = 0; j < 3; j++) { + strainData[3 * MappedIndex + j] = strain(j); + } + } + + int res = 0; + res += this->extendDataset(cell_data_group, "strain2D3", strainData.data(), H5T_NATIVE_DOUBLE, numElement, 3); + res += this->extendOffsetDataset(cell_data_offsets_group, "strain2D3", ¤t_Strain2D3Offset, H5T_NATIVE_INT, 1); + current_Strain2D3Offset += numElement; + return res; +} + +int VTKHDF_Recorder::writeStrees3D6(void) { + + std::vector stressData(numElement * 6, 0.0); + for (auto i: theEleTags) { + Element *theEle = theDomain->getElement(i); + int MappedIndex = theEleMapping[i]; + if (stress3D6Responses[MappedIndex]==0) { + continue; + } + stress3D6Responses[MappedIndex]->getResponse(); + Information &info = stress3D6Responses[MappedIndex]->getInformation(); + const Vector &stress = info.getData(); + for (int j = 0; j < 6; j++) { + stressData[6 * MappedIndex + j] = stress(j); + } + } + + int res = 0; + res += this->extendDataset(cell_data_group, "stress3D6", stressData.data(), H5T_NATIVE_DOUBLE, numElement, 6); + res += this->extendOffsetDataset(cell_data_offsets_group, "stress3D6", ¤t_Stress3D6Offset, H5T_NATIVE_INT, 1); + current_Stress3D6Offset += numElement; + return res; +} + + +int VTKHDF_Recorder::writeStrain3D6(void) { + + std::vector strainData(numElement * 6, 0.0); + for (auto i: theEleTags) { + Element *theEle = theDomain->getElement(i); + int MappedIndex = theEleMapping[i]; + if (strain3D6Responses[MappedIndex] == 0) { + continue; + } + strain3D6Responses[MappedIndex]->getResponse(); + Information &info = strain3D6Responses[MappedIndex]->getInformation(); + const Vector &strain = info.getData(); + for (int j = 0; j < 6; j++) { + strainData[6 * MappedIndex + j] = strain(j); + } + } + + int res = 0; + res += this->extendDataset(cell_data_group, "strain3D6", strainData.data(), H5T_NATIVE_DOUBLE, numElement, 6); + res += this->extendOffsetDataset(cell_data_offsets_group, "strain3D6", ¤t_Strain3D6Offset, H5T_NATIVE_INT, 1); + current_Strain3D6Offset += numElement; + return res; +} + +int VTKHDF_Recorder::writeVel(void) +{ + // write vel + std::vector velData(numNode * 3, 0.0); + for (auto i : theNodeTags) { + Node *theNode=theDomain->getNode(i); + const Vector &vel=theNode->getVel(); + int mappedIndex = theNodeMapping[i]; + int size = theNode->getCrds().Size(); + + velData[3 * mappedIndex + 0] = (size > 0) ? vel(0) : 0.0; + velData[3 * mappedIndex + 1] = (size > 1) ? vel(1) : 0.0; + velData[3 * mappedIndex + 2] = (size > 2) ? vel(2) : 0.0; + } + + { + // Open dataset in point_data_group and resize it to the new number of steps + hid_t dset_id = H5Dopen(point_data_group, "velocity", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset 'velocity'\n"; + return -1; + } + + // Get the current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for 'velocity'\n"; + H5Dclose(dset_id); + return -1; + } + + // Get the current dimensions + hsize_t current_dims[2]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Calculate new dimensions (current rows + new rows, same columns) + hsize_t new_dims[2] = {current_dims[0] + static_cast(numNode), 3}; + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for 'velocity'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for 'velocity'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Select the hyperslab where we want to write new data + hsize_t offset[2] = {current_dims[0], 0}; // Start from the end of existing data + hsize_t count[2] = {static_cast(numNode), 3}; // Size of new data + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(2, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for 'velocity'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Write only the new data + if (H5Dwrite(dset_id, H5T_NATIVE_DOUBLE, mem_space_id, new_space_id, H5P_DEFAULT, velData.data()) < 0) { + opserr << "Error writing data to 'velocity'\n"; + } + + // Close all resources + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + } + + { + // Open dataset in point_data_offsets_group and resize it to the new number of steps + hid_t dset_id = H5Dopen(point_data_offsets_group, "velocity", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset 'velocity'\n"; + return -1; + } + + // Get the current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for 'velocity'\n"; + H5Dclose(dset_id); + return -1; + } + + // Get the current dimensions + hsize_t current_dims[1]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Calculate new dimensions (current rows + new rows, same columns) + hsize_t new_dims[1] = {current_dims[0] + 1}; + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for 'velocity'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for 'velocity'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Select the hyperslab where we want to write new data + hsize_t offset[1] = {current_dims[0]}; // Start from the end of existing data + hsize_t count[1] = {1}; // Size of new data + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(1, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for 'velocity'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Write only the new data + if (H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space_id, new_space_id, H5P_DEFAULT, &CurrentVelOffset) < 0) { + opserr << "Error writing data to 'velocity'\n"; + } + + // Close all resources + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + } + + CurrentVelOffset += numNode; + return 0; +} + + +int VTKHDF_Recorder::writeAccel(void) +{ + // write accel + std::vector accelData(numNode * 3, 0.0); + for (auto i : theNodeTags) { + Node *theNode=theDomain->getNode(i); + const Vector &accel=theNode->getAccel(); + int mappedIndex = theNodeMapping[i]; + int size = theNode->getCrds().Size(); + + accelData[3 * mappedIndex + 0] = (size > 0) ? accel(0) : 0.0; + accelData[3 * mappedIndex + 1] = (size > 1) ? accel(1) : 0.0; + accelData[3 * mappedIndex + 2] = (size > 2) ? accel(2) : 0.0; + } + + { + // Open dataset in point_data_group and resize it to the new number of steps + hid_t dset_id = H5Dopen(point_data_group, "acceleration", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset 'acceleration'\n"; + return -1; + } + + // Get the current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for 'acceleration'\n"; + H5Dclose(dset_id); + return -1; + } + + // Get the current dimensions + hsize_t current_dims[2]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Calculate new dimensions (current rows + new rows, same columns) + hsize_t new_dims[2] = {current_dims[0] + static_cast(numNode), 3}; + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for 'acceleration'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for 'acceleration'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Select the hyperslab where we want to write new data + hsize_t offset[2] = {current_dims[0], 0}; // Start from the end of existing data + hsize_t count[2] = {static_cast(numNode), 3}; // Size of new data + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(2, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for 'acceleration'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Write only the new data + if (H5Dwrite(dset_id, H5T_NATIVE_DOUBLE, mem_space_id, new_space_id, H5P_DEFAULT, accelData.data()) < 0) { + opserr << "Error writing data to 'acceleration'\n"; + } + + // Close all resources + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + } + + { + // Open dataset in point_data_offsets_group and resize it to the new number of steps + hid_t dset_id = H5Dopen(point_data_offsets_group, "acceleration", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset 'acceleration'\n"; + return -1; + } + + // Get the current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for 'acceleration'\n"; + H5Dclose(dset_id); + return -1; + } + + // Get the current dimensions + hsize_t current_dims[1]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Calculate new dimensions (current rows + new rows, same columns) + hsize_t new_dims[1] = {current_dims[0] + 1}; + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for 'acceleration'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for 'acceleration'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Select the hyperslab where we want to write new data + hsize_t offset[1] = {current_dims[0]}; // Start from the end of existing data + hsize_t count[1] = {1}; // Size of new data + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(1, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for 'acceleration'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Write only the new data + if (H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space_id, new_space_id, H5P_DEFAULT, &CurrentAccelOffset) < 0) { + opserr << "Error writing data to 'acceleration'\n"; + } + + // Close all resources + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + } + + CurrentAccelOffset += numNode; + return 0; + +} + + +int VTKHDF_Recorder::writeDisp(void) +{ + // write disp + std::vector dispData(numNode * 3, 0.0); + for (auto i : theNodeTags) { + Node *theNode=theDomain->getNode(i); + const Vector &disp=theNode->getDisp(); + int mappedIndex = theNodeMapping[i]; + int size = theNode->getCrds().Size(); + + dispData[3 * mappedIndex + 0] = (size > 0) ? disp(0) : 0.0; + dispData[3 * mappedIndex + 1] = (size > 1) ? disp(1) : 0.0; + dispData[3 * mappedIndex + 2] = (size > 2) ? disp(2) : 0.0; + + } + + { + // Open dataset in point_data_group and resize it to the new number of steps + hid_t dset_id = H5Dopen(point_data_group, "displacement", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset 'displacement'\n"; + return -1; + } + + // Get the current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for 'displacement'\n"; + H5Dclose(dset_id); + return -1; + } + + // Get the current dimensions + hsize_t current_dims[2]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Calculate new dimensions (current rows + new rows, same columns) + hsize_t new_dims[2] = {current_dims[0] + static_cast(numNode), 3}; + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for 'displacement'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for 'displacement'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Select the hyperslab where we want to write new data + hsize_t offset[2] = {current_dims[0], 0}; // Start from the end of existing data + hsize_t count[2] = {static_cast(numNode), 3}; // Size of new data + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(2, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for 'displacement'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Write only the new data + if (H5Dwrite(dset_id, H5T_NATIVE_DOUBLE, mem_space_id, new_space_id, H5P_DEFAULT, dispData.data()) < 0) { + opserr << "Error writing data to 'displacement'\n"; + } + + // Close all resources + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + } + + + // write dispofsset into + { + // Open dataset in point_data_offsets_group and resize it to the new number of steps + hid_t dset_id = H5Dopen(point_data_offsets_group, "displacement", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset 'displacement'\n"; + return -1; + } + + // Get the current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for 'displacement'\n"; + H5Dclose(dset_id); + return -1; + } + + // Get the current dimensions + hsize_t current_dims[1]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Calculate new dimensions (current rows + new rows, same columns) + hsize_t new_dims[1] = {current_dims[0] + 1}; + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for 'displacement'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for 'displacement'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Select the hyperslab where we want to write new data + hsize_t offset[1] = {current_dims[0]}; // Start from the end of existing data + hsize_t count[1] = {1}; // Size of new data + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(1, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for 'displacement'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + + // Write only the new data + if (H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space_id, new_space_id, H5P_DEFAULT, &CurrentDispOffset) < 0) { + opserr << "Error writing data to 'displacement'\n"; + } + + // Close all resources + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + } + + // update the current offset + CurrentDispOffset += numNode; + return 0; +} + + + +int VTKHDF_Recorder::writeStep(double timeStamp) +{ + // Update numSteps and attribute + numSteps++; + const char* attr_name = "NSteps"; + + // Open and update NSteps attribute + hid_t attr_id = H5Aopen(steps_group, attr_name, H5P_DEFAULT); + if (attr_id < 0) { + opserr << "Error: Failed to open 'NSteps' attribute\n"; + return -1; + } + + H5Awrite(attr_id, H5T_NATIVE_INT, &numSteps); + H5Aclose(attr_id); + + // Values for each dataset + const int newNumberOfParts = 1; // Always one rank per recorder + const int newPointOffsets = current_PointOffset; + const int newCellOffsets = current_CellOffset; + const int newPartOffsets = current_PartOffset; + const int newConnectivityIdOffsets = current_ConnectivityIdOffset; + const double value = timeStamp; + const int newNumPoints = numNode; + const int newNumCells = numElement; + const int newNumberOfConnectivityIds = numConnectivityIds; + + + // Debug output (can be removed for production) + // opserr << " Number of parts: " << newNumberOfParts << endln; + // opserr << " Point offsets: " << newPointOffsets << endln; + // opserr << " Cell offsets: " << newCellOffsets << endln; + // opserr << " Part offsets: " << newPartOffsets << endln; + // opserr << " Value: " << value << endln; + // opserr << " Number of points: " << newNumPoints << endln; + // opserr << " Number of cells: " << newNumCells << endln; + // opserr << " Number of connectivity ids: " << newNumberOfConnectivityIds << endln; + + // Set up dimensions for dataset operations + hsize_t newSize[1] = {static_cast(numSteps)}; + hsize_t start[1] = {static_cast(numSteps - 1)}; + hsize_t count[1] = {1}; + + // NumberOfParts + { + hid_t dset_id = H5Dopen(steps_group, "NumberOfParts", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error: Failed to open 'NumberOfParts' dataset\n"; + return -1; + } + + H5Dset_extent(dset_id, newSize); + hid_t file_space = H5Dget_space(dset_id); + H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, NULL, count, NULL); + + // Create memory space and write data + hid_t mem_space = H5Screate_simple(1, count, NULL); + H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space, file_space, H5P_DEFAULT, &newNumberOfParts); + + // Clean up resources + H5Sclose(mem_space); + H5Sclose(file_space); + H5Dclose(dset_id); + } + // PointOffsets + { + hid_t dset_id = H5Dopen(steps_group, "PointOffsets", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error: Failed to open 'PointOffsets' dataset\n"; + return -1; + } + + H5Dset_extent(dset_id, newSize); + hid_t file_space = H5Dget_space(dset_id); + H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, NULL, count, NULL); + + // Create memory space and write data + hid_t mem_space = H5Screate_simple(1, count, NULL); + H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space, file_space, H5P_DEFAULT, &newPointOffsets); + + // Clean up resources + H5Sclose(mem_space); + H5Sclose(file_space); + H5Dclose(dset_id); + } + + // PartOffsets + { + hid_t dset_id = H5Dopen(steps_group, "PartOffsets", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error: Failed to open 'PartOffsets' dataset\n"; + return -1; + } + + H5Dset_extent(dset_id, newSize); + hid_t file_space = H5Dget_space(dset_id); + H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, NULL, count, NULL); + + // Create memory space and write data + hid_t mem_space = H5Screate_simple(1, count, NULL); + H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space, file_space, H5P_DEFAULT, &newPartOffsets); + + // Clean up resources + H5Sclose(mem_space); + H5Sclose(file_space); + H5Dclose(dset_id); + } + + // Values + { + hid_t dset_id = H5Dopen(steps_group, "Values", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error: Failed to open 'Values' dataset\n"; + return -1; + } + + H5Dset_extent(dset_id, newSize); + hid_t file_space = H5Dget_space(dset_id); + H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, NULL, count, NULL); + + // Create memory space and write data + hid_t mem_space = H5Screate_simple(1, count, NULL); + H5Dwrite(dset_id, H5T_NATIVE_DOUBLE, mem_space, file_space, H5P_DEFAULT, &value); + + // Clean up resources + H5Sclose(mem_space); + H5Sclose(file_space); + H5Dclose(dset_id); + } + + // NumberOfPoints + { + hid_t dset_id = H5Dopen(group_id, "NumberOfPoints", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error: Failed to open 'NumberOfPoints' dataset\n"; + return -1; + } + + H5Dset_extent(dset_id, newSize); + hid_t file_space = H5Dget_space(dset_id); + H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, NULL, count, NULL); + + // Create memory space and write data + hid_t mem_space = H5Screate_simple(1, count, NULL); + H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space, file_space, H5P_DEFAULT, &newNumPoints); + + // Clean up resources + H5Sclose(mem_space); + H5Sclose(file_space); + H5Dclose(dset_id); + } + // NumberOfCells + { + hid_t dset_id = H5Dopen(group_id, "NumberOfCells", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error: Failed to open 'NumberOfCells' dataset\n"; + return -1; + } + + H5Dset_extent(dset_id, newSize); + hid_t file_space = H5Dget_space(dset_id); + H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, NULL, count, NULL); + + // Create memory space and write data + hid_t mem_space = H5Screate_simple(1, count, NULL); + H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space, file_space, H5P_DEFAULT, &newNumCells); + + // Clean up resources + H5Sclose(mem_space); + H5Sclose(file_space); + H5Dclose(dset_id); + } + + // NumberOfConnectivityIds + { + hid_t dset_id = H5Dopen(group_id, "NumberOfConnectivityIds", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error: Failed to open 'NumberOfConnectivityIds' dataset\n"; + return -1; + } + + H5Dset_extent(dset_id, newSize); + hid_t file_space = H5Dget_space(dset_id); + H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start, NULL, count, NULL); + + // Create memory space and write data + hid_t mem_space = H5Screate_simple(1, count, NULL); + H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space, file_space, H5P_DEFAULT, &newNumberOfConnectivityIds); + + // Clean up resources + H5Sclose(mem_space); + H5Sclose(file_space); + H5Dclose(dset_id); + } + + // Handle CellOffsets dataset + { + // Set new dimensions for the current step + hsize_t newSize2[2] = {static_cast(numSteps), 1}; + hsize_t start2[2] = {static_cast(numSteps - 1), 0}; + hsize_t count2[2] = {1, 1}; + + // Open existing dataset + hid_t dset_id = H5Dopen(steps_group, "CellOffsets", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error: Failed to open 'CellOffsets' dataset\n"; + return -1; + } + + // Extend the dataset + H5Dset_extent(dset_id, newSize2); + + // Get the file space and select the hyperslab + hid_t file_space = H5Dget_space(dset_id); + H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start2, NULL, count2, NULL); + + // Create memory space for single value + hid_t mem_space = H5Screate_simple(2, count2, NULL); + + // Write the cell offset value + H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space, file_space, H5P_DEFAULT, &newCellOffsets); + + // Clean up + H5Sclose(mem_space); + H5Sclose(file_space); + H5Dclose(dset_id); + } + // Handle ConnectivityIdOffsets + { + // Set new dimensions for the current step + hsize_t newSize2[2] = {static_cast(numSteps), 1}; + hsize_t start2[2] = {static_cast(numSteps - 1), 0}; + hsize_t count2[2] = {1, 1}; + + // Open existing dataset + hid_t dset_id = H5Dopen(steps_group, "ConnectivityIdOffsets", H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error: Failed to open 'ConnectivityIdOffsets' dataset\n"; + return -1; + } + + // Extend the dataset + H5Dset_extent(dset_id, newSize2); + + // Get the file space and select the hyperslab + hid_t file_space = H5Dget_space(dset_id); + H5Sselect_hyperslab(file_space, H5S_SELECT_SET, start2, NULL, count2, NULL); + + // Create memory space for single value + hid_t mem_space = H5Screate_simple(2, count2, NULL); + + // Write the connectivity id offset value + H5Dwrite(dset_id, H5T_NATIVE_INT, mem_space, file_space, H5P_DEFAULT, &newConnectivityIdOffsets); + + // Clean up + H5Sclose(mem_space); + H5Sclose(file_space); + H5Dclose(dset_id); + } + + + return 0; +} + + +int VTKHDF_Recorder::restart(void) +{ + return 0; +} + +int VTKHDF_Recorder::domainChanged(void) +{ + opserr << "Warning: VTKHDF_Recorder::domainChanged() - This recorder does not support domain changes yet.\n"; + opserr << "if you changed the domain, you need to create a new recorder.\n"; + opserr << "if you just used the domainChanged() mesthod without changing the domain, you can ignore this warning.\n"; + this->writeMesh(); + return -1; +} + +int VTKHDF_Recorder::setDomain(Domain &domain) +{ + theDomain = &domain; + return 0; +} + +int VTKHDF_Recorder::sendSelf(int commitTag, Channel &theChannel) +{ + // Implementation for sending data + return 0; +} + +int VTKHDF_Recorder::recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker) +{ + // Implementation for receiving data + return 0; +} + + + + + +// int VTKHDF_Recorder::writeStep_stress3D6() { +// /* +// This function is used to write the 3D stress data to the HDF5 file. The function writes the following: + +// 1) collect the 3D stress data from the elements +// 2) Write the 3D stress data to the dataset "3DStress6" under group "/VTKHDF/CellData" in the HDF5 file +// 3) Write the offset to the dataset "3DStress6" under group "/VTKHDF/Steps/CellDataOffsets" in the HDF5 file +// */ + +// // 1) Collect the 3D stress data from the elements +// std::vector stress(numElement * 6, 0.0); + +// // std::vector velData(numNode * 3, 0.0); +// { +// for (auto i : theEleTags) { +// Element *theElement = theDomain->getElement(i); +// int mappedIndex = theEleMapping[i]; + +// int classTag = theElement->getClassTag(); + +// if (classTag == ELE_TAG_STDQUADUP) { +// // stdQuadUP +// Vector stressVec(6); +// Information &eleInfo = +// theElement->getResponse(1, stressVec); +// theElement->getResponse(1,) + +// } + +// } + +// } + + + + + + +VTKHDF_Recorder::~VTKHDF_Recorder() +{ + // close the HDF5 file + if (name) { + delete [] name; + name = nullptr; + } + + if (file_id >= 0) { H5Fclose(file_id);} + + if (group_id >= 0) {H5Gclose(group_id);} + + if (point_data_group >= 0) {H5Gclose(point_data_group);} + + if (cell_data_group >= 0) {H5Gclose(cell_data_group);} + + if (steps_group >= 0) {H5Gclose(steps_group);} + + if (point_data_offsets_group >= 0) {H5Gclose(point_data_offsets_group);} + + if (cell_data_offsets_group >= 0) {H5Gclose(cell_data_offsets_group);} + +} + + + + + +void VTKHDF_Recorder::setVTKType() +{ + if (!vtktypes.empty()) { + return; + } + // vtktypes[ELE_TAG_Subdomain] = VTK_POLY_VERTEX; + vtktypes[ELEMENT_TAGS_WrapperElement] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ElasticBeam2d] = VTK_LINE; + vtktypes[ELE_TAG_ModElasticBeam2d] = VTK_LINE; + vtktypes[ELE_TAG_ElasticBeam3d] = VTK_LINE; + vtktypes[ELE_TAG_Beam2d] = VTK_LINE; + vtktypes[ELE_TAG_beam2d02] = VTK_LINE; + vtktypes[ELE_TAG_beam2d03] = VTK_LINE; + vtktypes[ELE_TAG_beam2d04] = VTK_LINE; + vtktypes[ELE_TAG_beam3d01] = VTK_LINE; + vtktypes[ELE_TAG_beam3d02] = VTK_LINE; + vtktypes[ELE_TAG_Truss] = VTK_LINE; + vtktypes[ELE_TAG_TrussSection] = VTK_LINE; + vtktypes[ELE_TAG_CorotTruss] = VTK_LINE; + vtktypes[ELE_TAG_CorotTrussSection] = VTK_LINE; + vtktypes[ELE_TAG_fElmt05] = VTK_LINE; + vtktypes[ELE_TAG_fElmt02] = VTK_LINE; + vtktypes[ELE_TAG_MyTruss] = VTK_LINE; + vtktypes[ELE_TAG_ZeroLength] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ZeroLengthSection] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ZeroLengthND] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ZeroLengthContact2D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ZeroLengthContact3D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ZeroLengthContactASDimplex] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ZeroLengthContactNTS2D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ZeroLengthInterface2D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_CoupledZeroLength] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ZeroLengthRocking] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_NLBeamColumn2d] = VTK_LINE; + vtktypes[ELE_TAG_NLBeamColumn3d] = VTK_LINE; + vtktypes[ELE_TAG_LargeDispBeamColumn3d] = VTK_LINE; + vtktypes[ELE_TAG_FourNodeQuad] = VTK_QUAD; + vtktypes[ELE_TAG_FourNodeQuad3d] = VTK_QUAD; + vtktypes[ELE_TAG_Tri31] = VTK_TRIANGLE; + vtktypes[ELE_TAG_SixNodeTri] = VTK_TRIANGLE; + vtktypes[ELE_TAG_BeamWithHinges2d] = VTK_LINE; + vtktypes[ELE_TAG_BeamWithHinges3d] = VTK_LINE; + vtktypes[ELE_TAG_EightNodeBrick] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_TwentyNodeBrick] = VTK_QUADRATIC_HEXAHEDRON; + vtktypes[ELE_TAG_EightNodeBrick_u_p_U] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_TwentyNodeBrick_u_p_U] = VTK_QUADRATIC_HEXAHEDRON; + vtktypes[ELE_TAG_FourNodeQuadUP] = VTK_QUAD; + vtktypes[ELE_TAG_TotalLagrangianFD20NodeBrick] = VTK_QUADRATIC_HEXAHEDRON; + vtktypes[ELE_TAG_TotalLagrangianFD8NodeBrick] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_EightNode_LDBrick_u_p] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_EightNode_Brick_u_p] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_TwentySevenNodeBrick] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_BrickUP] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_Nine_Four_Node_QuadUP] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_Twenty_Eight_Node_BrickUP] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_Twenty_Node_Brick] = VTK_QUADRATIC_HEXAHEDRON; + vtktypes[ELE_TAG_BBarFourNodeQuadUP] = VTK_QUAD; + vtktypes[ELE_TAG_BBarBrickUP] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_PlateMITC4] = VTK_QUAD; + vtktypes[ELE_TAG_ShellMITC4] = VTK_QUAD; + vtktypes[ELE_TAG_ShellMITC9] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ASDShellQ4] = VTK_QUAD; + vtktypes[ELE_TAG_ASDShellT3] = VTK_TRIANGLE; + vtktypes[ELE_TAG_Plate1] = VTK_QUAD; + vtktypes[ELE_TAG_Brick] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_BbarBrick] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_FLBrick] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_EnhancedQuad] = VTK_QUAD; + vtktypes[ELE_TAG_ConstantPressureVolumeQuad] = VTK_QUAD; + vtktypes[ELE_TAG_NineNodeMixedQuad] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_NineNodeQuad] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_EightNodeQuad] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_DispBeamColumn2d] = VTK_LINE; + vtktypes[ELE_TAG_TimoshenkoBeamColumn2d] = VTK_LINE; + vtktypes[ELE_TAG_DispBeamColumn3d] = VTK_LINE; + vtktypes[ELE_TAG_DispBeamColumnWarping3d] = VTK_LINE; + vtktypes[ELE_TAG_HingedBeam2d] = VTK_LINE; + vtktypes[ELE_TAG_HingedBeam3d] = VTK_LINE; + vtktypes[ELE_TAG_TwoPointHingedBeam2d] = VTK_LINE; + vtktypes[ELE_TAG_TwoPointHingedBeam3d] = VTK_LINE; + vtktypes[ELE_TAG_OnePointHingedBeam2d] = VTK_LINE; + vtktypes[ELE_TAG_OnePointHingedBeam3d] = VTK_LINE; + vtktypes[ELE_TAG_BeamColumnJoint2d] = VTK_QUAD; + vtktypes[ELE_TAG_BeamColumnJoint3d] = VTK_QUAD; + vtktypes[ELE_TAG_ForceBeamColumn2d] = VTK_LINE; + vtktypes[ELE_TAG_ForceBeamColumnWarping2d] = VTK_LINE; + vtktypes[ELE_TAG_ForceBeamColumn3d] = VTK_LINE; + vtktypes[ELE_TAG_ElasticForceBeamColumn2d] = VTK_LINE; + vtktypes[ELE_TAG_ElasticForceBeamColumnWarping2d] = VTK_LINE; + vtktypes[ELE_TAG_ElasticForceBeamColumn3d] = VTK_LINE; + vtktypes[ELE_TAG_ForceBeamColumnCBDI2d] = VTK_LINE; + vtktypes[ELE_TAG_ForceBeamColumnCBDI3d] = VTK_LINE; + vtktypes[ELE_TAG_DispBeamColumn2dInt] = VTK_LINE; + vtktypes[ELE_TAG_InternalSpring] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_SimpleJoint2D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_Joint2D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_Joint3D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ElastomericBearingPlasticity3d] = VTK_LINE; + vtktypes[ELE_TAG_ElastomericBearingPlasticity2d] = VTK_LINE; + vtktypes[ELE_TAG_TwoNodeLink] = VTK_LINE; + vtktypes[ELE_TAG_ActuatorCorot] = VTK_LINE; + vtktypes[ELE_TAG_Actuator] = VTK_LINE; + vtktypes[ELE_TAG_Adapter] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ElastomericBearingBoucWen2d] = VTK_LINE; + vtktypes[ELE_TAG_ElastomericBearingBoucWen3d] = VTK_LINE; + vtktypes[ELE_TAG_FlatSliderSimple2d] = VTK_LINE; + vtktypes[ELE_TAG_FlatSliderSimple3d] = VTK_LINE; + vtktypes[ELE_TAG_FlatSlider2d] = VTK_LINE; + vtktypes[ELE_TAG_FlatSlider3d] = VTK_LINE; + vtktypes[ELE_TAG_SingleFPSimple2d] = VTK_LINE; + vtktypes[ELE_TAG_SingleFPSimple3d] = VTK_LINE; + vtktypes[ELE_TAG_SingleFP2d] = VTK_LINE; + vtktypes[ELE_TAG_SingleFP3d] = VTK_LINE; + vtktypes[ELE_TAG_DoubleFPSimple2d] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_DoubleFPSimple3d] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_DoubleFP2d] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_DoubleFP3d] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_TripleFPSimple2d] = VTK_LINE; + vtktypes[ELE_TAG_TripleFPSimple3d] = VTK_LINE; + vtktypes[ELE_TAG_TripleFP2d] = VTK_LINE; + vtktypes[ELE_TAG_TripleFP3d] = VTK_LINE; + vtktypes[ELE_TAG_MultiFP2d] = VTK_LINE; + vtktypes[ELE_TAG_MultiFP3d] = VTK_LINE; + vtktypes[ELE_TAG_GenericClient] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_GenericCopy] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_PY_MACRO2D] = VTK_LINE; + vtktypes[ELE_TAG_SimpleContact2D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_SimpleContact3D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_BeamContact3D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_SurfaceLoad] = VTK_QUAD; + vtktypes[ELE_TAG_BeamContact2D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_BeamEndContact3D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_SSPquad] = VTK_QUAD; + vtktypes[ELE_TAG_SSPquadUP] = VTK_QUAD; + vtktypes[ELE_TAG_SSPbrick] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_SSPbrickUP] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_BeamContact2Dp] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_BeamContact3Dp] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_BeamEndContact3Dp] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_Quad4FiberOverlay] = VTK_QUAD; + vtktypes[ELE_TAG_Brick8FiberOverlay] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_QuadBeamEmbedContact] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_DispBeamColumn2dThermal] = VTK_LINE; + vtktypes[ELE_TAG_TPB1D] = VTK_LINE; + vtktypes[ELE_TAG_TFP_Bearing] = VTK_LINE; + vtktypes[ELE_TAG_TFP_Bearing2d] = VTK_LINE; + vtktypes[ELE_TAG_TripleFrictionPendulum] = VTK_LINE; + vtktypes[ELE_TAG_TripleFrictionPendulumX] = VTK_LINE; + vtktypes[ELE_TAG_PFEMElement2D] = VTK_TRIANGLE; + vtktypes[ELE_TAG_FourNodeQuad02] = VTK_QUAD; + vtktypes[ELE_TAG_cont2d01] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_cont2d02] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_CST] = VTK_TRIANGLE; + vtktypes[ELE_TAG_Truss2] = VTK_LINE; + vtktypes[ELE_TAG_CorotTruss2] = VTK_LINE; + vtktypes[ELE_Tag_ZeroLengthImpact3D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_PFEMElement3D] = VTK_TETRA; + vtktypes[ELE_TAG_PFEMElement2DCompressible] = VTK_TRIANGLE; + vtktypes[ELE_TAG_PFEMElement2DBubble] = VTK_TRIANGLE; + vtktypes[ELE_TAG_PFEMElement2Dmini] = VTK_TRIANGLE; + vtktypes[ELE_TAG_ElasticTimoshenkoBeam2d] = VTK_LINE; + vtktypes[ELE_TAG_ElasticTimoshenkoBeam3d] = VTK_LINE; + vtktypes[ELE_TAG_ElastomericBearingUFRP2d] = VTK_LINE; + vtktypes[ELE_TAG_ElastomericBearingUFRP3d] = VTK_LINE; + vtktypes[ELE_TAG_RJWatsonEQS2d] = VTK_LINE; + vtktypes[ELE_TAG_RJWatsonEQS3d] = VTK_LINE; + vtktypes[ELE_TAG_HDR] = VTK_LINE; + vtktypes[ELE_TAG_ElastomericX] = VTK_LINE; + vtktypes[ELE_TAG_LeadRubberX] = VTK_LINE; + vtktypes[ELE_TAG_PileToe3D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_N4BiaxialTruss] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_ShellDKGQ] = VTK_QUAD; + vtktypes[ELE_TAG_ShellNLDKGQ] = VTK_QUAD; + vtktypes[ELE_TAG_MultipleShearSpring] = VTK_LINE; + vtktypes[ELE_TAG_MultipleNormalSpring] = VTK_LINE; + vtktypes[ELE_TAG_KikuchiBearing] = VTK_LINE; + vtktypes[ELE_TAG_ComponentElement2d] = VTK_LINE; + vtktypes[ELE_TAG_YamamotoBiaxialHDR] = VTK_LINE; + vtktypes[ELE_TAG_MVLEM] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_SFI_MVLEM] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_MVLEM_3D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_SFI_MVLEM_3D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_E_SFI_MVLEM_3D] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_E_SFI] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_MEFI] = VTK_POLY_VERTEX; + vtktypes[ELE_TAG_PFEMElement2DFIC] = VTK_TRIANGLE; + vtktypes[ELE_TAG_TaylorHood2D] = VTK_QUADRATIC_TRIANGLE; + vtktypes[ELE_TAG_PFEMElement2DQuasi] = VTK_TRIANGLE; + vtktypes[ELE_TAG_MINI] = VTK_TRIANGLE; + vtktypes[ELE_TAG_CatenaryCable] = VTK_LINE; + vtktypes[ELE_TAG_FourNodeTetrahedron] = VTK_TETRA; + vtktypes[ELE_TAG_PFEMElement3DBubble] = VTK_TETRA; + vtktypes[ELE_TAG_TriSurfaceLoad] = VTK_TRIANGLE; + vtktypes[ELE_TAG_ShellDKGT] = VTK_TRIANGLE; + vtktypes[ELE_TAG_ShellNLDKGT] = VTK_TRIANGLE; + vtktypes[ELE_TAG_InertiaTruss] = VTK_LINE; + vtktypes[ELE_TAG_ASDAbsorbingBoundary2D] = VTK_QUAD; + vtktypes[ELE_TAG_ASDAbsorbingBoundary3D] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_FSIFluidElement2D] = VTK_QUAD; + vtktypes[ELE_TAG_FSIInterfaceElement2D] = VTK_LINE; + vtktypes[ELE_TAG_FSIFluidBoundaryElement2D] = VTK_LINE; + vtktypes[ELE_TAG_PML2D_3] = VTK_QUAD; + vtktypes[ELE_TAG_PML2D_5] = VTK_QUAD; + vtktypes[ELE_TAG_PML2D_12] = VTK_QUAD; + vtktypes[ELE_TAG_PML2DVISCOUS] = VTK_QUAD; + vtktypes[ELE_TAG_PML2D] = VTK_QUAD; + vtktypes[ELE_TAG_PML3D] = VTK_HEXAHEDRON; + vtktypes[ELE_TAG_PML3DVISCOUS] = VTK_HEXAHEDRON; +} + + + +/** + * Creates an HDF5 dataset with automatic dimension detection based on columns + * + * param group_id Parent group ID where dataset will be created + * param dataset_name Name of the dataset to create + * param ncols Number of columns (0 for 1D dataset, >0 for 2D dataset) + * param chunk_rows Number of rows per chunk (default 100) + * param type_id HDF5 datatype for the dataset (default H5T_NATIVE_DOUBLE) + * param max_rows Maximum number of rows (H5S_UNLIMITED for unlimited, 0 for fixed size) + * return hid_t Dataset ID if successful, negative value if failed + */ +int VTKHDF_Recorder::createDataset( + hid_t group_id, + const char* dataset_name, + hsize_t ncols, + hsize_t chunk_rows, + hid_t type_id, + hsize_t max_rows +) { + + // Determine if it's 1D or 2D based on ncols + int ndims = (ncols == 0) ? 1 : 2; + + // Declare fixed-size arrays + hsize_t dims[2]; + hsize_t max_dims[2]; + hsize_t chunk_dims[2]; + + // Set dimensions based on whether it's 1D or 2D + if (ndims == 1) { + dims[0] = 0; + max_dims[0] = max_rows; + chunk_dims[0] = chunk_rows; + } else { + dims[0] = 0; + dims[1] = ncols; + max_dims[0] = max_rows; + max_dims[1] = ncols; + chunk_dims[0] = chunk_rows; + chunk_dims[1] = ncols; + } + + // Create dataspace + hid_t space_id = H5Screate_simple(ndims, dims, max_dims); + if (space_id < 0) { + fprintf(stderr, "Error creating dataspace for %s\n", dataset_name); + return -1; + } + + // Create property list for chunked storage + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + if (plist_id < 0) { + fprintf(stderr, "Error creating property list for %s\n", dataset_name); + H5Sclose(space_id); + return -1; + } + + // Set chunk size + if (H5Pset_chunk(plist_id, ndims, chunk_dims) < 0) { + fprintf(stderr, "Error setting chunk size for %s\n", dataset_name); + H5Pclose(plist_id); + H5Sclose(space_id); + return -1; + } + + // Create the dataset + hid_t dset_id = H5Dcreate( + group_id, + dataset_name, + type_id, + space_id, + H5P_DEFAULT, + plist_id, + H5P_DEFAULT + ); + + // Check if dataset was created successfully + if (dset_id < 0) { + fprintf(stderr, "Error creating dataset %s\n", dataset_name); + H5Pclose(plist_id); + H5Sclose(space_id); + return -1; + } + + // Clean up + H5Pclose(plist_id); + H5Sclose(space_id); + H5Dclose(dset_id); + + return 0; +} + + + +int VTKHDF_Recorder::extendDataset(hid_t dataGroup, + const char* datasetName, + const void* newData, + hid_t datatype, + size_t numNewElements, + size_t numColumns) { + // Open dataset + hid_t dset_id = H5Dopen(dataGroup, datasetName, H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset '" << datasetName << "'\n"; + return -1; + } + + // Get the current dataspace + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for '" << datasetName << "'\n"; + H5Dclose(dset_id); + return -1; + } + + // Get rank and dimensions + int rank = H5Sget_simple_extent_ndims(space_id); + std::vector current_dims(rank); + if (H5Sget_simple_extent_dims(space_id, current_dims.data(), NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Prepare new dimensions + std::vector new_dims = current_dims; + new_dims[0] += static_cast(numNewElements); // Extend first dimension + + // Extend the dataset + if (H5Dset_extent(dset_id, new_dims.data()) < 0) { + opserr << "Error setting new extent for '" << datasetName << "'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Get the new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for '" << datasetName << "'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Prepare hyperslab selection + std::vector offset(rank, 0); + std::vector count(rank); + + offset[0] = current_dims[0]; // Start from end of existing data + count[0] = numNewElements; // Number of new elements + + if (rank == 2) { + count[1] = numColumns; // Use specified number of columns for 2D + } + + // Select hyperslab for writing + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset.data(), + NULL, count.data(), NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Create memory space + hid_t mem_space_id = H5Screate_simple(rank, count.data(), NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for '" << datasetName << "'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Write data with the specified datatype + if (H5Dwrite(dset_id, datatype, mem_space_id, new_space_id, + H5P_DEFAULT, newData) < 0) { + opserr << "Error writing data to '" << datasetName << "'\n"; + } + + // Clean up + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + + return 0; +} + + + + +int VTKHDF_Recorder::createOffsetDataset(hid_t group_id, + const char* dataset_name, + hsize_t chunk_rows, + hid_t type_id, + hsize_t max_rows) { + // Define initial dimensions as 0 since we don't know the number of nodes yet + hsize_t dims[1] = {0}; // Initial size (0 rows) + hsize_t max_dims[1] = {max_rows}; // Maximum size (unlimited rows) + + // Create a dataspace with these dimensions + hid_t space_id = H5Screate_simple(1, dims, max_dims); + if (space_id < 0) { + fprintf(stderr, "Error creating dataspace for %s\n", dataset_name); + return -1; + } + + // Create a property list for chunked storage + hid_t plist_id = H5Pcreate(H5P_DATASET_CREATE); + if (plist_id < 0) { + fprintf(stderr, "Error creating property list for %s\n", dataset_name); + H5Sclose(space_id); + return -1; + } + + // Define the chunk size (e.g., 100 rows per chunk) + hsize_t chunk_dims[1] = {chunk_rows}; + if (H5Pset_chunk(plist_id, 1, chunk_dims) < 0) { + fprintf(stderr, "Error setting chunk size for %s\n", dataset_name); + H5Pclose(plist_id); + H5Sclose(space_id); + return -1; + } + + // Create the dataset with chunked storage + hid_t dset_id = H5Dcreate( + group_id, + dataset_name, + type_id, + space_id, + H5P_DEFAULT, + plist_id, + H5P_DEFAULT + ); + + if (dset_id < 0) { + fprintf(stderr, "Error creating dataset for %s\n", dataset_name); + H5Pclose(plist_id); + H5Sclose(space_id); + return -1; + } + + // Clean up + H5Pclose(plist_id); + H5Dclose(dset_id); + H5Sclose(space_id);// Create dataset with 1 column + + return 0; +} + +int VTKHDF_Recorder::extendOffsetDataset(hid_t group_id, + const char* dataset_name, + const void* new_value, + hid_t datatype, + size_t extra_rows) { + // Open dataset + hid_t dset_id = H5Dopen(group_id, dataset_name, H5P_DEFAULT); + if (dset_id < 0) { + opserr << "Error opening dataset '" << dataset_name << "'\n"; + return -1; + } + + // Get current dataspace and dimensions + hid_t space_id = H5Dget_space(dset_id); + if (space_id < 0) { + opserr << "Error getting dataspace for '" << dataset_name << "'\n"; + H5Dclose(dset_id); + return -1; + } + + // Get current dimensions + hsize_t current_dims[1]; + if (H5Sget_simple_extent_dims(space_id, current_dims, NULL) < 0) { + opserr << "Error getting current dimensions\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Calculate new dimensions + hsize_t new_dims[1] = {current_dims[0] + static_cast(extra_rows)}; + + // Extend dataset + if (H5Dset_extent(dset_id, new_dims) < 0) { + opserr << "Error setting new extent for '" << dataset_name << "'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Get new dataspace + hid_t new_space_id = H5Dget_space(dset_id); + if (new_space_id < 0) { + opserr << "Error getting new dataspace for '" << dataset_name << "'\n"; + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Select hyperslab for new data + hsize_t offset[1] = {current_dims[0]}; + hsize_t count[1] = {1}; + if (H5Sselect_hyperslab(new_space_id, H5S_SELECT_SET, offset, NULL, count, NULL) < 0) { + opserr << "Error selecting hyperslab\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Create memory space for new data + hid_t mem_space_id = H5Screate_simple(1, count, NULL); + if (mem_space_id < 0) { + opserr << "Error creating memory space for '" << dataset_name << "'\n"; + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Write new data using the provided datatype + if (H5Dwrite(dset_id, datatype, mem_space_id, new_space_id, H5P_DEFAULT, new_value) < 0) { + opserr << "Error writing data to '" << dataset_name << "'\n"; + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + return -1; + } + + // Clean up + H5Sclose(mem_space_id); + H5Sclose(new_space_id); + H5Sclose(space_id); + H5Dclose(dset_id); + + return 0; +} diff --git a/SRC/recorder/VTKHDF_Recorder.h b/SRC/recorder/VTKHDF_Recorder.h new file mode 100644 index 0000000000..d5ab0fea18 --- /dev/null +++ b/SRC/recorder/VTKHDF_Recorder.h @@ -0,0 +1,281 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in the main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ +#ifndef VTKHDF_RECORDER_H +#define VTKHDF_RECORDER_H + +// Written: Amin Pakzad, 2025 +// Purpose: Class definition for VTKHDF_Recorder to store responses in HDF5 format. + +// Include existing headers plus HDF5 + +#include +#include +#include +#include +#include +#include "Response.h" +#include +#include +#include +#include "hdf5.h" + + +// Define the OutputData class +class OutputDataHDF { +public: + OutputDataHDF(); + OutputDataHDF &operator=(const OutputDataHDF &other); + + bool disp; + bool vel; + bool accel; + bool reaction; + bool mass, unbalancedLoad; + bool stress3D6, strain3D6; + bool stress2D3, strain2D3; +}; + + +class SilentStream : public OPS_Stream { +public: + SilentStream(); + ~SilentStream() override; + + // Implement all pure virtual methods with no-op behavior + int tag(const char* tagName) override { return 0; } + int tag(const char* tagName, const char* value) override { return 0; } + int endTag() override { return 0; } + int attr(const char* name, int value) override { return 0; } + int attr(const char* name, double value) override { return 0; } + int attr(const char* name, const char* value) override { return 0; } + int write(Vector& data) override { return 0; } + int flush() override { return 0; } + int open() override { return 0; } + int close(openMode nextOpen = APPEND) override { return 0; } + + // Implement the write methods with no-op behavior + OPS_Stream& write(const char* s, int n) override { return *this; } + OPS_Stream& write(const unsigned char* s, int n) override { return *this; } + OPS_Stream& write(const signed char* s, int n) override { return *this; } + OPS_Stream& write(const void* s, int n) override { return *this; } + OPS_Stream& write(const double* s, int n) override { return *this; } + + // Implement output operators with no-op behavior + OPS_Stream& operator<<(char c) override { return *this; } + OPS_Stream& operator<<(unsigned char c) override { return *this; } + OPS_Stream& operator<<(signed char c) override { return *this; } + OPS_Stream& operator<<(const char* s) override { return *this; } + OPS_Stream& operator<<(const unsigned char* s) override { return *this; } + OPS_Stream& operator<<(const signed char* s) override { return *this; } + OPS_Stream& operator<<(const void* p) override { return *this; } + OPS_Stream& operator<<(int n) override { return *this; } + OPS_Stream& operator<<(unsigned int n) override { return *this; } + OPS_Stream& operator<<(long n) override { return *this; } + OPS_Stream& operator<<(unsigned long n) override { return *this; } + OPS_Stream& operator<<(short n) override { return *this; } + OPS_Stream& operator<<(unsigned short n) override { return *this; } + OPS_Stream& operator<<(bool b) override { return *this; } + OPS_Stream& operator<<(double n) override { return *this; } + OPS_Stream& operator<<(float n) override { return *this; } + + // Implement parallel methods with no-op behavior + void setAddCommon(int flag) override {} + int setOrder(const ID& order) override { return 0; } + int sendSelf(int commitTag, Channel& theChannel) override { return 0; } + int recvSelf(int commitTag, Channel& theChannel, FEM_ObjectBroker& theBroker) override { return 0; } +}; + +// Define the VTKHDF_Recorder class +class VTKHDF_Recorder : public Recorder { +public: + typedef std::vector EleData; + + VTKHDF_Recorder(const char *filename, const OutputDataHDF &ndata, + const std::vector &edata, double dt = 0, double rTolDt = 0.00001); + VTKHDF_Recorder(); + ~VTKHDF_Recorder(); + + int record(int commitTag, double timeStamp) override; + int restart() override; + int domainChanged() override; + int setDomain(Domain &domain) override; + int sendSelf(int commitTag, Channel &theChannel) override; + int recvSelf(int commitTag, Channel &theChannel, FEM_ObjectBroker &theBroker) override; + +private: + int createDataset(hid_t group_id, const char* dataset_name, + hsize_t ncols, hsize_t chunk_rows = 100, + hid_t type_id = H5T_NATIVE_DOUBLE, + hsize_t max_rows = H5S_UNLIMITED); + + int createOffsetDataset(hid_t group_id, const char* dataset_name, + hsize_t chunk_rows = 100, + hid_t type_id = H5T_NATIVE_DOUBLE, + hsize_t max_rows = H5S_UNLIMITED); + + int extendDataset(hid_t dataGroup, + const char* datasetName, + const void* newData, + hid_t datatype, + size_t numNewElements, + size_t numColumns = 0); + + + int extendOffsetDataset(hid_t group_id, + const char* dataset_name, + const void* new_value, + hid_t datatype, + size_t extra_rows = 1); + + + OutputDataHDF outputData; + +protected: + bool initDone; + virtual void addEleData(const EleData &edata) { eledata.push_back(edata); } + std::vector eledata; + +private: + int writeMesh(); + int writeStep(double timeStamp); + int writeDisp(); + int writeVel(); + int writeAccel(); + int writeStrees3D6(); + int writeStrain3D6(); + int writeStress2D3(); + int writeStrain2D3(); + + + + Domain *theDomain; + + double nextTimeStampToRecord; + double deltaT; + double relDeltaTTol; + + char *name; + int counter; + + int ndm; + int ndf; + + int numNode; + int numElement; + int numConnectivityIds; + int maxNDM; + int maxNDF; + + hid_t group_id; + hid_t file_id; + + bool initializationDone; + + hid_t dispOffsetDataset; + hid_t dispDataset; + + + int current_PointOffset; + int current_CellOffset; + int current_ConnectivityIdOffset; + int current_PartOffset; + int next_PointOffset; + int next_CellOffset; + int next_ConnectivityIdOffset; + int next_PartOffset; + + + + // data specif offsets + int CurrentDispOffset; + int CurrentVelOffset; + int CurrentAccelOffset; + + // 3Dstrees6 + int current_Stress3D6Offset; + std::vector stress3D6Responses; // specific to 3DStress6 responses + + // 3DStrain6 + int current_Strain3D6Offset; + std::vector strain3D6Responses; // specific to 3DStrain6 responses + + // 2Dstrees3 + int current_Stress2D3Offset; + std::vector stress2D3Responses; // specific to 2DStress3 responses + + // 2DStrain3 + int current_Strain2D3Offset; + std::vector strain2D3Responses; // specific to 2DStrain3 responses + + + + + + unsigned int numSteps; + + + + std::map theNodeMapping; + std::map theEleMapping; + + std::vector theNodeTags; + std::vector theEleTags; + std::vector theEleClassTags; + std::vector theEleVtkTags; + std::vector theEleVtkOffsets; + + // Create groups for temporal data + hid_t steps_group; + hid_t point_data_group; + hid_t cell_data_group; + hid_t point_data_offsets_group; + hid_t cell_data_offsets_group; + + hid_t nsteps_attr_id; + + + + // Keep VtkType enum and related static members + enum VtkType { + VTK_VERTEX = 1, + VTK_POLY_VERTEX = 2, + VTK_LINE = 3, + VTK_POLY_LINE = 4, + VTK_TRIANGLE = 5, + VTK_TRIANGLE_STRIP = 6, + VTK_POLYGON = 7, + VTK_PIXEL = 8, + VTK_QUAD = 9, + VTK_TETRA = 10, + VTK_VOXEL = 11, + VTK_HEXAHEDRON = 12, + VTK_WEDGE = 12, + VTK_PYRAMID = 14, + VTK_QUADRATIC_EDGE = 21, + VTK_QUADRATIC_TRIANGLE = 22, + VTK_QUADRATIC_QUAD = 23, + VTK_QUADRATIC_TETRA = 24, + VTK_QUADRATIC_HEXAHEDRON = 25 + }; + + static std::map vtktypes; + static void setVTKType(); +}; + +#endif diff --git a/SRC/recorder/VTK_Recorder.cpp b/SRC/recorder/VTK_Recorder.cpp index 16dc4b456b..ae3754e1db 100644 --- a/SRC/recorder/VTK_Recorder.cpp +++ b/SRC/recorder/VTK_Recorder.cpp @@ -1199,6 +1199,12 @@ VTK_Recorder::setVTKType() vtktypes[ELE_TAG_FSIFluidElement2D] = VTK_QUAD; vtktypes[ELE_TAG_FSIInterfaceElement2D] = VTK_LINE; vtktypes[ELE_TAG_FSIFluidBoundaryElement2D] = VTK_LINE; + vtktypes[ELE_TAG_PML2D_3] = VTK_QUAD; + vtktypes[ELE_TAG_PML2D_5] = VTK_QUAD; + vtktypes[ELE_TAG_PML2D_12] = VTK_QUAD; + vtktypes[ELE_TAG_PML2DVISCOUS] = VTK_QUAD; + vtktypes[ELE_TAG_PML2D] = VTK_QUAD; + vtktypes[ELE_TAG_PML3D] = VTK_HEXAHEDRON; } diff --git a/SRC/reliability/domain/spectrum/PointsSpectrum.cpp b/SRC/reliability/domain/spectrum/PointsSpectrum.cpp index 474ba9db8a..bdde40b6b6 100644 --- a/SRC/reliability/domain/spectrum/PointsSpectrum.cpp +++ b/SRC/reliability/domain/spectrum/PointsSpectrum.cpp @@ -91,7 +91,7 @@ PointsSpectrum::getAmplitude(double frequency) else { double dy, dx, a, b; for (int i=1; i frequencies(i-1) && frequency < frequencies(i)) { + if (frequency > frequencies(i-1) && frequency <= frequencies(i)) { dy = amplitudes(i) - amplitudes(i-1); dx = frequencies(i) - frequencies(i-1); a = dy/dx; diff --git a/SRC/runtime/CMakeLists.txt b/SRC/runtime/CMakeLists.txt index c45463de26..66b46df859 100644 --- a/SRC/runtime/CMakeLists.txt +++ b/SRC/runtime/CMakeLists.txt @@ -6,18 +6,21 @@ #============================================================================== add_library(OpenSeesRT SHARED) +add_library(OpenSeesRT_Static STATIC) + target_sources(OpenSeesRT PRIVATE "OpenSeesRT.cpp") +target_sources(OpenSeesRT_Static PRIVATE "OpenSeesRT.cpp") target_compile_definitions(OpenSeesRT PUBLIC USE_TCL_STUBS _TCL85) -set_property(TARGET OpenSeesRT PROPERTY POSITION_INDEPENDENT_CODE 1) +set_property(TARGET OpenSeesRT PROPERTY POSITION_INDEPENDENT_CODE 1) target_compile_options(OPS_Runtime PRIVATE - "$<$>:-Wextra>" - "$<$>:-Wpedantic>" - "$<$:/W4>" + "$<$>:-Wno-unused-parameter>" + "$<$:/W3>" + "$<$:/bigobj>" + "$<$:/wd4100>" ) -target_include_directories(OPS_Runtime PUBLIC - ./api/ +target_include_directories(OPS_Runtime PUBLIC ${OPS_SRC_DIR}/runtime/commands ${OPS_SRC_DIR}/runtime/parsing/ ${OPS_SRC_DIR}/runtime/commands/modeling @@ -27,11 +30,8 @@ target_link_libraries(OPS_Runtime PRIVATE G3 OPS_Algorithm) add_subdirectory(commands) add_subdirectory(runtime) +add_subdirectory(parsing) -target_sources(OPS_Runtime PRIVATE - "runtime/G3_Runtime.cpp" - "parsing/InterpreterAPI.cpp" -) if (DEFINED OPENSEESRT_VERSION) set_property( @@ -50,27 +50,20 @@ if (${TCL_INCLUDE_PATH}) target_include_directories(OPS_Runtime PUBLIC ${TCL_INCLUDE_PATH}) endif() -target_link_libraries(OpenSeesRT PRIVATE OPS_Runtime OPS_Renderer OPS_Algorithm ${TCL_STUB_LIBRARY}) - -# -# Python -# -find_package(Python COMPONENTS Interpreter Development) -find_package(pybind11 CONFIG) -if (${pybind11_FOUND} AND NOT DEFINED NoOpenSeesPyRT) - message(" :: Configuring Pyton extension") - add_subdirectory(python) -endif() - -# -# Parallel -# -if (FALSE) # (MPI_FOUND) - add_library(OpenSeesRT_Parallel SHARED) - add_subdirectory(commands/parallel) - target_sources(OpenSeesRT_Parallel PRIVATE OpenSeesPRT.cpp) -endif() +target_link_libraries(OpenSeesRT + PRIVATE + OPS_Runtime + OPS_Renderer + OPS_Algorithm + ${TCL_STUB_LIBRARY} +) +target_link_libraries(OpenSeesRT_Static + PUBLIC + OPS_Runtime + OPS_Renderer + OPS_Algorithm +) if (EXISTS ${CMAKE_CURRENT_LIST_DIR}/packages/UCSD_CompGeoMech/CMakeLists.txt) add_subdirectory(packages/UCSD_CompGeoMech) diff --git a/SRC/runtime/OpenSeesRT.cpp b/SRC/runtime/OpenSeesRT.cpp index 444fe3b119..e020300596 100644 --- a/SRC/runtime/OpenSeesRT.cpp +++ b/SRC/runtime/OpenSeesRT.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -12,8 +21,8 @@ #endif // #include -#include "G3_Runtime.h" -#include +#include "runtime/G3_Runtime.h" +#include #include #include #include "commands/strings.cpp" @@ -28,8 +37,9 @@ #else # include #endif -// -extern int OpenSeesAppInit(Tcl_Interp *interp); + +// interpreter/runtime.cpp +extern int Init_OpenSees(Tcl_Interp *interp); extern void G3_InitTclSequentialAPI(Tcl_Interp* interp); extern int init_g3_tcl_utils(Tcl_Interp*); @@ -53,7 +63,7 @@ version(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv) // extern "C" int #ifdef _WIN32 -__declspec(dllexport) // DLLEXPORT +__declspec(dllexport) #endif Openseesrt_Init(Tcl_Interp *interp) { @@ -68,7 +78,7 @@ Openseesrt_Init(Tcl_Interp *interp) Tcl_SetAssocData(interp, "G3_Runtime", NULL, (ClientData)rt); // Initialize OpenSees - OpenSeesAppInit(interp); + Init_OpenSees(interp); G3_InitTclSequentialAPI(interp); // Add sequential API init_g3_tcl_utils(interp); // Add utility commands (linspace, range, etc.) diff --git a/SRC/runtime/commands/CMakeLists.txt b/SRC/runtime/commands/CMakeLists.txt index e048ed6c97..325d796921 100644 --- a/SRC/runtime/commands/CMakeLists.txt +++ b/SRC/runtime/commands/CMakeLists.txt @@ -18,15 +18,28 @@ target_sources(OPS_Runtime PRIVATE "modeling/nodes.cpp" "modeling/constraint.cpp" "modeling/geomTransf.cpp" + "modeling/element.cpp" - "modeling/nDMaterial.cpp" + "modeling/element/frames.cpp" + "modeling/element/shells.cpp" + "modeling/element/brick.cpp" + "modeling/element/plane.cpp" + "modeling/element/truss.cpp" + "modeling/section.cpp" + "modeling/section/plane.cpp" + "modeling/section/frame.cpp" + "modeling/section/truss.cpp" + "modeling/uniaxialMaterial.cpp" "modeling/uniaxial.cpp" + "modeling/printing.cpp" - "modeling/blockND.cpp" - "modeling/Block2D.cpp" - "modeling/Block3D.cpp" + + "modeling/utilities/blockND.cpp" + "modeling/utilities/Block2D.cpp" + "modeling/utilities/Block3D.cpp" + "modeling/invoking/invoke.cpp" "modeling/invoking/invoke_uniaxial.cpp" "modeling/invoking/invoke_section.cpp" @@ -41,6 +54,7 @@ target_sources(OPS_Runtime PRIVATE "analysis/ctest.cpp" "analysis/solver.cpp" "analysis/solver.hpp" + "analysis/sensitivity.cpp" # Utilities "utilities/utilities.cpp" @@ -49,4 +63,9 @@ target_sources(OPS_Runtime PRIVATE ) add_subdirectory(domain) +add_subdirectory(parallel) +add_subdirectory(analysis/modal) +add_subdirectory(modeling) +target_include_directories(OPS_Runtime PUBLIC ${CMAKE_CURRENT_LIST_DIR}) +target_include_directories(OPS_Runtime PUBLIC ${CMAKE_CURRENT_LIST_DIR}/modeling) diff --git a/SRC/runtime/commands/analysis/algorithm.cpp b/SRC/runtime/commands/analysis/algorithm.cpp index 7bc0528c66..b3e5b46991 100644 --- a/SRC/runtime/commands/analysis/algorithm.cpp +++ b/SRC/runtime/commands/analysis/algorithm.cpp @@ -1,14 +1,25 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// // Description: This file implements commands that allow for construction // and interaction with Algorithm objects. Any command which requires // access to specific Algorithm types (from the standard library) should // be implemented here. // +#include #include #include #include @@ -16,6 +27,7 @@ #include #include #include +#include #include "BasicAnalysisBuilder.h" // Algorithms @@ -25,8 +37,6 @@ #include #include #include -#include -#include #include #include @@ -45,6 +55,8 @@ #include #include #include + + #include class G3_Runtime; @@ -55,29 +67,33 @@ extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, typedef EquiSolnAlgo *(TclEquiSolnAlgo)(ClientData, Tcl_Interp *, int, TCL_Char **); -OPS_Routine OPS_NewtonRaphsonAlgorithm; OPS_Routine OPS_ExpressNewton; -OPS_Routine OPS_ModifiedNewton; OPS_Routine OPS_NewtonHallM; TclEquiSolnAlgo G3Parse_newEquiSolnAlgo; -TclEquiSolnAlgo G3Parse_newSecantNewtonAlgorithm; -TclEquiSolnAlgo G3_newNewtonLineSearch; -static TclEquiSolnAlgo G3_newKrylovNewton; static TclEquiSolnAlgo G3_newBroyden; static TclEquiSolnAlgo G3_newBFGS; Tcl_CmdProc TclCommand_newLinearAlgorithm; Tcl_CmdProc TclCommand_newNewtonRaphson; -Tcl_CmdProc TclCommand_newModifiedNewton; Tcl_CmdProc TclCommand_newNewtonHallM; +Tcl_CmdProc TclCommand_newAcceleratedNewton; +static Tcl_CmdProc TclCommand_newNewtonLineSearch; namespace OpenSees { std::unordered_map Algorithms { - {"Linear", TclCommand_newLinearAlgorithm}, - {"Newton", TclCommand_newNewtonRaphson}, - {"NewtonHall", TclCommand_newNewtonHallM}, - {"ModifiedNewton", TclCommand_newModifiedNewton} + {"Linear", TclCommand_newLinearAlgorithm}, + + {"Newton", TclCommand_newNewtonRaphson}, + {"ModifiedNewton", TclCommand_newNewtonRaphson}, + {"NewtonHall", TclCommand_newNewtonHallM}, + {"NewtonLineSearch", TclCommand_newNewtonLineSearch}, + + {"SecantNewton", TclCommand_newAcceleratedNewton}, + {"MillerAccelerator", TclCommand_newAcceleratedNewton}, + {"KrylovNewton", TclCommand_newAcceleratedNewton}, + {"PeriodicNewton", TclCommand_newAcceleratedNewton}, + {"RaphsonNewton", TclCommand_newAcceleratedNewton}, }; } @@ -85,7 +101,7 @@ std::unordered_map Algorithms { // command invoked to allow the SolnAlgorithm object to be built // int -TclCommand_specifyAlgorithm(ClientData clientData, Tcl_Interp *interp, int argc, +TclCommand_specifyAlgorithm(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { @@ -94,14 +110,16 @@ TclCommand_specifyAlgorithm(ClientData clientData, Tcl_Interp *interp, int argc, // Make sure at least one other argument to contain numberer if (argc < 2) { - opserr << G3_ERROR_PROMPT << "Need to specify an Algorithm type.\n"; + opserr << OpenSees::PromptValueError << "Need to specify an Algorithm type.\n"; return TCL_ERROR; } + auto command = OpenSees::Algorithms.find(std::string{argv[1]}); if (command != OpenSees::Algorithms.end()) return (*command->second)(clientData, interp, argc, argv); + OPS_ResetInputNoBuilder(nullptr, interp, 2, argc, argv, nullptr); EquiSolnAlgo *theNewAlgo = G3Parse_newEquiSolnAlgo(clientData, interp, argc, argv); @@ -119,7 +137,7 @@ TclCommand_specifyAlgorithm(ClientData clientData, Tcl_Interp *interp, int argc, EquiSolnAlgo * -G3Parse_newEquiSolnAlgo(ClientData clientData, Tcl_Interp *interp, int argc, +G3Parse_newEquiSolnAlgo(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { @@ -130,66 +148,48 @@ G3Parse_newEquiSolnAlgo(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(argv[1], "BFGS") == 0) return G3_newBFGS(clientData, interp, argc, argv); - else if (strcmp(argv[1], "SecantNewton") == 0) - return G3Parse_newSecantNewtonAlgorithm(clientData, interp, argc, argv); - - else if (strcmp(argv[1], "NewtonLineSearch") == 0) - return G3_newNewtonLineSearch(clientData, interp, argc, argv); - - else if (strcmp(argv[1], "KrylovNewton") == 0) - return G3_newKrylovNewton(clientData, interp, argc, argv); - - EquiSolnAlgo *theNewAlgo = nullptr; G3_Runtime *rt = G3_getRuntime(interp); - if (strcmp(argv[1], "Newton") == 0) { - void *theNewtonAlgo = OPS_NewtonRaphsonAlgorithm(rt, argc, argv); - theNewAlgo = (EquiSolnAlgo *)theNewtonAlgo; - } - - else if ((strcmp(argv[1], "NewtonHallM") == 0) || + if ((strcmp(argv[1], "NewtonHallM") == 0) || (strcmp(argv[1], "NewtonHall") == 0)) { void *theNewtonAlgo = OPS_NewtonHallM(rt, argc, argv); theNewAlgo = (EquiSolnAlgo *)theNewtonAlgo; } - else if (strcmp(argv[1], "ModifiedNewton") == 0) { - void *theNewtonAlgo = OPS_ModifiedNewton(rt, argc, argv); - theNewAlgo = (EquiSolnAlgo *)theNewtonAlgo; - } - else if (strcmp(argv[1], "ExpressNewton") == 0) { void *theNewtonAlgo = OPS_ExpressNewton(rt, argc, argv); theNewAlgo = (EquiSolnAlgo *)theNewtonAlgo; } else { - opserr << G3_ERROR_PROMPT << "No EquiSolnAlgo of type '" << argv[1] << "' exists\n"; + opserr << OpenSees::PromptValueError + << "Unknown algorithm type '" << argv[1] << "'\n"; return nullptr; } return theNewAlgo; } + int -TclCommand_newLinearAlgorithm(ClientData clientData, Tcl_Interp *interp, int argc, +TclCommand_newLinearAlgorithm(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; assert(builder != nullptr); - int formTangent = CURRENT_TANGENT; + IncrementalIntegrator::TangentFlagType correction_tangent = CURRENT_TANGENT; int factorOnce = 0; int count = 2; while (count < argc) { if ((strcmp(argv[count], "-secant") == 0) || (strcmp(argv[count], "-Secant") == 0)) { - formTangent = CURRENT_SECANT; + correction_tangent = CURRENT_SECANT; } else if ((strcmp(argv[count], "-initial") == 0) || (strcmp(argv[count], "-Initial") == 0)) { - formTangent = INITIAL_TANGENT; + correction_tangent = INITIAL_TANGENT; } else if ((strcmp(argv[count], "-factorOnce") == 0) || (strcmp(argv[count], "-FactorOnce") == 0)) { @@ -198,43 +198,51 @@ TclCommand_newLinearAlgorithm(ClientData clientData, Tcl_Interp *interp, int arg count++; } - builder->set(new Linear(formTangent, factorOnce)); + builder->set(new Linear(correction_tangent, factorOnce)); return TCL_OK; } int -TclCommand_newNewtonRaphson(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char**const argv) +TclCommand_newNewtonRaphson(ClientData clientData, + Tcl_Interp* interp, + Tcl_Size argc, TCL_Char**const argv) { BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; assert(builder != nullptr); - int formTangent = CURRENT_TANGENT; + IncrementalIntegrator::TangentFlagType + correction_tangent = CURRENT_TANGENT, + prediction_tangent = CURRENT_TANGENT; double iFactor = 0; double cFactor = 1; for (int i=2; i= 2) { @@ -251,55 +259,24 @@ TclCommand_newNewtonRaphson(ClientData clientData, Tcl_Interp* interp, int argc, } } - builder->set(new NewtonRaphson(formTangent, iFactor, cFactor)); - - return TCL_OK; -} - - -int -TclCommand_newModifiedNewton(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char**const argv) -{ - BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - assert(builder != nullptr); - - int formTangent = CURRENT_TANGENT; - double iFactor = 0; - double cFactor = 1; - - for (int i=2; i= 2) { - if (Tcl_GetDouble(interp, argv[i+1], &iFactor) != TCL_OK) { - opserr << "WARNING invalid data reading ifactor\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i+2], &cFactor) != TCL_OK) { - opserr << "WARNING invalid data reading cfactor\n"; - return TCL_ERROR; - } - i += 2; - } - } + // + // + if (strcmp(argv[1], "Newton") == 0 || + strcmp(argv[1], "NewtonRaphson") == 0) { + builder->set(new NewtonRaphson(prediction_tangent, + correction_tangent, iFactor, cFactor)); + return TCL_OK; } - - auto algorithm = new ModifiedNewton(formTangent, iFactor, cFactor); - builder->set(algorithm); - return TCL_OK; + else if (strcmp(argv[1], "ModifiedNewton") == 0) { + builder->set(new ModifiedNewton(correction_tangent, iFactor, cFactor)); + return TCL_OK; + } + return TCL_ERROR; } + int -TclCommand_newNewtonHallM(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char**const argv) +TclCommand_newNewtonHallM(ClientData clientData, Tcl_Interp* interp, Tcl_Size argc, TCL_Char**const argv) { BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; assert(builder != nullptr); @@ -360,118 +337,71 @@ TclCommand_newNewtonHallM(ClientData clientData, Tcl_Interp* interp, int argc, T -EquiSolnAlgo * -G3Parse_newSecantNewtonAlgorithm(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) -{ - assert(clientData != nullptr); - BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - - ConvergenceTest *theTest = builder->getConvergenceTest(); - - if (theTest == nullptr) { - opserr << G3_ERROR_PROMPT << "No ConvergenceTest yet specified\n"; - return nullptr; - } - - int incrementTangent = CURRENT_TANGENT; - int iterateTangent = CURRENT_TANGENT; - int maxDim = 3; - int numTerms = 2; - for (int i = 2; i < argc; ++i) { - if (strcmp(argv[i], "-iterate") == 0 && i + 1 < argc) { - i++; - if (strcmp(argv[i], "current") == 0) - iterateTangent = CURRENT_TANGENT; - if (strcmp(argv[i], "initial") == 0) - iterateTangent = INITIAL_TANGENT; - if (strcmp(argv[i], "noTangent") == 0) - iterateTangent = NO_TANGENT; - - } else if (strcmp(argv[i], "-increment") == 0 && i + 1 < argc) { - i++; - if (strcmp(argv[i], "current") == 0) - incrementTangent = CURRENT_TANGENT; - if (strcmp(argv[i], "initial") == 0) - incrementTangent = INITIAL_TANGENT; - if (strcmp(argv[i], "noTangent") == 0) - incrementTangent = NO_TANGENT; - - } else if (strcmp(argv[i], "-maxDim") == 0 && i + 1 < argc) { - i++; - maxDim = atoi(argv[i]); - - } else if (strcmp(argv[i], "-numTerms") == 0) { - if (i+1 < argc) - numTerms = atoi(argv[++i]); - else { - opserr << G3_ERROR_PROMPT << "Flag -numTerms requires follow up argument\n"; - return nullptr; - } - } - } - - Accelerator *theAccel = nullptr; - if (numTerms <= 1) - theAccel = new SecantAccelerator1(maxDim, iterateTangent); - if (numTerms >= 3) - theAccel = new SecantAccelerator3(maxDim, iterateTangent); - if (numTerms == 2) - theAccel = new SecantAccelerator2(maxDim, iterateTangent); - return new AcceleratedNewton(*theTest, theAccel, incrementTangent); -} - static EquiSolnAlgo * -G3_newBFGS(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +G3_newBFGS(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); - BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - - ConvergenceTest *theTest = builder->getConvergenceTest(); - - if (theTest == nullptr) { - opserr << G3_ERROR_PROMPT << "No ConvergenceTest yet specified\n"; - return nullptr; - } - - int formTangent = CURRENT_TANGENT; + int correction_tangent = CURRENT_TANGENT; int count = -1; for (int i = 2; i < argc; ++i) { if (strcmp(argv[i], "-secant") == 0) { - formTangent = CURRENT_SECANT; - } else if (strcmp(argv[i], "-initial") == 0) { - formTangent = INITIAL_TANGENT; - } else if (strcmp(argv[i++], "-count") == 0 && i < argc) { - count = atoi(argv[i]); + correction_tangent = CURRENT_SECANT; + } + else if (strcmp(argv[i], "-initial") == 0) { + correction_tangent = INITIAL_TANGENT; + } + + else if (strcmp(argv[i++], "-count") == 0 && i < argc) { + if (i >= argc) { + opserr << OpenSees::PromptValueError + << "Flag -count requires follow up argument\n"; + return nullptr; + } + if (Tcl_GetInt(interp, argv[i], &count) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -count: " << argv[i] << "\n"; + return nullptr; + } } } EquiSolnAlgo *theNewAlgo = nullptr; if (count == -1) - theNewAlgo = new BFGS(*theTest, formTangent); + theNewAlgo = new BFGS(correction_tangent, 10); else - theNewAlgo = new BFGS(*theTest, formTangent, count); + theNewAlgo = new BFGS(correction_tangent, count); return theNewAlgo; } -EquiSolnAlgo * -G3_newNewtonLineSearch(ClientData clientData, Tcl_Interp *interp, int argc, +static int +TclCommand_newNewtonLineSearch(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { - assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - ConvergenceTest *theTest = builder->getConvergenceTest(); - - if (theTest == nullptr) { - opserr << G3_ERROR_PROMPT << " No ConvergenceTest yet specified\n"; - return nullptr; - } - - int count = 2; + enum class Positions: int { + EndRequired, + Tolerance, + End, + MaxIter, + MaxEta, + MinEta, + PFlag, + TypeSearch + }; + + enum class LineSearchType: int { + InitialInterpolated, + Bisection, + Secant, + RegulaFalsi + }; + + ArgumentTracker tracker; + std::set positions; // set some default variable double tol = 0.8; @@ -481,53 +411,151 @@ G3_newNewtonLineSearch(ClientData clientData, Tcl_Interp *interp, int argc, int pFlag = 1; int typeSearch = 0; - while (count < argc) { - if (strcmp(argv[count], "-tol") == 0) { - count++; - if (Tcl_GetDouble(interp, argv[count], &tol) != TCL_OK) - return nullptr; - count++; - - } else if (strcmp(argv[count], "-maxIter") == 0) { - count++; - if (Tcl_GetInt(interp, argv[count], &maxIter) != TCL_OK) - return nullptr; - - count++; - } else if (strcmp(argv[count], "-pFlag") == 0) { - count++; - if (Tcl_GetInt(interp, argv[count], &pFlag) != TCL_OK) - return nullptr; - count++; - - } else if (strcmp(argv[count], "-minEta") == 0) { - count++; - if (Tcl_GetDouble(interp, argv[count], &minEta) != TCL_OK) - return nullptr; - count++; + for (int i=2; i= argc) { + opserr << OpenSees::PromptValueError + << "Flag -tol requires follow up argument\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &tol) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -tol: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Tolerance); + } + else if (strcmp(argv[i], "-maxIter") == 0) { + if (++i >= argc) { + opserr << OpenSees::PromptValueError + << "Flag -maxIter requires follow up argument\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[i], &maxIter) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -maxIter: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::MaxIter); + + } else if (strcmp(argv[i], "-pFlag") == 0) { + if (++i >= argc) { + opserr << OpenSees::PromptValueError + << "Flag -pFlag requires follow up argument" + << OpenSees::SignalMessageEnd; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[i], &pFlag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -pFlag: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::PFlag); - } else if (strcmp(argv[count], "-maxEta") == 0) { - count++; - if (Tcl_GetDouble(interp, argv[count], &maxEta) != TCL_OK) - return nullptr; - count++; + } else if (strcmp(argv[i], "-minEta") == 0) { + if (++i >= argc) { + opserr << OpenSees::PromptValueError + << "Flag -minEta requires follow up argument\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &minEta) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -minEta: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::MinEta); - } else if (strcmp(argv[count], "-type") == 0) { - count++; - if (strcmp(argv[count], "Bisection") == 0) + } else if (strcmp(argv[i], "-maxEta") == 0) { + if (++i >= argc) { + opserr << OpenSees::PromptValueError + << "Flag -maxEta requires follow up argument\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &maxEta) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -maxEta: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::MaxEta); + } + + else if (strcmp(argv[i], "-type") == 0) { + if (++i >= argc) { + opserr << OpenSees::PromptValueError + << "Flag -type requires follow up argument\n"; + return TCL_ERROR; + } + if (strcmp(argv[i], "Bisection") == 0) { typeSearch = 1; - else if (strcmp(argv[count], "Secant") == 0) + } else if (strcmp(argv[i], "Secant") == 0) { typeSearch = 2; - else if (strcmp(argv[count], "RegulaFalsi") == 0) + } else if (strcmp(argv[i], "RegulaFalsi") == 0 || + strcmp(argv[i], "LinearInterpolated") == 0) { typeSearch = 3; - else if (strcmp(argv[count], "LinearInterpolated") == 0) - typeSearch = 3; - else if (strcmp(argv[count], "InitialInterpolated") == 0) + } else if (strcmp(argv[i], "InitialInterpolated") == 0) { typeSearch = 0; - count++; + } else { + opserr << OpenSees::PromptValueError + << "Unknown line search type: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::TypeSearch); + } + else { + positions.insert(i); + } + } - } else - count++; + for (int i : positions) { + if (tracker.current() == Positions::EndRequired) { + tracker.increment(); + } + switch (tracker.current()) { + case Positions::Tolerance: + if (Tcl_GetDouble(interp, argv[i], &tol) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -tol: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Tolerance); + break; + case Positions::MaxIter: + if (Tcl_GetInt(interp, argv[i], &maxIter) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -maxIter: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::MaxIter); + break; + case Positions::PFlag: + if (Tcl_GetInt(interp, argv[i], &pFlag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -pFlag: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::PFlag); + break; + case Positions::MinEta: + if (Tcl_GetDouble(interp, argv[i], &minEta) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -minEta: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::MinEta); + break; + case Positions::MaxEta: + if (Tcl_GetDouble(interp, argv[i], &maxEta) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Invalid value for -maxEta: " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::MaxEta); + break; + default: + opserr << OpenSees::PromptValueError + << "Unexpected argument: " << argv[i] << "\n"; + return TCL_ERROR; + } } LineSearch *theLineSearch = nullptr; @@ -541,218 +569,176 @@ G3_newNewtonLineSearch(ClientData clientData, Tcl_Interp *interp, int argc, theLineSearch = new RegulaFalsiLineSearch(tol, maxIter, minEta, maxEta, pFlag); - EquiSolnAlgo *theNewAlgo = nullptr; - theNewAlgo = new NewtonLineSearch(*theTest, theLineSearch); - return theNewAlgo; + builder->set(new NewtonLineSearch(theLineSearch)); + return TCL_OK; } -static EquiSolnAlgo * -G3_newKrylovNewton(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) + + +int +TclCommand_newAcceleratedNewton(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, + TCL_Char ** const argv) { assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - ConvergenceTest *theTest = builder->getConvergenceTest(); - - if (theTest == nullptr) { - opserr << G3_ERROR_PROMPT << "No ConvergenceTest yet specified\n"; - return nullptr; - } - - int incrementTangent = CURRENT_TANGENT; - int iterateTangent = CURRENT_TANGENT; - int maxDim = 3; + + IncrementalIntegrator::TangentFlagType + incrementTangent = CURRENT_TANGENT, + correction_tangent = CURRENT_TANGENT; + + int maxDim = 3; + int numTerms = 2; // Default for SecantAccelerator + double iFactor = 0.0; // Initial factor for RaphsonAccelerator + double cFactor = 1.0; // Current factor for RaphsonAccelerator + + enum class AcceleratorType { + Miller, + Secant, + Raphson, + Krylov, + Periodic + } type = AcceleratorType::Krylov; for (int i = 2; i < argc; ++i) { - if (strcmp(argv[i], "-iterate") == 0 && i + 1 < argc) { - i++; - if (strcmp(argv[i], "current") == 0) - iterateTangent = CURRENT_TANGENT; - if (strcmp(argv[i], "initial") == 0) - iterateTangent = INITIAL_TANGENT; - if (strcmp(argv[i], "noTangent") == 0) - iterateTangent = NO_TANGENT; - - } else if (strcmp(argv[i], "-increment") == 0 && i + 1 < argc) { - i++; - if (strcmp(argv[i], "current") == 0) + if ((strcmp(argv[i], "-iterate") == 0) || + (strcmp(argv[i], "-correction") == 0)) { + if (++i >= argc) { + opserr << OpenSees::PromptValueError + << "Flag -iterate requires follow up argument" + << OpenSees::SignalMessageEnd; + return TCL_ERROR; + } + if ((strcmp(argv[i], "current") == 0) || (strcmp(argv[i], "tangent") == 0)) + correction_tangent = CURRENT_TANGENT; + else if (strcmp(argv[i], "initial") == 0) + correction_tangent = INITIAL_TANGENT; + else if ((strcmp(argv[i], "noTangent") == 0) || strcmp(argv[i], "None") == 0) + correction_tangent = NO_TANGENT; + } + + else if ((strcmp(argv[i], "-increment") == 0) || + (strcmp(argv[i], "-prediction") == 0)) { + if (++i >= argc) { + opserr << OpenSees::PromptValueError + << "Flag -increment requires follow up argument" + << OpenSees::SignalMessageEnd; + return TCL_ERROR; + } + if ((strcmp(argv[i], "current") == 0) || (strcmp(argv[i], "tangent") == 0)) incrementTangent = CURRENT_TANGENT; - if (strcmp(argv[i], "initial") == 0) + else if (strcmp(argv[i], "initial") == 0) incrementTangent = INITIAL_TANGENT; - if (strcmp(argv[i], "noTangent") == 0) + else if ((strcmp(argv[i], "noTangent") == 0) || strcmp(argv[i], "None") == 0) incrementTangent = NO_TANGENT; - - } else if (strcmp(argv[i], "-maxDim") == 0 && i + 1 < argc) { + } + + else if (strcmp(argv[i], "-maxDim") == 0 && i + 1 < argc) { i++; - maxDim = atoi(argv[i]); + if (i >= argc || Tcl_GetInt(interp, argv[i], &maxDim) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Flag -maxDim requires follow up argument" + << OpenSees::SignalMessageEnd; + return TCL_ERROR; + } } - } - - Accelerator *theAccel = new KrylovAccelerator(maxDim, iterateTangent); - - EquiSolnAlgo *theNewAlgo = new AcceleratedNewton(*theTest, theAccel, incrementTangent); - return theNewAlgo; -} - -EquiSolnAlgo * -G3_newRaphsonNewton(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - assert(clientData != nullptr); - BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - ConvergenceTest *theTest = builder->getConvergenceTest(); - - if (theTest == nullptr) { - opserr << G3_ERROR_PROMPT << "No ConvergenceTest yet specified\n"; - return nullptr; - } - int incrementTangent = CURRENT_TANGENT; - int iterateTangent = CURRENT_TANGENT; - for (int i = 2; i < argc; ++i) { - if (strcmp(argv[i], "-iterate") == 0 && i + 1 < argc) { + else if (strcmp(argv[i], "-accelerator") == 0 && i + 1 < argc) { i++; - if (strcmp(argv[i], "current") == 0) - iterateTangent = CURRENT_TANGENT; - if (strcmp(argv[i], "initial") == 0) - iterateTangent = INITIAL_TANGENT; - if (strcmp(argv[i], "noTangent") == 0) - iterateTangent = NO_TANGENT; - - } else if (strcmp(argv[i], "-increment") == 0 && i + 1 < argc) { - i++; - if (strcmp(argv[i], "current") == 0) - incrementTangent = CURRENT_TANGENT; - if (strcmp(argv[i], "initial") == 0) - incrementTangent = INITIAL_TANGENT; - if (strcmp(argv[i], "noTangent") == 0) - incrementTangent = NO_TANGENT; + if (i >= argc) { + opserr << OpenSees::PromptValueError + << "Flag -accelerator requires follow up argument" + << OpenSees::SignalMessageEnd; + return TCL_ERROR; + } + if (strcmp(argv[i], "Miller") == 0) { + type = AcceleratorType::Miller; + } else if (strcmp(argv[i], "Secant") == 0 || strcmp(argv[i], "SecantNewton") == 0) { + type = AcceleratorType::Secant; + } else if (strcmp(argv[i], "Raphson") == 0 || strcmp(argv[i], "RaphsonNewton") == 0) { + type = AcceleratorType::Raphson; + } else if (strcmp(argv[i], "Krylov") == 0 || strcmp(argv[i], "KrylovNewton") == 0) { + type = AcceleratorType::Krylov; + } else if (strcmp(argv[i], "Periodic") == 0 || strcmp(argv[i], "PeriodicNewton") == 0) { + type = AcceleratorType::Periodic; + } else { + opserr << OpenSees::PromptValueError + << "Unknown accelerator '" << argv[i] << "'" + << OpenSees::SignalMessageEnd; + return TCL_ERROR; + } } - } - - Accelerator *theAccel; - theAccel = new RaphsonAccelerator(iterateTangent); - - EquiSolnAlgo *theNewAlgo = new AcceleratedNewton(*theTest, theAccel, incrementTangent); - return theNewAlgo; -} - -EquiSolnAlgo * -G3_newMillerNewton(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - assert(clientData != nullptr); - BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - ConvergenceTest *theTest = builder->getConvergenceTest(); - - if (theTest == nullptr) { - opserr << G3_ERROR_PROMPT << "No ConvergenceTest yet specified\n"; - return nullptr; - } - - int incrementTangent = CURRENT_TANGENT; - int iterateTangent = CURRENT_TANGENT; - int maxDim = 3; - for (int i = 2; i < argc; ++i) { - if (strcmp(argv[i], "-iterate") == 0 && i + 1 < argc) { - i++; - if (strcmp(argv[i], "current") == 0) - iterateTangent = CURRENT_TANGENT; - if (strcmp(argv[i], "initial") == 0) - iterateTangent = INITIAL_TANGENT; - if (strcmp(argv[i], "noTangent") == 0) - iterateTangent = NO_TANGENT; - } else if (strcmp(argv[i], "-increment") == 0 && i + 1 < argc) { - i++; - if (strcmp(argv[i], "current") == 0) - incrementTangent = CURRENT_TANGENT; - if (strcmp(argv[i], "initial") == 0) - incrementTangent = INITIAL_TANGENT; - if (strcmp(argv[i], "noTangent") == 0) - incrementTangent = NO_TANGENT; - } else if (strcmp(argv[i], "-maxDim") == 0 && i + 1 < argc) { - i++; - maxDim = atoi(argv[i]); + // SecantAccelerator + else if (strcmp(argv[i], "-numTerms") == 0) { + if (i+1 < argc) + numTerms = atoi(argv[++i]); + else { + opserr << OpenSees::PromptValueError + << "Flag -numTerms requires follow up argument" + << OpenSees::SignalMessageEnd; + return TCL_ERROR; + } } } - Accelerator *theAccel = new MillerAccelerator(maxDim, 0.01, iterateTangent); + Accelerator *accel = nullptr; + if (strcmp(argv[1], "MillerNewton") == 0) { + accel = new MillerAccelerator(maxDim, 0.01, correction_tangent); + } - EquiSolnAlgo *theNewAlgo = new AcceleratedNewton(*theTest, theAccel, incrementTangent); - return theNewAlgo; -} + else if (type == AcceleratorType::Secant || + strcmp(argv[1], "SecantNewton") == 0) { + if (numTerms <= 1) + accel = new SecantAccelerator1(maxDim, correction_tangent); + else if (numTerms >= 3) + accel = new SecantAccelerator3(maxDim, correction_tangent); + else + accel = new SecantAccelerator2(maxDim, correction_tangent); + } -EquiSolnAlgo * -G3_newPeriodicNewton(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - assert(clientData != nullptr); - BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - ConvergenceTest *theTest = builder->getConvergenceTest(); + else if (type == AcceleratorType::Raphson || + strcmp(argv[1], "RaphsonNewton") == 0) { + accel = new RaphsonAccelerator(correction_tangent, iFactor, cFactor); + } - if (theTest == nullptr) { - opserr << G3_ERROR_PROMPT << "No ConvergenceTest yet specified\n"; - return nullptr; + else if (type == AcceleratorType::Krylov || + strcmp(argv[1], "KrylovNewton") == 0) { + accel = new KrylovAccelerator(maxDim, correction_tangent); } - int incrementTangent = CURRENT_TANGENT; - int iterateTangent = CURRENT_TANGENT; - int maxDim = 3; - for (int i = 2; i < argc; ++i) { - if (strcmp(argv[i], "-iterate") == 0 && i + 1 < argc) { - i++; - if (strcmp(argv[i], "current") == 0) - iterateTangent = CURRENT_TANGENT; - if (strcmp(argv[i], "initial") == 0) - iterateTangent = INITIAL_TANGENT; - if (strcmp(argv[i], "noTangent") == 0) - iterateTangent = NO_TANGENT; - - } else if (strcmp(argv[i], "-increment") == 0 && i + 1 < argc) { - i++; - if (strcmp(argv[i], "current") == 0) - incrementTangent = CURRENT_TANGENT; - if (strcmp(argv[i], "initial") == 0) - incrementTangent = INITIAL_TANGENT; - if (strcmp(argv[i], "noTangent") == 0) - incrementTangent = NO_TANGENT; + else if (type == AcceleratorType::Periodic || + strcmp(argv[1], "PeriodicNewton") == 0) { + accel = new PeriodicAccelerator(maxDim, correction_tangent); + } - } else if (strcmp(argv[i], "-maxDim") == 0 && i + 1 < argc) { - i++; - maxDim = atoi(argv[i]); - } + else { + opserr << OpenSees::PromptValueError + << "Unknown accelerator type '" << argv[1] << "'\n"; + return TCL_ERROR; } - Accelerator *theAccel; - theAccel = new PeriodicAccelerator(maxDim, iterateTangent); + builder->set(new AcceleratedNewton(accel, incrementTangent)); - EquiSolnAlgo *theNewAlgo = nullptr; - theNewAlgo = new AcceleratedNewton(*theTest, theAccel, incrementTangent); - return theNewAlgo; + return TCL_OK; } + static EquiSolnAlgo * -G3_newBroyden(ClientData clientData, Tcl_Interp *interp, int argc, +G3_newBroyden(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - ConvergenceTest *theTest = builder->getConvergenceTest(); - int formTangent = CURRENT_TANGENT; + int correction_tangent = CURRENT_TANGENT; int count = -1; - if (theTest == nullptr) { - opserr << G3_ERROR_PROMPT << "No ConvergenceTest yet specified\n"; - return nullptr; - } for (int i = 2; i < argc; ++i) { if (strcmp(argv[i], "-secant") == 0) { - formTangent = CURRENT_SECANT; + correction_tangent = CURRENT_SECANT; } else if (strcmp(argv[i], "-initial") == 0) { - formTangent = INITIAL_TANGENT; + correction_tangent = INITIAL_TANGENT; } else if (strcmp(argv[i++], "-count") == 0 && i < argc) { count = atoi(argv[i]); @@ -761,9 +747,9 @@ G3_newBroyden(ClientData clientData, Tcl_Interp *interp, int argc, EquiSolnAlgo *theNewAlgo = nullptr; if (count == -1) - theNewAlgo = new Broyden(*theTest, formTangent); + theNewAlgo = new Broyden(correction_tangent); else - theNewAlgo = new Broyden(*theTest, formTangent, count); + theNewAlgo = new Broyden(correction_tangent, count); return theNewAlgo; } @@ -772,22 +758,22 @@ G3_newBroyden(ClientData clientData, Tcl_Interp *interp, int argc, // Other commands // int -printAlgorithm(ClientData clientData, Tcl_Interp *interp, int argc, +printAlgorithm(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv, OPS_Stream &output) { assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - EquiSolnAlgo* theAlgorithm = builder->getAlgorithm(); + const EquiSolnAlgo* theAlgorithm = builder->getAlgorithm(); int eleArg = 0; if (theAlgorithm == nullptr) { - opserr << G3_ERROR_PROMPT << "No algorithm has been set.\n"; + opserr << OpenSees::PromptValueError << "No algorithm has been set.\n"; return TCL_ERROR; } // if just 'print algorithm'- no flag if (argc == 0) { - theAlgorithm->Print(output); + theAlgorithm->Print(output, 0); return TCL_OK; } @@ -795,7 +781,7 @@ printAlgorithm(ClientData clientData, Tcl_Interp *interp, int argc, int flag; if (Tcl_GetInt(interp, argv[eleArg], &flag) != TCL_OK) { opserr << "WARNING print algorithm failed to get integer flag: \n"; - opserr << argv[eleArg] << endln; + opserr << argv[eleArg] << "\n"; return TCL_ERROR; } theAlgorithm->Print(output, flag); @@ -803,11 +789,11 @@ printAlgorithm(ClientData clientData, Tcl_Interp *interp, int argc, } int -TclCommand_accelCPU(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +TclCommand_accelCPU(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - EquiSolnAlgo* algo = builder->getAlgorithm(); + const EquiSolnAlgo* algo = builder->getAlgorithm(); if (algo == nullptr) return TCL_ERROR; @@ -817,12 +803,13 @@ TclCommand_accelCPU(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Cha return TCL_OK; } + int -TclCommand_numFact(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +TclCommand_numFact(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder *)clientData; - EquiSolnAlgo* algo = builder->getAlgorithm(); + const EquiSolnAlgo* algo = builder->getAlgorithm(); if (algo == nullptr) return TCL_ERROR; @@ -833,46 +820,17 @@ TclCommand_numFact(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char } int -TclCommand_algorithmRecorder(ClientData clientData, Tcl_Interp *interp, int argc, +TclCommand_algorithmRecorder(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { -#if 1 return TCL_ERROR; -#else - Recorder *theRecorder = nullptr; - BasicAnalysisBuilder* builder = (BasicAnalysisBuilder*)clientData; - Domain* domain = builder->getDomain(); - EquiSolnAlgo *theAlgo; - TclCreateRecorder(clientData, interp, argc, argv, *domain, &theRecorder); - - if (theRecorder == nullptr) { - char buffer[] = "-1"; - Tcl_SetResult(interp, buffer, TCL_VOLATILE); - return TCL_ERROR; - } - - // add the recorder to the domain, - // NOTE: will not be called with theALgo == 0 - if (theAlgo != nullptr) { - if ((theAlgo->addRecorder(*theRecorder)) < 0) { - opserr << "WARNING could not add to domain - recorder " << argv[1] - << endln; - delete theRecorder; - return TCL_ERROR; - } - } - - int recorderTag = theRecorder->getTag(); - Tcl_SetObjResult(interp, Tcl_NewIntObj(recorderTag)); - return TCL_OK; -#endif } int -TclCommand_totalCPU(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +TclCommand_totalCPU(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); - EquiSolnAlgo *algo = ((BasicAnalysisBuilder *)clientData)->getAlgorithm(); + const EquiSolnAlgo *algo = ((BasicAnalysisBuilder *)clientData)->getAlgorithm(); if (algo == nullptr) return TCL_ERROR; @@ -883,10 +841,10 @@ TclCommand_totalCPU(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Cha } int -TclCommand_solveCPU(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +TclCommand_solveCPU(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); - EquiSolnAlgo *algo = ((BasicAnalysisBuilder *)clientData)->getAlgorithm(); + const EquiSolnAlgo *algo = ((BasicAnalysisBuilder *)clientData)->getAlgorithm(); if (algo == nullptr) @@ -899,10 +857,10 @@ TclCommand_solveCPU(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Cha int -TclCommand_numIter(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +TclCommand_numIter(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); - EquiSolnAlgo *algo = ((BasicAnalysisBuilder *)clientData)->getAlgorithm(); + const EquiSolnAlgo *algo = ((BasicAnalysisBuilder *)clientData)->getAlgorithm(); if (algo == nullptr) return TCL_ERROR; diff --git a/SRC/runtime/commands/analysis/analysis.cpp b/SRC/runtime/commands/analysis/analysis.cpp index ef3cc9da1f..2b3b6deda2 100644 --- a/SRC/runtime/commands/analysis/analysis.cpp +++ b/SRC/runtime/commands/analysis/analysis.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -9,8 +18,9 @@ // #include #include +#include #include -#include +#include #include #include @@ -20,10 +30,6 @@ #include "BasicAnalysisBuilder.h" -#include -#include -#include - #include #include // for printA @@ -44,35 +50,37 @@ #include // numberers -#include -#include +#include +#include #include "analysis.h" -// for response spectrum analysis -extern void OPS_DomainModalProperties(G3_Runtime*); -extern int OPS_ResponseSpectrumAnalysis(G3_Runtime*); +// extern int OPS_ResponseSpectrumAnalysis(G3_Runtime*); extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, Tcl_Interp *interp, int cArg, int mArg, TCL_Char ** const argv, Domain *domain); Tcl_CmdProc TclCommand_clearAnalysis; Tcl_CmdProc TclCommand_setNumberer; +namespace OpenSees { +Tcl_CmdProc responseSpectrumAnalysis; +} // // Add commands to the interpreter that take the AnalysisBuilder as clientData. // int -G3_AddTclAnalysisAPI(Tcl_Interp *interp, Domain* domain) +G3_AddTclAnalysisAPI(Tcl_Interp *interp, BasicModelBuilder& context) { - - BasicAnalysisBuilder *builder = new BasicAnalysisBuilder(domain); + BasicAnalysisBuilder *builder = new BasicAnalysisBuilder(context); Tcl_CreateCommand(interp, "wipeAnalysis", &wipeAnalysis, builder, nullptr); Tcl_CreateCommand(interp, "_clearAnalysis", &TclCommand_clearAnalysis, builder, nullptr); Tcl_CreateCommand(interp, "numberer", TclCommand_setNumberer, builder, nullptr); + Tcl_CreateCommand(interp, "responseSpectrumAnalysis", &OpenSees::responseSpectrumAnalysis, nullptr, nullptr); + static int ncmd = sizeof(tcl_analysis_cmds)/sizeof(char_cmd); for (int i = 0; i < ncmd; ++i) @@ -88,14 +96,15 @@ G3_AddTclAnalysisAPI(Tcl_Interp *interp, Domain* domain) // command invoked to build an Analysis object // static int -specifyAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, +specifyAnalysis(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "need to specify an analysis type (Static, Transient)\n"; + opserr << OpenSees::PromptValueError + << "need to specify an analysis type (Static, Transient)\n"; return TCL_ERROR; } @@ -103,7 +112,7 @@ specifyAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, if (strcmp(argv[argi], "-linear") == 0) { if (argc < 3) { - opserr << G3_ERROR_PROMPT << "need to specify an analysis type (Static, Transient)\n"; + opserr << OpenSees::PromptValueError << "need to specify an analysis type (Static, Transient)\n"; return TCL_ERROR; } Tcl_Eval(interp, "algorithm Linear\n" @@ -127,7 +136,7 @@ specifyAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, return TCL_ERROR; } else { - opserr << G3_ERROR_PROMPT << "Analysis type '" << argv[1] + opserr << OpenSees::PromptValueError << "Analysis type '" << argv[1] << "' does not exists (Static or Transient only). \n"; return TCL_ERROR; } @@ -140,35 +149,55 @@ specifyAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, // on the Analysis object // static int -analyzeModel(ClientData clientData, Tcl_Interp *interp, int argc, +analyzeModel(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder*)clientData; - VariableTimeStepDirectIntegrationAnalysis* theVariableTimeStepTransientAnalysis = - builder->getVariableTimeStepDirectIntegrationAnalysis(); - int result = 0; + int commit = BasicAnalysisBuilder::Increment + | BasicAnalysisBuilder::Iterate + | BasicAnalysisBuilder::Commit; + + for (int i=2; iCurrentAnalysisFlag) { case BasicAnalysisBuilder::STATIC_ANALYSIS: { int numIncr; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "static analysis: analysis numIncr?\n"; + opserr << OpenSees::PromptValueError << "static analysis: analysis numIncr?\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[1], &numIncr) != TCL_OK) return TCL_ERROR; - result = builder->analyze(numIncr, 0.0); + result = builder->analyze(numIncr, 0.0, commit); break; } case BasicAnalysisBuilder::TRANSIENT_ANALYSIS: { double dT; int numIncr; if (argc < 3) { - opserr << G3_ERROR_PROMPT << "transient analysis: analysis numIncr? deltaT?\n"; + opserr << OpenSees::PromptValueError << "transient analysis: analysis numIncr? deltaT?\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[1], &numIncr) != TCL_OK) @@ -186,36 +215,26 @@ analyzeModel(ClientData clientData, Tcl_Interp *interp, int argc, if (Tcl_GetInt(interp, argv[5], &Jd) != TCL_OK) return TCL_ERROR; - if (theVariableTimeStepTransientAnalysis != nullptr) - result = theVariableTimeStepTransientAnalysis->analyze( - numIncr, dT, dtMin, dtMax, Jd); - else { - opserr << G3_ERROR_PROMPT << "analyze - no variable time step transient analysis " - "object constructed\n"; - return TCL_ERROR; - } + result = builder->analyzeVariable(numIncr, dT, dtMin, dtMax, Jd); } else { - // result = theTransientAnalysis->analyze(numIncr, dT); - result = builder->analyze(numIncr, dT); + result = builder->analyze(numIncr, dT, commit); } break; } default: - opserr << G3_ERROR_PROMPT << "No Analysis type has been specified \n"; + opserr << OpenSees::PromptValueError << "No Analysis type has been specified \n"; return TCL_ERROR; } - char buffer[10]; - sprintf(buffer, "%d", result); - Tcl_SetResult(interp, buffer, TCL_VOLATILE); + Tcl_SetObjResult(interp, Tcl_NewIntObj(result)); return TCL_OK; } static int -initializeAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, +initializeAnalysis(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -228,11 +247,9 @@ initializeAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, static int -eigenAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, +eigenAnalysis(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { - static char *resDataPtr = 0; - static int resDataSize = 0; BasicAnalysisBuilder *builder = (BasicAnalysisBuilder*)clientData; @@ -241,7 +258,7 @@ eigenAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, // make sure at least one other argument to contain type of system if (argc < 2) { - opserr << G3_ERROR_PROMPT << "eigen numModes?\n"; + opserr << OpenSees::PromptValueError << "eigen numModes?\n"; return TCL_ERROR; } @@ -299,22 +316,10 @@ eigenAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, // check argv[loc] for number of modes if ((Tcl_GetInt(interp, argv[loc], &numEigen) != TCL_OK) || numEigen < 0) { - opserr << G3_ERROR_PROMPT << "eigen numModes? - invalid numModes\n"; + opserr << OpenSees::PromptValueError << "eigen numModes? - invalid numModes\n"; return TCL_ERROR; } - int requiredDataSize = 40 * numEigen; - if (requiredDataSize > resDataSize) { - if (resDataPtr != nullptr) - delete[] resDataPtr; - - resDataPtr = new char[requiredDataSize]; - resDataSize = requiredDataSize; - } - - for (int i = 0; i < requiredDataSize; ++i) - resDataPtr[i] = '\n'; - // // create a transient analysis if no analysis exists // @@ -322,43 +327,25 @@ eigenAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, int result = builder->eigen(numEigen,generalizedAlgo,findSmallest); + Tcl_Obj* eig_values = Tcl_NewListObj(numEigen, nullptr); + if (result == 0) { const Vector &eigenvalues = domain->getEigenvalues(); - int cnt = 0; for (int i = 0; i < numEigen; ++i) { - cnt += sprintf(&resDataPtr[cnt], "%35.20f ", eigenvalues[i]); + Tcl_ListObjAppendElement(interp, eig_values, Tcl_NewDoubleObj(eigenvalues[i])); } - - Tcl_SetResult(interp, resDataPtr, TCL_STATIC); } + Tcl_SetObjResult(interp, eig_values); return TCL_OK; } -static int -modalProperties(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - G3_Runtime *rt = G3_getRuntime(interp); - OPS_ResetInputNoBuilder(clientData, interp, 1, argc, argv, nullptr); - OPS_DomainModalProperties(rt); - return TCL_OK; -} -static int -responseSpectrum(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - OPS_ResetInputNoBuilder(clientData, interp, 1, argc, argv, nullptr); - G3_Runtime *rt = G3_getRuntime(interp); - OPS_ResponseSpectrumAnalysis(rt); - return TCL_OK; -} // TODO: Move this to commands/modeling/damping.cpp? ...but it uses and // AnalysisBuilder static int -modalDamping(ClientData clientData, Tcl_Interp *interp, int argc, +modalDamping(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -367,7 +354,7 @@ modalDamping(ClientData clientData, Tcl_Interp *interp, int argc, if (argc < 2) { opserr - << G3_ERROR_PROMPT << argv[0] << " ?factor - not enough arguments to command\n"; + << OpenSees::PromptValueError << argv[0] << " ?factor - not enough arguments to command\n"; return TCL_ERROR; } @@ -398,7 +385,8 @@ modalDamping(ClientData clientData, Tcl_Interp *interp, int argc, if (numModes != 1 && numModes != numEigen) { // TODO: Just call eigen again? - opserr << G3_ERROR_PROMPT << "modalDampingQ - same number of damping factors as modes must be " + opserr << OpenSees::PromptValueError + << "modalDampingQ - same number of damping factors as modes must be " "specified\n"; // opserr << " - same damping ratio will be applied to all\n"; return TCL_ERROR; @@ -412,7 +400,7 @@ modalDamping(ClientData clientData, Tcl_Interp *interp, int argc, // read in all factors one at a time for (int i = 0; i < numEigen; ++i) { if (Tcl_GetDouble(interp, argv[1 + i], &factor) != TCL_OK) { - opserr << G3_ERROR_PROMPT << argv[0] << " - could not read factor at position " + opserr << OpenSees::PromptValueError << argv[0] << " - could not read factor at position " << i << "\n"; return TCL_ERROR; } @@ -422,7 +410,7 @@ modalDamping(ClientData clientData, Tcl_Interp *interp, int argc, } else { // read in one & set all factors to that value if (Tcl_GetDouble(interp, argv[1], &factor) != TCL_OK) { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "rayleigh alphaM? betaK? betaK0? betaKc? - could not " "read betaK? \n"; return TCL_ERROR; @@ -441,7 +429,7 @@ modalDamping(ClientData clientData, Tcl_Interp *interp, int argc, } static int -resetModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +resetModel(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder*)clientData; @@ -459,7 +447,7 @@ resetModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** cons int -printIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, +printIntegrator(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv, OPS_Stream &output) { assert(clientData != nullptr); @@ -472,37 +460,36 @@ printIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, if (the_static_integrator == nullptr && theTransientIntegrator == nullptr) return TCL_OK; - Integrator *theIntegrator; - if (the_static_integrator != 0) - theIntegrator = the_static_integrator; - else - theIntegrator = theTransientIntegrator; - - // if just 'print integrator'- no flag - if (argc == 0) { - theIntegrator->Print(output); - return TCL_OK; - } - // if 'print Algorithm flag' get the flag - int flag; - if (Tcl_GetInt(interp, argv[eleArg], &flag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "print algorithm failed to get integer flag: \n"; - opserr << argv[eleArg] << endln; - return TCL_ERROR; + int flag = 0; + if (argc > 2) { + if (Tcl_GetInt(interp, argv[eleArg], &flag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "print algorithm failed to get integer flag: \n"; + opserr << argv[eleArg] << endln; + return TCL_ERROR; + } } - theIntegrator->Print(output, flag); + + if (the_static_integrator != 0) + the_static_integrator->Print(output, flag); + else + theTransientIntegrator->Print(output, flag); return TCL_OK; } static int -printA(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +printA(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { + // printA - m -c -k assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder*)clientData; int res = 0; + enum class Format { + None + } format = Format::None; + FileStream outputFile; OPS_Stream *output = &opserr; LinearSOE *oldSOE = builder->getLinearSOE(); @@ -520,9 +507,9 @@ printA(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const ar bool ret = false; - int currentArg = 1; double m = 0.0, c = 0.0, k = 0.0; bool do_mck = false; + int currentArg = 1; while (currentArg < argc) { if ((strcmp(argv[currentArg], "file") == 0) || (strcmp(argv[currentArg], "-file") == 0)) { @@ -533,19 +520,20 @@ printA(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const ar } if (outputFile.setFile(argv[currentArg]) != 0) { - opserr << "printA .. - failed to open file: " - << argv[currentArg] << endln; + opserr << "failed to open file: " + << argv[currentArg] << "\n"; return TCL_ERROR; } output = &outputFile; - } else if ((strcmp(argv[currentArg], "ret") == 0) || + } + else if ((strcmp(argv[currentArg], "ret") == 0) || (strcmp(argv[currentArg], "-ret") == 0)) { ret = true; } else if ((strcmp(argv[currentArg], "-m") == 0)) { currentArg++; if (Tcl_GetDouble(interp, argv[currentArg], &m) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "failed to read float following flag -m\n"; + opserr << OpenSees::PromptValueError << "failed to read float following flag -m\n"; return TCL_ERROR; } do_mck = true; @@ -553,7 +541,7 @@ printA(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const ar } else if ((strcmp(argv[currentArg], "-c") == 0)) { currentArg++; if (Tcl_GetDouble(interp, argv[currentArg], &c) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "failed to read float following flag -c\n"; + opserr << OpenSees::PromptValueError << "failed to read float following flag -c\n"; return TCL_ERROR; } do_mck = true; @@ -561,7 +549,7 @@ printA(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const ar } else if ((strcmp(argv[currentArg], "-k") == 0)) { currentArg++; if (Tcl_GetDouble(interp, argv[currentArg], &k) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "failed to read float following flag -k\n"; + opserr << OpenSees::PromptValueError << "failed to read float following flag -k\n"; return TCL_ERROR; } do_mck = true; @@ -593,7 +581,11 @@ printA(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const ar builder->getTransientIntegrator()->formTangent(0); builder->getTransientIntegrator()->revertToLastStep(); } - builder->getDomain()->revertToLastCommit(); + else { + opserr << OpenSees::PromptValueError + << "No integrator has been set, cannot form tangent\n"; + return TCL_ERROR; + } const Matrix *A = theSOE.getA(); if (A == nullptr) { @@ -602,37 +594,40 @@ printA(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const ar return TCL_ERROR; } - if (ret) { - int n = A->noRows(); - int m = A->noCols(); - if (n*m == 0) { - opserr << OpenSees::PromptValueError - << "linear system is empty\n"; - return TCL_ERROR; - } + if (format == Format::None) { + if (ret) { + int n = A->noRows(); + int m = A->noCols(); + if (n*m == 0) { + opserr << OpenSees::PromptValueError + << "linear system is empty, got n=" << n << " m= " << m << "\n"; + return TCL_ERROR; + } - // Create an empty list with space preallocated for - // n*m elements. This is not formally documented, but - // it is mentioned here - // https://wiki.tcl-lang.org/page/Tcl_NewListObj - // - // and evident from the source code here: - // https://github.com/enthought/tcl/blob/master/generic/tclListObj.c - // - Tcl_Obj* list = Tcl_NewListObj(n*m, nullptr); + // Create an empty list with space preallocated for + // n*m elements. This is not formally documented, but + // it is mentioned here + // https://wiki.tcl-lang.org/page/Tcl_NewListObj + // + // and evident from the source code here: + // https://github.com/enthought/tcl/blob/master/generic/tclListObj.c + // + Tcl_Obj* list = Tcl_NewListObj(n*m, nullptr); - for (int i = 0; i < n; ++i) { - for (int j = 0; j < m; j++) - Tcl_ListObjAppendElement(interp, list, Tcl_NewDoubleObj((*A)(i, j))); - } - Tcl_SetObjResult(interp, list); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < m; j++) + Tcl_ListObjAppendElement(interp, list, Tcl_NewDoubleObj((*A)(i, j))); + } + Tcl_SetObjResult(interp, list); - } else { - *output << *A; - outputFile.close(); + } else { + *output << *A; + outputFile.close(); + } } + builder->getDomain()->revertToLastCommit(); // put the original SOE back. if (oldSOE != nullptr) builder->set(oldSOE, true); @@ -644,7 +639,7 @@ printA(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const ar } static int -printB(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +printB(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); BasicAnalysisBuilder *builder = (BasicAnalysisBuilder*)clientData; @@ -707,9 +702,9 @@ printB(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const ar return res; } -// This is removed in model.cpp +// This is removed from the Tcl_Interp in model.cpp extern int -TclCommand_clearAnalysis(ClientData cd, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +TclCommand_clearAnalysis(ClientData cd, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { if (cd != nullptr) { @@ -729,7 +724,7 @@ TclCommand_clearAnalysis(ClientData cd, Tcl_Interp *interp, int argc, TCL_Char * } static int -wipeAnalysis(ClientData cd, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +wipeAnalysis(ClientData cd, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { if (cd != nullptr) { @@ -744,7 +739,7 @@ wipeAnalysis(ClientData cd, Tcl_Interp *interp, int argc, TCL_Char ** const argv // command invoked to allow the ConstraintHandler object to be built // static int -specifyConstraintHandler(ClientData clientData, Tcl_Interp *interp, int argc, +specifyConstraintHandler(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { @@ -752,7 +747,7 @@ specifyConstraintHandler(ClientData clientData, Tcl_Interp *interp, int argc, // make sure at least one other argument to contain type name if (argc < 2) { - opserr << G3_ERROR_PROMPT << "need to specify a constraint type \n"; + opserr << OpenSees::PromptValueError << "need to specify a constraint type \n"; return TCL_ERROR; } @@ -791,7 +786,7 @@ specifyConstraintHandler(ClientData clientData, Tcl_Interp *interp, int argc, } else { - opserr << G3_ERROR_PROMPT << "ConstraintHandler type '" << argv[1] + opserr << OpenSees::PromptValueError << "ConstraintHandler type '" << argv[1] << "' does not exists \n\t(Plain, Penalty, Lagrange, Transformation) only\n"; return TCL_ERROR; } diff --git a/SRC/runtime/commands/analysis/analysis.h b/SRC/runtime/commands/analysis/analysis.h index e28e8f9ca7..fff885de18 100644 --- a/SRC/runtime/commands/analysis/analysis.h +++ b/SRC/runtime/commands/analysis/analysis.h @@ -1,9 +1,17 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// // #include // @@ -13,8 +21,6 @@ static Tcl_CmdProc wipeAnalysis; // static Tcl_CmdProc specifyAnalysis; static Tcl_CmdProc eigenAnalysis; -static Tcl_CmdProc modalProperties; -static Tcl_CmdProc responseSpectrum; static Tcl_CmdProc printA; static Tcl_CmdProc printB; static Tcl_CmdProc initializeAnalysis; @@ -29,6 +35,7 @@ extern Tcl_CmdProc specifyIntegrator; // commands/analysis/solver.cpp extern Tcl_CmdProc specifySOE; extern Tcl_CmdProc specifySysOfEqnTable; +extern Tcl_CmdProc TclCommand_systemSize; // commands/analysis/algorithm.cpp extern Tcl_CmdProc TclCommand_specifyAlgorithm; @@ -44,11 +51,16 @@ extern Tcl_CmdProc getCTestNorms; extern Tcl_CmdProc getCTestIter; extern Tcl_CmdProc TclCommand_algorithmRecorder; +// from commands/analysis/sensitivity.cpp +extern Tcl_CmdProc TclCommand_sensitivityAlgorithm; +extern Tcl_CmdProc TclCommand_sensLambda; + struct char_cmd { const char* name; Tcl_CmdProc* func; -} const tcl_analysis_cmds[] = { +} const tcl_analysis_cmds[] = { {"system", &specifySysOfEqnTable}, + {"systemSize", &TclCommand_systemSize}, {"test", &specifyCTest}, {"testIter", &getCTestIter}, @@ -61,10 +73,8 @@ struct char_cmd { {"analyze", &analyzeModel}, {"initialize", &initializeAnalysis}, - {"modalProperties", &modalProperties}, {"modalDamping", &modalDamping}, {"modalDampingQ", &modalDamping}, - {"responseSpectrum", &responseSpectrum}, {"printA", &printA}, {"printB", &printB}, {"reset", &resetModel}, @@ -78,5 +88,9 @@ struct char_cmd { {"solveCPU", &TclCommand_solveCPU}, // recorder.cpp {"algorithmRecorder", &TclCommand_algorithmRecorder}, + + // sensitivity + {"sensitivityAlgorithm", TclCommand_sensitivityAlgorithm}, + {"sensLambda", TclCommand_sensLambda}, }; diff --git a/SRC/runtime/commands/analysis/ctest.cpp b/SRC/runtime/commands/analysis/ctest.cpp index 52e0e2422d..a3c2c75e5c 100644 --- a/SRC/runtime/commands/analysis/ctest.cpp +++ b/SRC/runtime/commands/analysis/ctest.cpp @@ -1,9 +1,18 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// -// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// // Description: This file implements the selection of a convergence test. // #include @@ -14,7 +23,7 @@ #include #include -// convergence tests +// Convergence tests #include #include #include @@ -27,7 +36,7 @@ #include -ConvergenceTest* +static ConvergenceTest* TclDispatch_newConvergenceTest(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char ** const argv); @@ -51,7 +60,7 @@ specifyCTest(ClientData clientData, Tcl_Interp *interp, int argc, G3_Char ** con return TCL_OK; } -ConvergenceTest* +static ConvergenceTest* TclDispatch_newConvergenceTest(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char ** const argv) { // get the tolerence first @@ -70,12 +79,13 @@ TclDispatch_newConvergenceTest(ClientData clientData, Tcl_Interp* interp, int ar // make sure at least one other argument to contain test type if (argc < 2) { - opserr << G3_ERROR_PROMPT << "need to specify a ConvergenceTest type \n"; + opserr << OpenSees::PromptValueError << "need to specify a ConvergenceTest type \n"; return nullptr; } if ((strcmp(argv[1], "NormDispAndUnbalance") == 0) || - (strcmp(argv[1], "NormDispOrUnbalance") == 0)) { + (strcmp(argv[1], "NormDispOrUnbalance") == 0)) + { if (argc == 5) { if (Tcl_GetDouble(interp, argv[2], &tol) != TCL_OK) return nullptr; @@ -118,8 +128,8 @@ TclDispatch_newConvergenceTest(ClientData clientData, Tcl_Interp* interp, int ar if (Tcl_GetInt(interp, argv[7], &maxIncr) != TCL_OK) return nullptr; } - - } else if (strcmp(argv[1], "FixedNumIter") == 0) { + } + else if (strcmp(argv[1], "FixedNumIter") == 0) { // test FixedNumIter $iter <$pFlag> <$nType> if (argc == 3) { if (Tcl_GetInt(interp, argv[2], &numIter) != TCL_OK) @@ -146,8 +156,8 @@ TclDispatch_newConvergenceTest(ClientData clientData, Tcl_Interp* interp, int ar if (Tcl_GetDouble(interp, argv[5], &maxTol) != TCL_OK) return nullptr; } - - } else { + } + else { // // All others // @@ -222,40 +232,44 @@ TclDispatch_newConvergenceTest(ClientData clientData, Tcl_Interp* interp, int ar break; } - ConvergenceTest *theNewTest = nullptr; if (numIter == 0) { - opserr << G3_ERROR_PROMPT << "no numIter specified in test command\n"; + opserr << OpenSees::PromptValueError << "no numIter specified in test command\n"; return nullptr; } + + // ConvergenceTest *theNewTest = nullptr; if (strcmp(argv[1], "FixedNumIter") == 0) - theNewTest = new CTestFixedNumIter(numIter, flag, normType); + return new CTestFixedNumIter(numIter, flag, normType); else { if (tol == 0.0) { - opserr << G3_ERROR_PROMPT << "no tolerance specified in test command\n"; + opserr << OpenSees::PromptValueError << "no tolerance specified in test command\n"; return nullptr; } - if (strcmp(argv[1], "NormUnbalance") == 0) + if ((strcmp(argv[1], "Residual") == 0) || (strcmp(argv[1], "NormUnbalance") == 0)) return new CTestNormUnbalance(tol, numIter, flag, normType, maxIncr, maxTol); - else if (strcmp(argv[1], "NormDispIncr") == 0) + else if ((strcmp(argv[1], "Correction") == 0) || (strcmp(argv[1], "NormDispIncr") == 0)) return new CTestNormDispIncr(tol, numIter, flag, normType, maxTol); - else if (strcmp(argv[1], "NormDispAndUnbalance") == 0) - return new NormDispAndUnbalance(tol, tol2, numIter, flag, - normType, maxIncr); + else if ((strcmp(argv[1], "EnergyIncr") == 0) || + (strcmp(argv[1], "Energy") == 0)) + return new CTestEnergyIncr(tol, numIter, flag, normType, maxTol); + + + else if ((strcmp(argv[1], "Residual&Correction") == 0) || + (strcmp(argv[1], "Correction&Residual") == 0) || + (strcmp(argv[1], "NormDispAndUnbalance") == 0)) + return new NormDispAndUnbalance(tol, tol2, numIter, flag, normType, maxIncr); else if (strcmp(argv[1], "NormDispOrUnbalance") == 0) return new NormDispOrUnbalance(tol, tol2, numIter, flag, normType, maxIncr); - else if (strcmp(argv[1], "EnergyIncr") == 0) - theNewTest = new CTestEnergyIncr(tol, numIter, flag, normType, maxTol); - else if (strcmp(argv[1], "RelativeNormUnbalance") == 0) return new CTestRelativeNormUnbalance(tol, numIter, flag, normType); @@ -269,11 +283,12 @@ TclDispatch_newConvergenceTest(ClientData clientData, Tcl_Interp* interp, int ar return new CTestRelativeTotalNormDispIncr(tol, numIter, flag, normType); else { - opserr << G3_ERROR_PROMPT << "unknown ConvergenceTest type"; + opserr << OpenSees::PromptValueError << "unknown ConvergenceTest type"; return nullptr; } } - return theNewTest; + + return nullptr; } int @@ -297,7 +312,7 @@ getCTestNorms(ClientData clientData, Tcl_Interp *interp, int argc, return TCL_OK; } - opserr << G3_ERROR_PROMPT << "testNorms - no convergence test has been constructed.\n"; + opserr << OpenSees::PromptValueError << "no convergence test has been defined.\n"; return TCL_ERROR; } @@ -318,7 +333,7 @@ getCTestIter(ClientData clientData, Tcl_Interp *interp, int argc, G3_Char ** con return TCL_OK; } - opserr << G3_ERROR_PROMPT << "testIter - no convergence test.\n"; + opserr << OpenSees::PromptValueError << "no convergence test was found.\n"; return TCL_ERROR; } diff --git a/SRC/runtime/commands/analysis/integrator.cpp b/SRC/runtime/commands/analysis/integrator.cpp index 3a846cb0a1..673cfb9861 100644 --- a/SRC/runtime/commands/analysis/integrator.cpp +++ b/SRC/runtime/commands/analysis/integrator.cpp @@ -1,15 +1,24 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // -// Description: This file implements selection of an integrator object. +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Description: This file implements selection of an integrator. // -#include -#include "integrator.h" -#include #include +#include +#include +#include #include #include #include @@ -23,6 +32,71 @@ #include #include +// +// Helpers +// + +// Type 1 +template +static int +dispatch(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char** const argv) +{ + BasicAnalysisBuilder *builder = static_cast(clientData); + Type* theIntegrator = (Type*)fn( G3_getRuntime(interp), argc, argv ); + + if (theIntegrator == nullptr) + return TCL_ERROR; + + + opsdbg << G3_DEBUG_PROMPT << "Set integrator to \n"; + theIntegrator->Print(opsdbg); + builder->set(*theIntegrator); + return TCL_OK; +} + +// Type 2 +template +static int +dispatch(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char** const argv) +{ + assert(clientData != nullptr); + + + Type* theIntegrator = fn( clientData, interp, argc, argv ); + + if (theIntegrator == nullptr) + return TCL_ERROR; + + BasicAnalysisBuilder *builder = static_cast(clientData); + + opsdbg << G3_DEBUG_PROMPT << "Set integrator to \n"; + theIntegrator->Print(opsdbg); + builder->set(*theIntegrator); + return TCL_OK; +} + +// Type 3 +template +static int +dispatch(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char** const argv) +{ + assert(clientData != nullptr); + return fn( clientData, interp, argc, argv ); +} + +#define DISPATCH(Type, Class) \ + (Tcl_CmdProc*)[](ClientData clientData, Tcl_Interp*, int, G3_Char**const)->int{ \ + BasicAnalysisBuilder *builder = static_cast(clientData); \ + Type* theIntegrator = new Class(); \ + opsdbg << G3_DEBUG_PROMPT << "Set integrator to \n"; \ + theIntegrator->Print(opsdbg); \ + builder->set(*theIntegrator); \ + return TCL_OK; \ + } + +#include "integrator.h" + + extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, Tcl_Interp *interp, int cArg, int mArg, TCL_Char ** const argv, Domain *domain); @@ -60,7 +134,7 @@ specifyIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char int TclCommand_newStaticIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { - BasicAnalysisBuilder *builder = (BasicAnalysisBuilder*)clientData; + BasicAnalysisBuilder *builder = static_cast(clientData); auto tcl_cmd = StaticIntegratorLibrary.find(std::string(argv[1])); if (tcl_cmd != StaticIntegratorLibrary.end()) @@ -100,7 +174,7 @@ TclCommand_newStaticIntegrator(ClientData clientData, Tcl_Interp *interp, int ar int TclCommand_newTransientIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { - BasicAnalysisBuilder *builder = (BasicAnalysisBuilder*)clientData; + BasicAnalysisBuilder *builder = static_cast(clientData); auto tcl_cmd = TransientIntegratorLibrary.find(std::string(argv[1])); if (tcl_cmd != TransientIntegratorLibrary.end()) @@ -136,7 +210,7 @@ TclCommand_newTransientIntegrator(ClientData clientData, Tcl_Interp *interp, int } #include -StaticIntegrator* +int G3Parse_newHSIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]) { double arcLength, psi_u, psi_f, u_ref; @@ -144,57 +218,78 @@ G3Parse_newHSIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, con if (argc < 3) { opserr << "WARNING integrator HSConstraint " " \n"; - return nullptr; + return TCL_ERROR;; } + if (argc >= 3 && Tcl_GetDouble(interp, argv[2], &arcLength) != TCL_OK) - return nullptr; + return TCL_ERROR;; if (argc >= 4 && Tcl_GetDouble(interp, argv[3], &psi_u) != TCL_OK) - return nullptr; + return TCL_ERROR;; if (argc >= 5 && Tcl_GetDouble(interp, argv[4], &psi_f) != TCL_OK) - return nullptr; + return TCL_ERROR;; if (argc == 6 && Tcl_GetDouble(interp, argv[5], &u_ref) != TCL_OK) - return nullptr; + return TCL_ERROR;; + // Create the integrator + StaticIntegrator* theStaticIntegrator = nullptr; switch (argc) { case 3: - return new HSConstraint(arcLength); + theStaticIntegrator = new HSConstraint(arcLength); + break; case 4: - return new HSConstraint(arcLength, psi_u); + theStaticIntegrator = new HSConstraint(arcLength, psi_u); + break; case 5: - return new HSConstraint(arcLength, psi_u, psi_f); + theStaticIntegrator = new HSConstraint(arcLength, psi_u, psi_f); + break; case 6: - return new HSConstraint(arcLength, psi_u, psi_f, u_ref); - default: - return nullptr; + theStaticIntegrator = new HSConstraint(arcLength, psi_u, psi_f, u_ref); + break; } + + if (theStaticIntegrator == nullptr) + return TCL_ERROR; + + + BasicAnalysisBuilder *builder = static_cast(clientData); + + builder->set(*theStaticIntegrator); + return TCL_OK; } -StaticIntegrator* +int G3Parse_newLoadControl(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[]) { - double dLambda; - double minIncr, maxIncr; - int numIter; - if (argc < 3) { - opserr << "WARNING incorrect # args - integrator LoadControl dlam \n"; - return nullptr; - } - if (Tcl_GetDouble(interp, argv[2], &dLambda) != TCL_OK) - return nullptr; - if (argc > 5) { - if (Tcl_GetInt(interp, argv[3], &numIter) != TCL_OK) - return nullptr; - if (Tcl_GetDouble(interp, argv[4], &minIncr) != TCL_OK) - return nullptr; - if (Tcl_GetDouble(interp, argv[5], &maxIncr) != TCL_OK) - return nullptr; - } else { - minIncr = dLambda; - maxIncr = dLambda; - numIter = 1; - } - return new LoadControl(dLambda, numIter, minIncr, maxIncr); + double dLambda; + double minIncr, maxIncr; + int numIter; + if (argc < 3) { + opserr << "WARNING incorrect # args - integrator LoadControl dlam \n"; + return TCL_ERROR;; + } + if (Tcl_GetDouble(interp, argv[2], &dLambda) != TCL_OK) + return TCL_ERROR;; + if (argc > 5) { + if (Tcl_GetInt(interp, argv[3], &numIter) != TCL_OK) + return TCL_ERROR;; + if (Tcl_GetDouble(interp, argv[4], &minIncr) != TCL_OK) + return TCL_ERROR;; + if (Tcl_GetDouble(interp, argv[5], &maxIncr) != TCL_OK) + return TCL_ERROR;; + } else { + minIncr = dLambda; + maxIncr = dLambda; + numIter = 1; + } + + StaticIntegrator *theStaticIntegrator = + new LoadControl(dLambda, numIter, minIncr, maxIncr); + + BasicAnalysisBuilder *builder = static_cast(clientData); + + builder->set(*theStaticIntegrator); + return TCL_OK; } #include @@ -213,8 +308,6 @@ G3Parse_newEQPathIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, if (Tcl_GetDouble(interp, argv[2], &arcLength) != TCL_OK) { opserr << "WARNING integrator EQPath $arc_length $type \n"; - opserr << " https://doi.org/10.12989/sem.2013.48.6.849 \n"; - opserr << " https://doi.org/10.12989/sem.2013.48.6.879 \n"; return nullptr; } @@ -232,7 +325,8 @@ G3Parse_newEQPathIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, #include StaticIntegrator * -G3Parse_newArcLengthIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +G3Parse_newArcLengthIntegrator(ClientData clientData, Tcl_Interp *interp, + Tcl_Size argc, TCL_Char ** const argv) { double arcLength; double alpha = 1.0; @@ -246,7 +340,7 @@ G3Parse_newArcLengthIntegrator(ClientData clientData, Tcl_Interp *interp, int ar // Begin parse if (argc < 3) { - opserr << G3_ERROR_PROMPT << "integrator ArcLength arcLength alpha \n"; + opserr << OpenSees::PromptValueError << "integrator ArcLength arcLength alpha \n"; return nullptr; } @@ -259,13 +353,13 @@ G3Parse_newArcLengthIntegrator(ClientData clientData, Tcl_Interp *interp, int ar } else if ((strcmp(argv[i], "-exp") == 0)) { if (++i >= argc || Tcl_GetDouble(interp, argv[i], &expon) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "failed to read expon\n"; + opserr << OpenSees::PromptValueError << "failed to read expon\n"; return nullptr; } } else if ((strcmp(argv[i], "-j") == 0)) { if (++i >= argc || Tcl_GetDouble(interp, argv[i], &numIter) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "failed to read iter\n"; + opserr << OpenSees::PromptValueError << "failed to read iter\n"; return nullptr; } } @@ -273,9 +367,11 @@ G3Parse_newArcLengthIntegrator(ClientData clientData, Tcl_Interp *interp, int ar if (++i < argc && strcmp(argv[i], "point")==0) { reference = ReferencePattern::Point; } - } else if (!got_alpha) { + } + else if (!got_alpha) { if (Tcl_GetDouble(interp, argv[i], &alpha) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "failed to read alpha, got " << argv[i] << "\n"; + opserr << OpenSees::PromptValueError + << "failed to read alpha, got " << argv[i] << "\n"; return nullptr; } got_alpha = true; @@ -299,7 +395,7 @@ G3Parse_newMinUnbalDispNormIntegrator(ClientData clientData, Tcl_Interp* interp, double lambda11; if (Tcl_GetDouble(interp, argv[2], &lambda11) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "expected float for lambda11 but got " << argv[2] << "\n"; + opserr << OpenSees::PromptValueError << "expected float for lambda11 but got " << argv[2] << "\n"; return nullptr; } @@ -332,10 +428,12 @@ G3Parse_newMinUnbalDispNormIntegrator(ClientData clientData, Tcl_Interp* interp, } else if ((recvd&MinLamb) == 0) { if (Tcl_GetDouble(interp, argv[i], &minlambda) != TCL_OK) return nullptr; + recvd |= MinLamb; } else if ((recvd&MaxLamb) == 0) { if (Tcl_GetDouble(interp, argv[i], &maxlambda) != TCL_OK) return nullptr; + recvd |= MaxLamb; } } @@ -417,35 +515,6 @@ G3Parse_newDisplacementControlIntegrator(ClientData clientData, Tcl_Interp *inte #endif } -#if 0 -StaticIntegrator* -G3Parse_newStagedLoadControlIntegrator(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - double dLambda; - double minIncr, maxIncr; - int numIter; - if (argc < 3) { - opserr << "WARNING incorrect # args - integrator StagedLoadControl dlam " - "\n"; - return nullptr; - } - if (Tcl_GetDouble(interp, argv[2], &dLambda) != TCL_OK) - return nullptr; - if (argc > 5) { - if (Tcl_GetInt(interp, argv[3], &numIter) != TCL_OK) - return nullptr; - if (Tcl_GetDouble(interp, argv[4], &minIncr) != TCL_OK) - return nullptr; - if (Tcl_GetDouble(interp, argv[5], &maxIncr) != TCL_OK) - return nullptr; - } else { - minIncr = dLambda; - maxIncr = dLambda; - numIter = 1; - } - return new StagedLoadControl(dLambda, numIter, minIncr, maxIncr); -} -#endif #ifdef _PARALLEL_INTERPRETERS diff --git a/SRC/runtime/commands/analysis/integrator.h b/SRC/runtime/commands/analysis/integrator.h index 756dde417a..2bdf157f59 100644 --- a/SRC/runtime/commands/analysis/integrator.h +++ b/SRC/runtime/commands/analysis/integrator.h @@ -1,22 +1,25 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// All dispatching macros and templates are defined in integrator.cpp before +// this file is included. +// #include OPS_Routine OPS_Newmark; -OPS_Routine OPS_StagedNewmark; OPS_Routine OPS_GimmeMCK; -OPS_Routine OPS_AlphaOS; -OPS_Routine OPS_AlphaOS_TP; -OPS_Routine OPS_AlphaOSGeneralized; -OPS_Routine OPS_AlphaOSGeneralized_TP; -OPS_Routine OPS_ExplicitDifference; -OPS_Routine OPS_CentralDifference; -OPS_Routine OPS_CentralDifferenceAlternative; -OPS_Routine OPS_CentralDifferenceNoDamping; OPS_Routine OPS_Collocation; OPS_Routine OPS_CollocationHSFixedNumIter; OPS_Routine OPS_CollocationHSIncrLimit; @@ -55,7 +58,6 @@ OPS_Routine OPS_WilsonTheta; // integrators #include -// #include #include #include @@ -64,10 +66,13 @@ OPS_Routine OPS_WilsonTheta; #include #include #include +#include +#include +#include +#include - -StaticIntegrator* G3Parse_newHSIntegrator(ClientData, Tcl_Interp*, int, TCL_Char ** const); -StaticIntegrator* G3Parse_newLoadControl(ClientData, Tcl_Interp*, int argc, TCL_Char *argv[]); +Tcl_CmdProc G3Parse_newHSIntegrator; +Tcl_CmdProc G3Parse_newLoadControl; StaticIntegrator* G3Parse_newEQPathIntegrator(ClientData, Tcl_Interp*, int argc, TCL_Char ** const); StaticIntegrator* G3Parse_newArcLengthIntegrator(ClientData, Tcl_Interp*, int argc, TCL_Char ** const); StaticIntegrator* G3Parse_newMinUnbalDispNormIntegrator(ClientData, Tcl_Interp*, int, TCL_Char ** const); @@ -78,87 +83,13 @@ TransientIntegrator* G3Parse_newNewmark1Integrator(ClientData, Tcl_Interp*, int, TransientIntegrator* TclCommand_newNewmarkIntegrator(ClientData, Tcl_Interp*, int, TCL_Char** const); -// -// Helpers -// - -// Type 1 -template -static int -dispatch(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char** const argv) -{ - BasicAnalysisBuilder *builder = static_cast(clientData); - Type* theIntegrator = (Type*)fn( G3_getRuntime(interp), argc, argv ); - - if (theIntegrator == nullptr) - return TCL_ERROR; - - - opsdbg << G3_DEBUG_PROMPT << "Set integrator to \n"; - theIntegrator->Print(opsdbg); - builder->set(*theIntegrator); - return TCL_OK; -} - -// Type 2 -template -static int -dispatch(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char** const argv) -{ - assert(clientData != nullptr); - - - Type* theIntegrator = fn( clientData, interp, argc, argv ); - - if (theIntegrator == nullptr) - return TCL_ERROR; - - BasicAnalysisBuilder *builder = static_cast(clientData); - - opsdbg << G3_DEBUG_PROMPT << "Set integrator to \n"; - theIntegrator->Print(opsdbg); - builder->set(*theIntegrator); - return TCL_OK; -} - -// Type 3 -template -static int -dispatch(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char** const argv) -{ - assert(clientData != nullptr); - return fn( clientData, interp, argc, argv ); -} - -#define DISPATCH(Type, Class) \ - (Tcl_CmdProc*)[](ClientData clientData, Tcl_Interp*, int, G3_Char**const)->int{ \ - BasicAnalysisBuilder *builder = static_cast(clientData); \ - Type* theIntegrator = new Class(); \ - opsdbg << G3_DEBUG_PROMPT << "Set integrator to \n"; \ - theIntegrator->Print(opsdbg); \ - builder->set(*theIntegrator); \ - return TCL_OK; \ - } - // // // -#if 0 -std::unordered_map -StaticIntegratorLibrary = { - {"LoadControl", G3Parse_newLoadControl}, -//{"StagedLoadControl", G3Parse_newStagedLoadControlIntegrator}, - {"EQPath", G3Parse_newEQPathIntegrator}, - {"ArcLength", G3Parse_newArcLengthIntegrator}, - {"MinUnbalDispNorm", G3Parse_newMinUnbalDispNormIntegrator}, - {"DisplacementControl", G3Parse_newDisplacementControlIntegrator}, -}; -#endif - std::unordered_map StaticIntegratorLibrary = { - {"LoadControl", dispatch}, + {"LoadControl", G3Parse_newLoadControl}, {"EQPath", dispatch}, @@ -185,82 +116,75 @@ TransientIntegratorLibrary = { {"ParkLMS3", DISPATCH(TransientIntegrator, ParkLMS3)}, // MCK - {"GimmeMCK", dispatch }, - {"MCK", dispatch }, - {"ZZTop", dispatch }, - - {"Newmark", dispatch }, + {"GimmeMCK", dispatch }, + {"MCK", dispatch }, + {"ZZTop", dispatch }, - {"NewmarkExplicit", dispatch}, + {"Newmark", dispatch }, - {"Newmark1", dispatch}, + {"NewmarkExplicit", dispatch}, - {"NewmarkHSIncrReduct", dispatch}, + {"Newmark1", dispatch}, - {"NewmarkHSIncrLimit", dispatch}, + {"NewmarkHSIncrReduct", dispatch}, - {"NewmarkHSFixedNumIter", dispatch}, + {"NewmarkHSIncrLimit", dispatch}, - {"HHT", dispatch}, + {"NewmarkHSFixedNumIter", dispatch}, - {"HHT_TP", dispatch}, + {"HHT", dispatch}, - {"HHTGeneralized", dispatch}, + {"HHT_TP", dispatch}, - {"HHTGeneralized_TP", dispatch}, + {"HHTGeneralized", dispatch}, - {"HHTExplicit", dispatch}, + {"HHTGeneralized_TP", dispatch}, - {"HHTExplicit_TP", dispatch}, + {"HHTExplicit", dispatch}, - {"HHTGeneralizedExplicit", dispatch}, + {"HHTExplicit_TP", dispatch}, - {"HHTGeneralizedExplicit_TP", dispatch}, + {"HHTGeneralizedExplicit", dispatch}, - {"HHTHSIncrLimit", dispatch}, + {"HHTGeneralizedExplicit_TP", dispatch}, - {"HHTHSIncrLimit_TP", dispatch}, + {"HHTHSIncrLimit", dispatch}, - {"HHTHSIncrReduct", dispatch}, + {"HHTHSIncrLimit_TP", dispatch}, - {"HHTHSIncrReduct_TP", dispatch}, + {"HHTHSIncrReduct", dispatch}, - {"HHTHSFixedNumIter", dispatch}, + {"HHTHSIncrReduct_TP", dispatch}, - {"HHTHSFixedNumIter_TP", dispatch}, + {"HHTHSFixedNumIter", dispatch}, - {"GeneralizedAlpha", dispatch}, + {"HHTHSFixedNumIter_TP", dispatch}, - {"KRAlphaExplicit", dispatch}, + {"GeneralizedAlpha", dispatch}, - {"KRAlphaExplicit_TP", dispatch}, + {"KRAlphaExplicit", dispatch}, - {"AlphaOS", dispatch}, + {"KRAlphaExplicit_TP", dispatch}, - {"AlphaOS_TP", dispatch}, + {"Collocation", dispatch}, - {"AlphaOSGeneralized", dispatch}, + {"CollocationHSIncrReduct", dispatch}, - {"AlphaOSGeneralized_TP", dispatch}, - - {"Collocation", dispatch}, - - {"CollocationHSIncrReduct", dispatch}, - - {"CollocationHSIncrLimit", dispatch}, + {"CollocationHSIncrLimit", dispatch}, {"CollocationHSFixedNumIter", dispatch}, {"WilsonTheta", dispatch}, - {"ExplicitDifference", dispatch}, + {"ExplicitDifference", DISPATCH(TransientIntegrator, ExplicitDifference)}, - {"CentralDifference", dispatch}, + {"CentralDifference", DISPATCH(TransientIntegrator, CentralDifference)}, - {"CentralDifferenceAlternative", dispatch}, + {"CentralDifferenceAlternative", DISPATCH(TransientIntegrator, CentralDifferenceAlternative)}, - {"CentralDifferenceNoDamping", dispatch}, + {"CentralDifferenceNoDamping", DISPATCH(TransientIntegrator, CentralDifferenceNoDamping)}, }; + diff --git a/SRC/runtime/commands/analysis/itpack.cpp b/SRC/runtime/commands/analysis/itpack.cpp new file mode 100644 index 0000000000..24d1c3cfcc --- /dev/null +++ b/SRC/runtime/commands/analysis/itpack.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +#include +#include +#include + +LinearSOE* +TclDispatch_newItpackLinearSOE(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +{ + // now must determine the type of solver to create + // from rest of args + int method = 1; + if (argc == 3) { + if (Tcl_GetInt(interp, argv[2], &method) != TCL_OK) + return nullptr; + } + ItpackLinSolver *theSolver = new ItpackLinSolver(method); + return new ItpackLinSOE(*theSolver); +} + + + diff --git a/SRC/runtime/commands/analysis/modal/CMakeLists.txt b/SRC/runtime/commands/analysis/modal/CMakeLists.txt new file mode 100644 index 0000000000..154506f6ba --- /dev/null +++ b/SRC/runtime/commands/analysis/modal/CMakeLists.txt @@ -0,0 +1,8 @@ + + + +target_sources(OPS_Runtime PRIVATE + "modal.cpp" + "ResponseSpectrumAnalysis.cpp" + "DomainModalProperties.cpp" +) \ No newline at end of file diff --git a/SRC/runtime/commands/analysis/modal/DomainModalProperties.cpp b/SRC/runtime/commands/analysis/modal/DomainModalProperties.cpp new file mode 100644 index 0000000000..c0a9b1ed28 --- /dev/null +++ b/SRC/runtime/commands/analysis/modal/DomainModalProperties.cpp @@ -0,0 +1,859 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ +// +// Written: Massimo Petracca (ASDEA Software) +// Created: Fri Nov 27 18:07:11: 2020 +// Revision: A +// +// Description: This file contains the class definition for DomainModalProperties. +// It contains all data optionally computed after an Eigenvalue analysis. +// +// What: "@(#) DomainModalProperties.h, revA" +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DomainModalProperties.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +#if defined(_WIN32) +#ifndef NOMINMAX +#define NOMINMAX +#endif +#endif + +//#define DMP_VERBOSE +//#define DMP_DEBUG + +#define DMP_ERR_INFO "( function: " << __func__ << ", file: \"" << __FILE__ << "\", line: " << __LINE__ << " )\n" +#define DMP_ERR(X) opserr << "FATAL ERROR: " << X << DMP_ERR_INFO, exit(-1) + +#define DMP_DBL_LARGE 1.0e200 + +// find domain size +static int +domainSize(Domain *domain) { + int ndm = 0; + Node* node; + NodeIter& theNodes = domain->getNodes(); + while ((node = theNodes()) != nullptr) { + int trial = node->getCrds().Size(); + if (ndm == 0) + ndm = trial; + if (ndm != trial) + DMP_ERR("Cannot mix nodes with different dimensions\n"); + } + + if ((ndm != 2) && (ndm != 3)) + DMP_ERR("DomainModalProperties can be calculated only when NDM is 2 or 3, not " << ndm << "\n"); + return ndm; +} + +// Anonymous namespace for utilities +namespace +{ + // a simple structure to collect nodes in a contiguos array + // and with a map that maps the node tag to its position in the array + struct node_map_t + { + enum DOF_TYPE { DOF_EXCLUDED = -1, DOF_FIXED = -2}; + + // the contiguous list of nodes + std::vector nodes; + // for each node, save a re-mapped ID to the contiguous list of dofs + // (-1 means "exluded", -2 means "fixed") + std::vector node_ids; + // for each node, save a list of local DOF id (0 to ndf) + std::vector > node_u_flags; + // for each node, save the first position in the contiguos list of dofs, ndf for each node (3 in 2D and 6 in 3D) + std::map pos; + + node_map_t(Domain* domain, int ndm, int ndf) { + size_t n = static_cast(domain->getNumNodes()); + if (n > 0) { + nodes.resize(n); + node_ids.resize(n); + node_u_flags.resize(n); + Node* nodePtr; + NodeIter& theNodes = domain->getNodes(); + size_t counter = 0; + while ((nodePtr = theNodes()) != 0) { + // node + nodes[counter] = nodePtr; + // map + pos.emplace(std::make_pair(nodePtr->getTag(), counter)); + // id (original), needed to see if this dof is fixed + const ID& id_source = nodePtr->getDOF_GroupPtr()->getID(); + // id (remapped) + auto& id = node_ids[counter]; + int node_ndf = nodePtr->getNumberDOF(); + id.resize(node_ndf); + int offset = static_cast(counter)* ndf; // each node has ndf DOFs in this context + for (int j = 0; j < node_ndf; ++j) { + if (j < ndf) { + // exclude pressure dofs + // we can detect a pressure node (node_ndf=4) in 3d.. but not in 2d! + if (node_ndf == 4 && ndf == 6 && j == 3) { + id(j) = DOF_EXCLUDED; + } + else { + if (id_source(j) == -1) + id(j) = DOF_FIXED; + else + id(j) = offset; + } + ++offset; + } + else { + // exclude any dof >= ndf + id(j) = DOF_EXCLUDED; + } + } + // local dof flags + std::vector& flags = node_u_flags[counter]; + flags.resize(node_ndf); + for (int j = 0; j < node_ndf; ++j) + flags[static_cast(j)] = id(j) == DOF_EXCLUDED ? -1 : j; + // go on + ++counter; + } + } + +#ifdef DMP_VERBOSE + opserr << "NODE RE-MAPPING:\n"; + opserr << "num eq: " << (int)(n * ndf) << "\n"; + for (size_t i = 0; i < n; ++i) { + auto node = nodes[i]; + const auto& id = node_ids[i]; + const auto& uf = node_u_flags[i]; + opserr << "[" << (int)i << "] Node " << node->getTag() << " -> ("; + for (int j = 0; j < id.Size(); ++j) + opserr << " " << id(j); + opserr << " ) {"; + for (size_t j = 0; j < uf.size(); ++j) + opserr << " " << static_cast(uf[j]); + opserr << " }\n"; + } +#endif // DMP_VERBOSE + } + + inline size_t getPosition(int tag) const { + auto it = pos.find(tag); + if (it == pos.end()) + DMP_ERR("Cannot find node " << tag << "\n"); + return it->second; + } + + }; + + // a simple structure to collect element data + struct ele_map_t + { + // the contiguous list of elements + std::vector elements; + // for each element, save a re-mapped ID to the contiguous list of dofs + std::vector element_ids; + // for each element, save a list of nodal position pointing to the contiguos position of the node + // in the node map + std::vector > element_node_pos; + // for each element, save a list of flags. true if the dof is translational, false otherwise + std::vector > element_u_flags; + + ele_map_t(Domain* domain, const node_map_t& nm) { + size_t count = static_cast(domain->getNumElements()); + elements.resize(count); + element_ids.resize(count); + element_u_flags.resize(count); + element_node_pos.resize(count); + count = 0; + { + Element* elePtr; + ElementIter& theEles = domain->getElements(); + while ((elePtr = theEles()) != 0) { + // save element + elements[count] = elePtr; + // element node tags + const ID& ele_nodes = elePtr->getExternalNodes(); + // count number of dofs + size_t dof_count = 0; + for (int i = 0; i < ele_nodes.Size(); ++i) { + size_t pos = nm.getPosition(ele_nodes(i)); + const ID& node_id = nm.node_ids[pos]; + dof_count += static_cast(node_id.Size()); + } + // initialize element data + ID& id = element_ids[count]; + std::vector& uf = element_u_flags[count]; + std::vector& positions = element_node_pos[count]; + id.resize(static_cast(dof_count)); + uf.resize(dof_count); + positions.resize(dof_count); + // remap element data + dof_count = 0; + for (int i = 0; i < ele_nodes.Size(); ++i) { + size_t pos = nm.getPosition(ele_nodes(i)); + const ID& node_id = nm.node_ids[pos]; + const std::vector& node_uf = nm.node_u_flags[pos]; + if (static_cast(dof_count) + node_id.Size() > id.Size()) + DMP_ERR("FE_Element::getID() Size < sum(size(mapped node IDs))"); + for (int j = 0; j < node_id.Size(); ++j) { + id(dof_count) = node_id(j); + uf[dof_count] = node_uf[static_cast(j)]; + positions[dof_count] = pos; + ++dof_count; + } + } + ++count; +#ifdef DMP_VERBOSE + int dof_count_print = 0; + size_t uf_count_print = 0; + size_t pos_count_print = 0; + opserr << "ELEMENT " << elePtr->getTag() << " RE-MAPPING:\n"; + for (size_t i = 0; i < ele_nodes.Size(); ++i) { + size_t pos = nm.getPosition(ele_nodes(i)); + const ID& node_id = nm.node_ids[pos]; + opserr << " [" << ele_nodes(i) << "] ("; + for (int j = 0; j < node_id.Size(); ++j) + opserr << " " << id(dof_count_print++); + opserr << " ) {"; + for (size_t j = 0; j < static_cast(node_id.Size()); ++j) + opserr << " " << uf[uf_count_print++]; + opserr << " } <"; + for (size_t j = 0; j < static_cast(node_id.Size()); ++j) + opserr << " " << static_cast(positions[pos_count_print++]); + opserr << " >\n"; + } +#endif // DMP_VERBOSE + } + } + } + }; +} + +DomainModalProperties::DomainModalProperties(Domain *domain, bool unorm) + : m_domain(domain) + , m_unorm(unorm) +{ +} + +bool +DomainModalProperties::compute() +{ + /* + Notes: + 1 - we assemble the global mass matrix and eigenvectors with our own (plain) numbering + 2 - we make room for rotational DOFs even if some nodes are translational only, because we + also include the rotational effect given by the translational masses gyrating about the + center of mass + 3 - the mass matrix may be consistent. however we need also a diagonalized version of it + to compute the center of mass, the total mass of the structure, and the rotational masses + due to the translational masses gyrating about the center of mass + */ + + Domain* domain = m_domain; + + // number of eigen-modes + int num_eigen = domain->getEigenvalues().Size(); + if (num_eigen < 1) + DMP_ERR("No Eigenvalue provided.\n"); + + // eigenvalues + m_eigenvalues = domain->getEigenvalues(); + // number of dimensions + int ndm = domainSize(domain); + // max number of DOFs per node, translational and rotational only + int ndf = ndm == 2 ? 3 : 6; + // number of nodes + int num_nodes = domain->getNumNodes(); + // number of equations (not the real one, include rotational dofs even if not present) + int num_eq = num_nodes * ndf; + + // initialize members + m_center_of_mass.resize(ndm); + m_total_mass.resize(ndf); + m_total_free_mass.resize(ndf); + m_generalized_mass_matrix.resize(num_eigen); + m_modal_participation_factors.resize(num_eigen, ndf); + m_modal_participation_masses.resize(num_eigen, ndf); + m_modal_participation_masses_cumulative.resize(num_eigen, ndf); + m_modal_participation_mass_ratios.resize(num_eigen, ndf); + m_modal_participation_mass_ratios_cumulative.resize(num_eigen, ndf); + + // map all nodes + node_map_t nodemap(domain, ndm, ndf); + + // map all elements + ele_map_t elemap(domain, nodemap); + + // the sparse mass matrix + SparseMatrix M; + // the equivalent diagonalized masses for each node (total) + Matrix ML(num_nodes, ndf); + // the equivalent diagonalized masses for each node (only at free DOFs) + Matrix MLfree(num_nodes, ndf); + // the array of eigenvectors + std::vector V(num_eigen); + for (auto& iV : V) { + iV.resize(num_eq); + iV.Zero(); + } + + + // + // + // + { + // + // assemble in the sparse mass matrix + // + Vector aux_MD; // auxiliary: sum of each row of iM + Vector aux_ML(ndf); // auxiliary: sum of MD for each DOF + Vector aux_MC(ndf); // auxiliary: sum of consistent mass iM diagonal terms only + Vector aux_C(ndf); // auxiliary: scale factors + Vector aux_Lumped; // auxiliary: lumped diagonalized mass matrix + auto addM = [&M, &ML, &MLfree, &aux_MD, &aux_ML, &aux_MC, &aux_C, &aux_Lumped]( + const Matrix& iM, const ID& iD, const std::vector &uflags, const std::vector &npos) { + int n = iD.Size(); + if (iM.noRows() != n || iM.noCols() != n) + DMP_ERR("Error: inconsistent mass matrix and ID\n"); + + for (int i = 0; i < n; ++i) { + int iloc = iD(i); + if (iloc >= 0) { + for (int j = 0; j < n; ++j) { + int jloc = iD(j); + if (jloc >= 0) { + double value = iM(i, j); + if (value != 0.0) + M.append(iloc, jloc, value); + } + } + } + } + // compute diagonal terms summing each row (it can have negative terms, so + // it cannot be directly used as a lumping approach) + aux_MD.resize(n); + aux_MD.Zero(); + for (int i = 0; i < n; ++i) { + if (uflags[static_cast(i)] >= 0) { + for (int j = 0; j < n; ++j) { + aux_MD(i) += iM(i, j); + } + } + } + // sum terms in MD DOF by DOF. This will give the total mass of the element + // for each DOF + aux_ML.Zero(); + for (int i = 0; i < n; i++) { + int local_dof = uflags[static_cast(i)]; + if (local_dof >= 0) + aux_ML(local_dof) += aux_MD(i); + } + // sum consistent diagonal terms of iM DOF by DOF + aux_MC.Zero(); + for (int i = 0; i < n; i++) { + int local_dof = uflags[static_cast(i)]; + if (local_dof >= 0) + aux_MC(local_dof) += iM(i, i); + } + // obtain scale factors + for (int i = 0; i < aux_C.Size(); ++i) { + double ml = aux_ML(i); + double mc = aux_MC(i); + aux_C(i) = std::abs(mc) > 0.0 ? ml / mc : 0.0; + } + // obtain lumped mass matrix + aux_Lumped.resize(n); + aux_Lumped.Zero(); + for (int i = 0; i < n; ++i) { + int local_dof = uflags[static_cast(i)]; + if (local_dof >= 0) { + aux_Lumped(i) = iM(i, i) * aux_C(local_dof); + int node_pos = npos[static_cast(i)]; + ML(node_pos, local_dof) += aux_Lumped(i); + if (iD(i) >= 0) + MLfree(node_pos, local_dof) += aux_Lumped(i); + } + } + }; + + // assemble in the array of eigenvectors + auto addV = [&V](const Matrix& iV, const ID& iD) { + int n = iD.Size(); + if (iV.noRows() != n || iV.noCols() != static_cast(V.size())) + DMP_ERR("Error: inconsistent eigenvector matrix and ID\n"); + for (int j = 0; j < static_cast(V.size()); ++j) { + auto& jV = V[static_cast(j)]; + for (int i = 0; i < n; ++i) { + int iloc = iD(i); + if (iloc >= 0) + jV(iloc) = iV(i, j); + } + } + }; + + // assemble all element contributions + { + for (size_t i = 0; i < elemap.elements.size(); ++i) { + Element* element = elemap.elements[i]; + const ID& iD = elemap.element_ids[i]; + const std::vector& uflags = elemap.element_u_flags[i]; + const std::vector& npos = elemap.element_node_pos[i]; + const Matrix& iM = element->getMass(); + addM(iM, iD, uflags, npos); + } + } + // assemble all nodal contributions + { + std::vector npos; + for (size_t i = 0; i < nodemap.nodes.size(); ++i) { + Node* node = nodemap.nodes[i]; + const ID& iD = nodemap.node_ids[i]; + const std::vector& uflags = nodemap.node_u_flags[i]; + npos.resize(static_cast(iD.Size())); + std::fill(npos.begin(), npos.end(), i); + const Matrix& iV = node->getEigenvectors(); + const Matrix& iM = node->getMass(); + addM(iM, iD, uflags, npos); + addV(iV, iD); + } + } + } + + // done assemling M + M.finish(); + + + // Normalize eigenvectors such that their max component is 1 + // if requested by the user + m_unorm_scale_factors.resize(num_eigen); + if (m_unorm) { + for (int imode = 0; imode < num_eigen; ++imode) { + Vector& iV = V[static_cast(imode)]; + double umax = 0.0; + for (int i = 0; i < iV.Size(); ++i) + umax = std::max(umax, std::abs(iV(i))); + double scale = umax == 0.0 ? DMP_DBL_LARGE : 1.0 / umax; + for (int i = 0; i < iV.Size(); ++i) + iV(i) *= scale; + m_unorm_scale_factors(imode) = scale; + } + } + else { + for (int imode = 0; imode < num_eigen; ++imode) { + m_unorm_scale_factors(imode) = 1.0; + } + } + + // compute the center of mass. + // note that if the total mass in one of the global directions is 0 + // we sould take the geometric center, as otherwise it will be 0. + // TODO: check wether we need the total or free mass. + // accordingly, for the geometric center... should we use free nodes only? + // let's start with free nodes only... by the way they are the only ones + // accounted for by the eigenvalue analysis... + { + Vector geometric_center(ndm); + Vector com_weight(ndm); // weight for center of mass + Vector cog_weight(ndm); // weight for geometric center + m_center_of_mass.Zero(); + for (int i = 0; i < num_nodes; ++i) { + Node* node = nodemap.nodes[static_cast(i)]; + const ID& ids = nodemap.node_ids[static_cast(i)]; + const Vector& pos = node->getCrds(); + for (int j = 0; j < ndm; ++j) { + if ((j < ids.Size()) && (ids(j) >= 0)) { + double Mij = MLfree(i, j); // use the free masses only + double Pi = pos(j); + geometric_center(j) += Pi; + cog_weight(j) += 1.0; + m_center_of_mass(j) += Pi * Mij; + com_weight(j) += Mij; + } + } + } + for (int j = 0; j < ndm; ++j) { + // finish computing geometric center + if (cog_weight(j) > 0.0) + geometric_center(j) /= cog_weight(j); + // finish computing center of mass. + // select the geometric center if not mass is provided in this component + if (com_weight(j) > 0.0) + m_center_of_mass(j) /= com_weight(j); + else + m_center_of_mass(j) = geometric_center(j); + } + } + + // Now the sparse matrix M contains the orignal mass (consistent or lumped). + // ML is a lumped version of M. for rotational DOFs it contains only the + // rotary masses directly input by the user. + // However we also need to compute, for the modal properties, the rotational + // masses due to the translational masses gyrating about the center of mass. + // Of course this goes only in ML, not in M. + auto compute_extra_rotary_mass = [&nodemap, num_nodes, ndf, this](Matrix& iML) { + for (int i = 0; i < num_nodes; ++i) { + Node* node = nodemap.nodes[static_cast(i)]; + /// const ID& ids = nodemap.node_ids[static_cast(i)]; + const Vector& pos = node->getCrds(); + double dx = pos(0) - m_center_of_mass(0); + double dy = pos(1) - m_center_of_mass(1); + double mx = iML(i, 0); + double my = iML(i, 1); + if (ndf == 3) { // 2D case + iML(i, 2) += dx * dx * my + dy * dy * mx; + } + else { // 3D case + double dz = pos(2) - m_center_of_mass(2); + double mz = iML(i, 2); + iML(i, 3) += dy * dy * mz + dz * dz * my; + iML(i, 4) += dx * dx * mz + dz * dz * mx; + iML(i, 5) += dx * dx * my + dy * dy * mx; + } + } + }; + compute_extra_rotary_mass(ML); + compute_extra_rotary_mass(MLfree); + + // compute the total mass of the domain (total and free-only) + m_total_mass.Zero(); + m_total_free_mass.Zero(); + for (int j = 0; j < ndf; ++j) { + double msum = 0.0; + double msum_free = 0.0; + for (int i = 0; i < num_nodes; ++i) { + msum += ML(i, j); + msum_free += MLfree(i, j); + } + m_total_mass(j) = msum; + m_total_free_mass(j) = msum_free; + } + + + // + // Modal Participation + // + + // now we can compute all the modal masses and participation factors. + // we can do it mode by mode due to their orthogonality. + + // a temporary to store the V'*M product + Vector jVTM(num_eq); + // defines the magnitude of the rigid body response of a DOF + // to imposed rigid body motion (displacement or infinitesimal rotation) in the i-direction. + // each (ndf x 1) block correspond to a node (ordered sequentially as in nodemap), and it is defined as: + // | 1 0 0 0 dz -dz | |e1| + // | 0 1 0 -dz 0 dx | |e2| + // | 0 0 1 dy -dx 0 | |e3| + // | 0 0 0 1 0 0 | |e4| + // | 0 0 0 0 1 0 | |e5| + // | 0 0 0 0 0 1 | |e6| + // where ei is 1, and all the other are 0. + Vector R(num_eq); + // for each j mode... + for (int j = 0; j < num_eigen; ++j) { + + // current mode eigenvector + const Vector& jV = V[j]; + + // compute [V' * M] : a temporary to avoid extra calculations + jVTM.Zero(); + for (const auto& it : M.triplets) + jVTM[it.j] += it.val * jV(it.i); + + // compute [V' * M * V] : generalized mass matrix + double GM = jVTM ^ jV; + m_generalized_mass_matrix(j) = GM; + double invGM = GM == 0.0 ? DMP_DBL_LARGE : 1.0 / GM; + + // for each DOF ... + for (int i = 0; i < ndf; ++i) { + + // compute the rigid-body-mode vector R + R.Zero(); + for (int inode = 0; inode < num_nodes; ++inode) { + int index = inode * ndf; + R(index + i) = 1.0; // one at the current DOF for direct translational or rotational effects + if (i >= ndm) { + const Vector& pos = nodemap.nodes[static_cast(inode)]->getCrds(); + double dx = pos(0) - m_center_of_mass(0); + double dy = pos(1) - m_center_of_mass(1); + if (ndf == 3) { // 2D case + if (i == 2) { + R(index + 0) = -dy; + R(index + 1) = dx; + } + } + else { // 3D case + double dz = pos(2) - m_center_of_mass(2); + if (i == 3) { + R(index + 1) = -dz; + R(index + 2) = dy; + } + else if (i == 4) { + R(index + 0) = dz; + R(index + 2) = -dx; + } + else if (i == 5) { + R(index + 0) = -dy; + R(index + 1) = dx; + } + } + } + } + + // compute [V' * M * R] : generalized load vector + double L = jVTM ^ R; + + // compute [(V' * M * R) / diag(V' * M * V)] : modal participation factors + m_modal_participation_factors(j, i) = L * invGM; + + // compute [(V' * M * R)^2 / diag(V' * M * V)] : effective modal masses + m_modal_participation_masses(j, i) = L * L * invGM; + } + } + + // now we can compute the cumulative masses and ratios + for (int j = 0; j < ndf; ++j) { + double tot_mass = m_total_free_mass(j); + double inv_tot_mass = tot_mass == 0.0 ? DMP_DBL_LARGE : 1.0 / tot_mass; + double accum_1 = 0.0; + double accum_2 = 0.0; + for (int i = 0; i < num_eigen; ++i) { + double mpm = m_modal_participation_masses(i, j); + double mpmr = mpm * inv_tot_mass; + accum_1 += mpm; + accum_2 += mpmr; + m_modal_participation_mass_ratios(i, j) = mpmr; + m_modal_participation_masses_cumulative(i, j) = accum_1; + m_modal_participation_mass_ratios_cumulative(i, j) = accum_2; + } + } + + return true; +} + +namespace +{ +#define DMP_OUT_COMMENT "#" +#define DMP_OUT_RECORD "*" +#define DMP_OUT_BLANK " " +#define DMP_OUT_FLOAT(X) std::setw(14) << std::setprecision(6) << X +#define DMP_OUT_GEN(X) std::setw(14) << X +#define DMP_OUT_HLINE "-------------" +#define DMP_OUT_TOL 1.0e-16 +#define DMP_OUT_REL_TOL 1.0e-12 + + inline double getTolerance(const Vector& x) { + double vmax = 0.0; + for (int i = 0; i < x.Size(); ++i) + vmax = std::max(vmax, std::abs(x(i))); + return std::max(DMP_OUT_REL_TOL * vmax, DMP_OUT_TOL); + } + + inline double getTolerance(const Matrix& x) { + double vmax = 0.0; + for (int i = 0; i < x.noRows(); ++i) + for (int j = 0; j < x.noCols(); ++j) + vmax = std::max(vmax, std::abs(x(i, j))); + return std::max(DMP_OUT_REL_TOL * vmax, DMP_OUT_TOL); + } + + inline double cleanFloat(double x, double tol) { + return std::abs(x) > tol ? x : 0.0; + } + + template + void print_internal(TStream& out, const DomainModalProperties& dmp) + { + // utils + auto print_vec = [&out](const Vector& x, const char* fchar = DMP_OUT_BLANK) { + double tol = getTolerance(x); + out << fchar; + for (int i = 0; i < x.Size(); ++i) + out << DMP_OUT_FLOAT(cleanFloat(x(i), tol)); + out << "\n"; + }; + auto print_mat = [&out](const Matrix& x, double scale = 1.0, const char *fchar = DMP_OUT_BLANK) { + double tol = getTolerance(x); + for (int j = 0; j < x.noRows(); ++j) { + out << fchar << DMP_OUT_GEN(j + 1); + for (int i = 0; i < x.noCols(); ++i) + out << DMP_OUT_FLOAT(scale * cleanFloat(x(j, i), tol)); + out << "\n"; + } + }; + auto print_svec = [&out](const std::vector& x, const char* fchar = DMP_OUT_BLANK) { + out << fchar; + for (size_t i = 0; i < x.size(); ++i) + out << DMP_OUT_GEN(x[i]); + out << "\n"; + }; + + // labels + static std::vector lab_freq = { "MODE", "LAMBDA", "OMEGA", "FREQUENCY", "PERIOD" }; + static std::vector lab_mass_2d = { "MX", "MY", "RMZ" }; + static std::vector lab_mass_3d = { "MX", "MY", "MZ", "RMX", "RMY", "RMZ" }; + static std::vector lab_efmass_2d = { "MODE", "MX", "MY", "RMZ" }; + static std::vector lab_efmass_3d = { "MODE", "MX", "MY", "MZ", "RMX", "RMY", "RMZ" }; + static std::vector lab_pos_2d = { "X", "Y" }; + static std::vector lab_pos_3d = { "X", "Y", "Z" }; + static std::vector lab_sep_2 = { DMP_OUT_HLINE, DMP_OUT_HLINE }; + static std::vector lab_sep_3 = { DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE }; + static std::vector lab_sep_4 = { DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE }; + static std::vector lab_sep_5 = { DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE }; + static std::vector lab_sep_6 = { DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE }; + static std::vector lab_sep_7 = { DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE, DMP_OUT_HLINE }; + + // header + out << DMP_OUT_COMMENT << " MODAL ANALYSIS REPORT\n\n"; + + // problem size + int ndm = dmp.centerOfMass().Size(); + out << DMP_OUT_RECORD << " 1. DOMAIN SIZE:\n" + << DMP_OUT_COMMENT << " This is the size of the problem: 2 for 2D problems, 3 for 3D problems.\n" + << ndm << "\n\n\n"; + + // eigenvalues and derived quantities + out << DMP_OUT_RECORD << " 2. EIGENVALUE ANALYSIS:\n"; + print_svec(lab_freq, DMP_OUT_COMMENT); + print_svec(lab_sep_5, DMP_OUT_COMMENT); + for (int i = 0; i < dmp.eigenvalues().Size(); ++i) { + double lambda = dmp.eigenvalues()(i); + double omega = std::sqrt(lambda); + double freq = omega / 2.0 / M_PI; + double period = 1.0 / freq; + out << DMP_OUT_BLANK << DMP_OUT_GEN(i + 1) + << DMP_OUT_FLOAT(lambda) + << DMP_OUT_FLOAT(omega) + << DMP_OUT_FLOAT(freq) + << DMP_OUT_FLOAT(period) + << "\n"; + } + out << "\n\n"; + + // total mass + out << DMP_OUT_RECORD << " 3. TOTAL MASS OF THE STRUCTURE:\n" + << DMP_OUT_COMMENT << " The total masses (translational and rotational) of the structure\n" + << DMP_OUT_COMMENT << " including the masses at fixed DOFs (if any).\n"; + print_svec(ndm == 2 ? lab_mass_2d : lab_mass_3d, DMP_OUT_COMMENT); + print_svec(ndm == 2 ? lab_sep_3 : lab_sep_6, DMP_OUT_COMMENT); + print_vec(dmp.totalMass()); + out << "\n\n"; + out << DMP_OUT_RECORD << " 4. TOTAL FREE MASS OF THE STRUCTURE:\n" + << DMP_OUT_COMMENT << " The total masses (translational and rotational) of the structure\n" + << DMP_OUT_COMMENT << " including only the masses at free DOFs.\n"; + print_svec(ndm == 2 ? lab_mass_2d : lab_mass_3d, DMP_OUT_COMMENT); + print_svec(ndm == 2 ? lab_sep_3 : lab_sep_6, DMP_OUT_COMMENT); + print_vec(dmp.totalFreeMass()); + out << "\n\n"; + + // center of mass + out << DMP_OUT_RECORD << " 5. CENTER OF MASS:\n" + << DMP_OUT_COMMENT << " The center of mass of the structure, calculated from free masses.\n"; + print_svec(ndm == 2 ? lab_pos_2d : lab_pos_3d, DMP_OUT_COMMENT); + print_svec(ndm == 2 ? lab_sep_2 : lab_sep_3, DMP_OUT_COMMENT); + print_vec(dmp.centerOfMass()); + out << "\n\n"; + + // modal participation factors + out << DMP_OUT_RECORD << " 6. MODAL PARTICIPATION FACTORS:\n" + << DMP_OUT_COMMENT << " The participation factor for a certain mode 'a' in a certain direction 'i'\n" + << DMP_OUT_COMMENT << " indicates how strongly displacement along (or rotation about)\n" + << DMP_OUT_COMMENT << " the global axes is represented in the eigenvector of that mode.\n"; + print_svec(ndm == 2 ? lab_efmass_2d : lab_efmass_3d, DMP_OUT_COMMENT); + print_svec(ndm == 2 ? lab_sep_4 : lab_sep_7, DMP_OUT_COMMENT); + print_mat(dmp.modalParticipationFactors()); + out << "\n\n"; + + // modal participation masses + out << DMP_OUT_RECORD << " 7. MODAL PARTICIPATION MASSES:\n" + << DMP_OUT_COMMENT << " The modal participation masses for each mode.\n"; + print_svec(ndm == 2 ? lab_efmass_2d : lab_efmass_3d, DMP_OUT_COMMENT); + print_svec(ndm == 2 ? lab_sep_4 : lab_sep_7, DMP_OUT_COMMENT); + print_mat(dmp.modalParticipationMasses()); + out << "\n\n"; + + // modal participation masses (cumulative) + out << DMP_OUT_RECORD << " 8. MODAL PARTICIPATION MASSES (cumulative):\n" + << DMP_OUT_COMMENT << " The cumulative modal participation masses for each mode.\n"; + print_svec(ndm == 2 ? lab_efmass_2d : lab_efmass_3d, DMP_OUT_COMMENT); + print_svec(ndm == 2 ? lab_sep_4 : lab_sep_7, DMP_OUT_COMMENT); + print_mat(dmp.modalParticipationMassesCumulative()); + out << "\n\n"; + + // modal participation masses + out << DMP_OUT_RECORD << " 9. MODAL PARTICIPATION MASS RATIOS (%):\n" + << DMP_OUT_COMMENT << " The modal participation mass ratios (%) for each mode.\n"; + print_svec(ndm == 2 ? lab_efmass_2d : lab_efmass_3d, DMP_OUT_COMMENT); + print_svec(ndm == 2 ? lab_sep_4 : lab_sep_7, DMP_OUT_COMMENT); + print_mat(dmp.modalParticipationMassRatios(), 100.0); + out << "\n\n"; + + // modal participation masses (cumulative) + out << DMP_OUT_RECORD << " 10. MODAL PARTICIPATION MASS RATIOS (%) (cumulative):\n" + << DMP_OUT_COMMENT << " The cumulative modal participation mass ratios (%) for each mode.\n"; + print_svec(ndm == 2 ? lab_efmass_2d : lab_efmass_3d, DMP_OUT_COMMENT); + print_svec(ndm == 2 ? lab_sep_4 : lab_sep_7, DMP_OUT_COMMENT); + print_mat(dmp.modalParticipationMassRatiosCumulative(), 100.0); + out << "\n\n"; + } +} + +void +DomainModalProperties::print() +{ + std::stringstream ss; + print_internal(ss, *this); + std::string s = ss.str(); + opserr << s.c_str(); +} + +void +DomainModalProperties::print(const std::string& file_name) +{ + std::ofstream ss(file_name); + if (!ss.is_open()) + DMP_ERR("Cannot open file \"" << file_name.c_str() << "\"\n"); + print_internal(ss, *this); + ss.close(); +} + + diff --git a/SRC/runtime/commands/analysis/modal/DomainModalProperties.h b/SRC/runtime/commands/analysis/modal/DomainModalProperties.h new file mode 100644 index 0000000000..376d39664a --- /dev/null +++ b/SRC/runtime/commands/analysis/modal/DomainModalProperties.h @@ -0,0 +1,102 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +// $Revision: 1.0 $ +// $Date: 2020-11-27 18:07:11 $ +// $Source: /usr/local/cvs/OpenSees/SRC/domain/domain/DomainModalProperties.h,v $ + +// Written: Massimo Petracca (ASDEA Software) +// Created: Fri Nov 27 18:07:11: 2020 +// Revision: A +// +// Description: This file contains the class definition for DomainModalProperties. +// It contains all data optionally computed after an Eigenvalue analysis. +// +// What: "@(#) DomainModalProperties.h, revA" + +#ifndef DomainModalProperties_h +#define DomainModalProperties_h + +#include +#include +#include + +class Domain; + +class DomainModalProperties +{ +public: + DomainModalProperties(Domain* domain, bool unorm); + DomainModalProperties(const DomainModalProperties&) = default; + DomainModalProperties& operator = (const DomainModalProperties&) = default; + +public: + Domain* getDomain() const { return m_domain; } + bool compute(); + void print(); + void print(const std::string& file_name); + +public: + inline bool isUnormalized() const { return m_unorm; } + inline const Vector& eigenVectorScaleFactors() const { return m_unorm_scale_factors; } + inline const Vector& centerOfMass() const { return m_center_of_mass; } + inline const Vector& totalMass() const { return m_total_mass; } + inline const Vector& totalFreeMass() const { return m_total_free_mass; } + inline const Vector& eigenvalues() const { return m_eigenvalues; } + inline const Vector& generalizedMasses() const { return m_generalized_mass_matrix; } + inline const Matrix& modalParticipationFactors() const { return m_modal_participation_factors; } + inline const Matrix& modalParticipationMasses() const { return m_modal_participation_masses; } + inline const Matrix& modalParticipationMassesCumulative() const { return m_modal_participation_masses_cumulative; } + inline const Matrix& modalParticipationMassRatios() const { return m_modal_participation_mass_ratios; } + inline const Matrix& modalParticipationMassRatiosCumulative() const { return m_modal_participation_mass_ratios_cumulative; } + +private: + Domain* m_domain; + // optional flag to force eigenvector displacement-normalization + bool m_unorm; + // the scale factors for each eigenvector (equal to 1 if unorm==false) (size = NUM_MODES) + Vector m_unorm_scale_factors; + // the center of mass (size = NDM) + Vector m_center_of_mass; + // the total mass of the domain including the mass of fixed DOFs (size = NDF : 3 if NDM==2, 6 if NDM==3) + Vector m_total_mass; + // the total mass of the domain excluding the mass of fixed DOFs (size = NDF : 3 if NDM==2, 6 if NDM==3) + Vector m_total_free_mass; + // eigenvalues (size = NUM_MODES) + Vector m_eigenvalues; + // diag(V'*M*V) + // the diagonal of the generalized mass matrix (size = NUM_MODES) + // we store this because it the eigenvectors are not properly normalized + // the diagonal entries won't be 1 + Vector m_generalized_mass_matrix; + // (V'*M*R)/diag(V'*M*V) + // the modal participation factors (size = NUM_MODES x NDF) + Matrix m_modal_participation_factors; + // ((V'*M*R)^2)/diag(V'*M*V) + // the modal participation masses (size = NUM_MODES x NDF) + Matrix m_modal_participation_masses; + Matrix m_modal_participation_masses_cumulative; + // ((V'*M*R)^2)/diag(V'*M*V)/m_total_free_mass*100 + // the modal participation mass ratio (%) (size = NUM_MODES x NDF) + Matrix m_modal_participation_mass_ratios; + Matrix m_modal_participation_mass_ratios_cumulative; +}; + +#endif \ No newline at end of file diff --git a/SRC/runtime/commands/analysis/modal/ResponseSpectrumAnalysis.cpp b/SRC/runtime/commands/analysis/modal/ResponseSpectrumAnalysis.cpp new file mode 100644 index 0000000000..95667d6efb --- /dev/null +++ b/SRC/runtime/commands/analysis/modal/ResponseSpectrumAnalysis.cpp @@ -0,0 +1,317 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +// $Revision: 1.0 $ +// $Date: 2020-11-27 18:07:11 $ +// $Source: /usr/local/cvs/OpenSees/SRC/analysis/analysis/ResponseSpectrumAnalysis.h,v $ + +// Written: Massimo Petracca (ASDEA Software) +// Created: Fri Nov 27 18:07:11: 2020 +// Revision: A +// +// Description: This file contains the class definition for ResponseSpectrumAnalysis. +// +// What: "@(#) ResponseSpectrumAnalysis.h, revA" + +#include +#include "ResponseSpectrumAnalysis.h" +#include "DomainModalProperties.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#if defined(_WIN32) +#ifndef NOMINMAX +#define NOMINMAX +#endif +#endif + +ResponseSpectrumAnalysis::ResponseSpectrumAnalysis( + DomainModalProperties& mp, + TimeSeries* theFunction, + const std::vector& Tn, + const std::vector& Sa, + int theDirection, + double scale +) + : mp(mp) + , m_domain(mp.getDomain()) + , m_function(theFunction) + , m_Tn(Tn) + , m_Sa(Sa) + , m_direction(theDirection) + , m_scale(scale) + , m_current_mode(0) +{ + +} + +ResponseSpectrumAnalysis::~ResponseSpectrumAnalysis() +{ +} + +int +ResponseSpectrumAnalysis::analyze() +{ + // get the domain + Domain* domain = m_domain; + + // size info + int num_eigen = domain->getEigenvalues().Size(); + + // check consistency + int error_code; + error_code = check(); + if (error_code < 0) + return error_code; + + // loop over all required eigen-modes, compute the modal displacement + // and save the results. + // we just compute modal displacements without doing any (SRSS, CQC, etc..) + // modal combination otherwise derived results cannot be computed. + // for each mode, this analysis produces a new analysis step. + // modal combination of displacements (or any derived results) + // it's up to the user. + for (m_current_mode = 0; m_current_mode < num_eigen; ++m_current_mode) + { + // init the new step + error_code = beginMode(); + if (error_code < 0) return error_code; + + // compute modal acceleration for this mode using the + // provided response spectrum function (time series) + error_code = solveMode(); + if (error_code < 0) return error_code; + + // done with the current step. + // here the modal displacements will be recorded (and all other results + // if requested via recorders...) + error_code = endMode(); + if (error_code < 0) return error_code; + } + + return 0; +} + +int +ResponseSpectrumAnalysis::analyze(int mode_id) +{ + // get the domain + Domain* domain = m_domain; + + // size info + int num_eigen = domain->getEigenvalues().Size(); + if (mode_id < 0 || mode_id >= num_eigen) { + opserr << "ResponseSpectrumAnalysis::analyze(mode_id) - The provided mode_id (" << mode_id + 1 << ") is out of range (1, " << num_eigen << ")\n"; + return -1; + } + m_current_mode = mode_id; + + // check consistency + int error_code; + error_code = check(); + if (error_code < 0) return error_code; + + // init the new step + error_code = beginMode(); + if (error_code < 0) return error_code; + + // compute modal acceleration for this mode using the + // provided response spectrum function (time series) + error_code = solveMode(); + if (error_code < 0) return error_code; + + // done with the current step. + // here the modal displacements will be recorded (and all other results + // if requested via recorders...) + error_code = endMode(); + if (error_code < 0) return error_code; + + return 0; +} + +int +ResponseSpectrumAnalysis::check() +{ + // get the domain + Domain* domain = m_domain; + + + // number of eigen-modes + int num_eigen = domain->getEigenvalues().Size(); + if (num_eigen < 1) { + opserr << "ResponseSpectrumAnalysis::check() - No Eigenvalue provided.\n"; + return -1; + } + + // check consistency + { + const Vector& ev = domain->getEigenvalues(); + if (ev.Size() != mp.eigenvalues().Size()) + return -2; + double tol = std::max(1.0e-15, 1.0e-12 * ev.Norm()); + for (int i = 0; i < ev.Size(); ++i) { + double a = ev(i); + double b = mp.eigenvalues()(i); + if (std::abs(a - b) > tol) + return -2; + } + return 0; + }; + + return 0; +} + +int +ResponseSpectrumAnalysis::beginMode() +{ + // new step... (do nothing) + if (m_domain->analysisStep(0.0) < 0) { + opserr << "ResponseSpectrumAnalysis::analyze() - the AnalysisModel failed" + " at mode " << m_current_mode << "\n"; + return -1; + } + + return 0; +} + +int ResponseSpectrumAnalysis::endMode() +{ + // update domain + if (m_domain->update() < 0) { + opserr << "ResponseSpectrumAnalysis::analyze() - the AnalysisModel failed in updateDomain" + " at mode " << m_current_mode << "\n"; + return -1; + } + // update Handler (cmp) + + // commit domain + if (m_domain->commit() < 0) { + opserr << "ResponseSpectrumAnalysis::analyze() - the AnalysisModel failed in commitDomain" + " at mode " << m_current_mode << "\n"; + return -1; + } + + return 0; +} + +int +ResponseSpectrumAnalysis::solveMode() +{ + // get the domain + Domain* domain = m_domain; + + + // size info + int ndf = mp.totalMass().Size(); + + // excited DOF. + // Note: now we assume that a RS acts along one of the global directions, so we need + // to consider only the associated column of the modal participation factors. + // in future versions we can implement a general direction vector. + int exdof = m_direction - 1; // make it 0-based + + // compute modal acceleration for this mode using the + // provided response spectrum function (time series) + double lambda = mp.eigenvalues()(m_current_mode); + double omega = std::sqrt(lambda); + double freq = omega / 2.0 / M_PI; + double period = 1.0 / freq; + double mga = getSa(period); + double Vscale = mp.eigenVectorScaleFactors()(m_current_mode); + double MPF = mp.modalParticipationFactors()(m_current_mode, exdof); + + // loop over all nodes and compute the modal displacements + Node* node; + NodeIter& theNodes = domain->getNodes(); + while ((node = theNodes()) != 0) { + + // get the nodal eigenvector, according to the ndf of modal properties + // and its scaling + const Matrix& node_evec = node->getEigenvectors(); + int node_ndf = node_evec.noRows(); + + // for each DOF... + for (int i = 0; i < std::min(node_ndf, ndf); ++i) { + // exclude any dof >= node_ndf (if ndf > node_ndf... in case node is U-only) + // exclude any dof >= ndf (if node_ndf > ndf... in case the node has more DOFs than U and R) + + // we also need to exclude pressure dofs... easy in 3D because node_ndf is 4, + // but in 2D it is 3, as in U-R... + if (ndf == 6 && node_ndf == 4 && i == 3) + continue; + + // eigenvector + double V = node_evec(i, m_current_mode) * Vscale; + + // compute modal displacements for the i-th DOF + double u_modal = V * MPF * mga / lambda; + + // save this displacement at the i-th dof as new trial displacement + node->setTrialDisp(u_modal, i); + } + + } + + return 0; +} + +double ResponseSpectrumAnalysis::getSa(double T) const +{ + // use the time series if provided + if (m_function) + return m_function->getFactor(T); + // otherwise use the vectors + std::size_t n = m_Tn.size(); + // check empty + if (n < 1) + return 0.0; + // check constant + if (n == 1) + return m_Sa[0]; + // check bounds + if (T <= m_Tn.front()) + return m_Sa.front(); + if (T >= m_Tn.back()) + return m_Sa.back(); + // interpolate + for (std::size_t i = 1; i < n; ++i) { + double t1 = m_Tn[i]; + if (T <= t1) { + double t0 = m_Tn[i - 1]; + double s1 = m_Sa[i]; + double s0 = m_Sa[i - 1]; + double dT = t1 - t0; + double dS = s1 - s0; + double scale = dT > 0.0 ? (T - t0) / dT : 0.5; + return s0 + scale * dS; + } + } + return m_Sa.back(); +} diff --git a/SRC/runtime/commands/analysis/modal/ResponseSpectrumAnalysis.h b/SRC/runtime/commands/analysis/modal/ResponseSpectrumAnalysis.h new file mode 100644 index 0000000000..509a8eb536 --- /dev/null +++ b/SRC/runtime/commands/analysis/modal/ResponseSpectrumAnalysis.h @@ -0,0 +1,78 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +// $Revision: 1.0 $ +// $Date: 2020-11-27 18:07:11 $ +// $Source: /usr/local/cvs/OpenSees/SRC/analysis/analysis/ResponseSpectrumAnalysis.h,v $ + +// Written: Massimo Petracca (ASDEA Software) +// Created: Fri Nov 27 18:07:11: 2020 +// Revision: A +// +// Description: This file contains the class definition for ResponseSpectrumAnalysis. +// +// What: "@(#) ResponseSpectrumAnalysis.h, revA" + + +#include +class Domain; +class TimeSeries; +class DomainModalProperties; + +class ResponseSpectrumAnalysis +{ +public: + ResponseSpectrumAnalysis( + DomainModalProperties&, + TimeSeries*, + const std::vector& Tn, + const std::vector& Sa, + int theDirection, + double scale + ); + ~ResponseSpectrumAnalysis(); + +public: + int analyze(); + int analyze(int mode_id); + +private: + int check(); + int beginMode(); + int endMode(); + int solveMode(); + double getSa(double T) const; + +private: + DomainModalProperties& mp; + Domain* m_domain; + // the response spectrum function + TimeSeries* m_function; + std::vector m_Tn; + std::vector m_Sa; + // the direction 1 to 3 (for 2D models) or 1 to 6 (for 3D models) + int m_direction; + // the scale factor for the computed displacement field + double m_scale; + // current mode + int m_current_mode; +}; + + diff --git a/SRC/runtime/commands/analysis/modal/modal.cpp b/SRC/runtime/commands/analysis/modal/modal.cpp new file mode 100644 index 0000000000..f540ee2195 --- /dev/null +++ b/SRC/runtime/commands/analysis/modal/modal.cpp @@ -0,0 +1,366 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +#include +#include +#include + +#include +#include "DomainModalProperties.h" +#include "ResponseSpectrumAnalysis.h" + + +namespace OpenSees { + +Tcl_CmdProc responseSpectrumAnalysis; + +namespace DomainCommands { + +int +modalProperties(ClientData clientData, + Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) +{ + // modalProperties <-print> <-file $fileName> <-unorm> + + // some kudos + static bool first_done = false; + if (!first_done) { + opserr << "Using DomainModalProperties - Developed by: Massimo Petracca, Guido Camata, ASDEA Software Technology\n"; + first_done = true; + } + + // init default values + bool unorm = false; // by default do not displacement-normalize eigenvectors + bool print_on_console = false; // by default do not print on console + bool print_on_file = false; // by default do no print on file + std::string fname; + + // check options + int loc = 1; + while (loc < argc) { + if (strcmp(argv[loc], "-unorm") == 0) { + unorm = true; + } + else if (strcmp(argv[loc], "-print") == 0) { + print_on_console = true; + } + else if (strcmp(argv[loc], "-file") == 0) { + print_on_file = true; + if (loc < argc - 1) { + ++loc; + fname = argv[loc]; + } + else { + opserr << "Error in modalProperties; " + "After the keyword -file you should specify the file name.\n"; + return TCL_ERROR; + } + } + ++loc; + } + + + Domain* domain = static_cast(clientData); + + // create the modal properties, compute them, + // and add them to the domain + DomainModalProperties *modal_props = new DomainModalProperties(domain, unorm); + if (!modal_props->compute()) + return TCL_ERROR; + // domain->setModalProperties(modal_props); + + // report + if (print_on_console) + modal_props->print(); + + if (print_on_file) + modal_props->print(fname); + + + Tcl_CreateCommand(interp, "responseSpectrumAnalysis", + responseSpectrumAnalysis, modal_props, nullptr); + + return TCL_OK; +} + +} // namespace DomainCommands + + +int +responseSpectrumAnalysis(ClientData clientData, + Tcl_Interp* interp, + Tcl_Size argc, + const char** const argv) +{ + // responseSpectrum $tsTag $dir <-scale $scale> + // + + // some kudos + static bool first_done = false; + if (!first_done) { + opslog << "Using ResponseSpectrumAnalysis - Developed by: Massimo Petracca, Guido Camata, ASDEA Software Technology\n"; + first_done = true; + } + + if (clientData == nullptr) { + opserr << "ResponseSpectrumAnalysis - eigen and modalProperties have not been called" << "\n"; + return TCL_ERROR; + } + + + // make sure eigenvalue and modal properties have been called before + DomainModalProperties& modal_props = *static_cast(clientData); + + int ndf = modal_props.totalMass().Size(); + + + // + // parse + // + // ResponseSpectrumAnalysis $tsTag $dir <-scale $scale> <-damp $damp> + // or + // ResponseSpectrumAnalysis $dir -Tn $TnValues -fn $fnValues -Sa $SaValues <-scale $scale> <-damp $damp> + // + + // init default arguments + TimeSeries* ts = nullptr; + int dir = 1; + double scale = 1.0; + std::vector Tn; + std::vector Sa; + int mode_id = 0; + bool single_mode = false; + + + int nargs = argc - 1; // skip the command name + if (nargs < 2) { + opserr << "ResponseSpectrumAnalysis $tsTag $dir <-scale $scale> <-damp $damp>\n" + << "or\n" + << "ResponseSpectrumAnalysis $dir -Tn $TnValues -fn $fnValues -Sa $SaValues <-scale $scale> <-damp $damp>\n" + "Error: at least 2 arguments should be provided.\n"; + return TCL_ERROR; + } + + // search for -Tn -Sa, if both found we use them as lists + // otherwise we fallback to the old implementation of the timeSeries + bool found_Tn = false; + bool found_Sa = false; + for (int i=1; i <-damp $damp> + + int tstag; + if (Tcl_GetInt(interp, argv[argi], &tstag) != TCL_OK) { + opserr << "ResponseSpectrumAnalysis Error: Failed to get timeSeries tag.\n"; + return TCL_ERROR; + } + + // ts = OPS_getTimeSeries(tstag); + if (ts == nullptr) { + opserr << "ResponseSpectrumAnalysis Error: Failed to get timeSeries with tag = " << tstag << ".\n"; + return TCL_ERROR; + } + + argi++; // move to the next argument + } + + // get direction + if (Tcl_GetInt(interp, argv[argi], &dir) != TCL_OK) { + opserr << "ResponseSpectrumAnalysis Error: Failed to get direction.\n"; + return TCL_ERROR; + } + if (dir < 1 || dir > ndf) { + opserr << "ResponseSpectrumAnalysis Error: provided direction (" << dir << ") should be in the range 1-" << ndf << ".\n"; + return TCL_ERROR; + } + + // parse optional data + for (int i=argi; i= argc) { + opserr << "ResponseSpectrumAnalysis Error: scale factor requested but not provided.\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i+1], &scale) < 0) { + opserr << "ResponseSpectrumAnalysis Error: Failed to get scale factor.\n"; + return TCL_ERROR; + } + i++; + } + + else if (strcmp(value, "-mode") == 0) { + if (i + 1 >= argc) { + opserr << "ResponseSpectrumAnalysis Error: mode_id requested but not provided.\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[i + 1], &mode_id) < 0) { + opserr << "ResponseSpectrumAnalysis Error: Failed to get mode_id.\n"; + return TCL_ERROR; + } + --mode_id; // make it 0-based + single_mode = true; + i++; + } + + else if (strcmp(value, "-Tn") == 0 || strcmp(value, "-fn") == 0) { + // first try expanded list like {*}$the_list, + // also used in python like *the_list + Tn.clear(); + if (i + 1 >= argc) { + opserr << "ResponseSpectrumAnalysis Error: Tn values requested but not provided.\n"; + return TCL_ERROR; + } + + for (int j=i+1; j= argc) { + opserr << "ResponseSpectrumAnalysis Error: Sa values requested but not provided.\n"; + return TCL_ERROR; + } + + for (int j = i + 1; j < argc; j++) { + double item; + if (Tcl_GetDouble(interp, argv[j], &item) != TCL_OK) { + break; + } + Sa.push_back(item); + } + + if (Sa.size() == 0) { + // try Tcl list + int sa_argc; + const char** sa_argv = nullptr; + if (Tcl_SplitList(interp, argv[i + 1], &sa_argc, &sa_argv) != TCL_OK) { + opserr << "ResponseSpectrumAnalysis Error: cannot parse the Sa list.\n"; + return TCL_ERROR; + } + for (int j = 0; j < sa_argc; ++j) { + double item; + if (Tcl_GetDouble(interp, sa_argv[j], &item) != TCL_OK) { + opserr << "ResponseSpectrumAnalysis Error: cannot parse the Sa list.\n"; + Tcl_Free((char*)sa_argv); + return TCL_ERROR; + } + Sa.push_back(item); + } + Tcl_Free((char*)sa_argv); + } + } + } + + // check Tn and Sa vectors + if (use_lists) { + if (Tn.size() != Sa.size()) { + opserr << "ResponseSpectrumAnalysis Error: Sa and Tn lists must have the same length\n"; + opserr << (int)Tn.size() << " != " << (int)Sa.size() << "\n"; + return TCL_ERROR; + } + if (Tn.size() == 0) { + opserr << "ResponseSpectrumAnalysis Error: Sa and Tn lists cannot be empty\n"; + return TCL_ERROR; + } + for (std::size_t i = 0; i < Tn.size(); ++i) { + if (Tn[i] < 0.0) { + opserr << "ResponseSpectrumAnalysis Error: Tn values must be positive (found " << Tn[i] << ")\n"; + return TCL_ERROR; + } + if (i > 0 && Tn[i] <= Tn[i - 1]) { + opserr << "ResponseSpectrumAnalysis Error: Tn values must be monotonically increasing (found " << Tn[i] << " after " << Tn[i - 1] << ")\n"; + return TCL_ERROR; + } + } + for (double item : Sa) { + if (item < 0.0) { + opserr << "ResponseSpectrumAnalysis Error: Sa values must be positive (found " << item << ")\n"; + return TCL_ERROR; + } + } + } + + // Create the response spectrum analysis and run it + ResponseSpectrumAnalysis rsa(modal_props, ts, Tn, Sa, dir, scale); + int result; + if (single_mode) + result = rsa.analyze(mode_id); + else + result = rsa.analyze(); + + return result == 0? TCL_OK : TCL_ERROR; +} + + +} // namespace OpenSees \ No newline at end of file diff --git a/SRC/runtime/commands/analysis/numberer.cpp b/SRC/runtime/commands/analysis/numberer.cpp index f54cd2ce68..26076364eb 100644 --- a/SRC/runtime/commands/analysis/numberer.cpp +++ b/SRC/runtime/commands/analysis/numberer.cpp @@ -1,17 +1,26 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// -// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// // Description: This file implements the selection of a Numberer object, // which is used to optimally number the degrees of freedom of a problem. // #include #include #include -#include -#include +#include +#include #include #include diff --git a/SRC/runtime/commands/analysis/sensitivity.cpp b/SRC/runtime/commands/analysis/sensitivity.cpp index 324e022a59..1552adda8c 100644 --- a/SRC/runtime/commands/analysis/sensitivity.cpp +++ b/SRC/runtime/commands/analysis/sensitivity.cpp @@ -1,57 +1,117 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // #include -#include -#include +#include +#include +#include +#include +#include +#include +#include + + +int +computeGradients(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char**const argv) +{ + BasicAnalysisBuilder *builder = static_cast(clientData); + + if (builder->analyzeGradient() < 0) { + opserr << OpenSees::PromptValueError << "failed to compute sensitivities\n"; + return TCL_ERROR; + } + + return TCL_OK; +} int -TclCommand_sensitivityAlgorithm(ClientData builder, Tcl_Interp* interp, int argc, TCL_Char**const argv) +TclCommand_sensLambda(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { - if (builder == nullptr) - return 0; - - int analysisTypeTag = 1; - - Integrator* theIntegrator = nullptr; - - if (builder->getStaticIntegrator() != nullptr) { - theIntegrator = builder->getStaticIntegrator(); - - } else if(builder->getTransientIntegrator() != nullptr) { - theIntegrator = builder->getTransientIntegrator(); - } - - - // 1: compute at each step (default); - // 2: compute by command; - if (OPS_GetNumRemainingInputArgs() < 1) { - opserr << "ERROR: Wrong number of parameters to sensitivity algorithm." << "\n"; - return -1; - } - if (theIntegrator == nullptr) { - opserr << "The integrator needs to be instantiated before " << "\n" - << " setting sensitivity algorithm." << "\n"; - return -1; - } - - const char* type = OPS_GetString(); - if (strcmp(type,"-computeAtEachStep") == 0) - analysisTypeTag = 1; - else if (strcmp(type,"-computeByCommand") == 0) - analysisTypeTag = 2; - else { - opserr << "Unknown sensitivity algorithm option: " << type << "\n"; - return -1; - } - - theIntegrator->setComputeType(analysisTypeTag); - theIntegrator->activateSensitivityKey(); - - return 0; + BasicAnalysisBuilder* builder = static_cast(clientData); + + if (argc < 3) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + return TCL_ERROR; + } + + int pattern, paramTag; + if (Tcl_GetInt(interp, argv[1], &pattern) != TCL_OK) { + opserr << "ERROR reading load pattern tag\n"; + return TCL_ERROR; + } + + LoadPattern *thePattern = builder->getDomain()->getLoadPattern(pattern); + if (thePattern == nullptr) { + opserr << "ERROR load pattern with tag " << pattern + << " not found in domain\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[2], ¶mTag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "sensLambda patternTag? paramTag? - could not read " + "paramTag? "; + return TCL_ERROR; + } + + Parameter *theParam = builder->getDomain()->getParameter(paramTag); + if (theParam == nullptr) { + opserr << OpenSees::PromptValueError + << "sensLambda: parameter " << paramTag << " not found" << "\n"; + return TCL_ERROR; + } + + int gradIndex = theParam->getGradIndex(); + double value = thePattern->getLoadFactorSensitivity(gradIndex); + + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(value)); + + return TCL_OK; +} + + +int +TclCommand_sensitivityAlgorithm(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char**const argv) +{ + BasicAnalysisBuilder *builder = static_cast(clientData); + + if (argc < 2) { + opserr << "ERROR: Wrong number of parameters to sensitivity algorithm." << "\n"; + return TCL_ERROR; + } + + // 1: compute at each step (default); + // 2: compute by command; + + int analysisTypeTag = 1; + if (strcmp(argv[1],"-computeAtEachStep") == 0) + analysisTypeTag = 1; + + else if (strcmp(argv[1],"-computeByCommand") == 0) + analysisTypeTag = 2; + + else { + opserr << "Unknown sensitivity algorithm option: " << argv[1] << "\n"; + return TCL_ERROR; + } + + if (builder->setGradientType(analysisTypeTag) < 0) { + return TCL_ERROR; + } + + return TCL_OK; } diff --git a/SRC/runtime/commands/analysis/solver.cpp b/SRC/runtime/commands/analysis/solver.cpp index 66239dd0e9..e33e20ae8a 100644 --- a/SRC/runtime/commands/analysis/solver.cpp +++ b/SRC/runtime/commands/analysis/solver.cpp @@ -1,11 +1,19 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // -// Description: This file implements commands that configure the linear -// solver. +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Description: This file implements commands that configure the linear solver. // #include #include @@ -15,21 +23,14 @@ #else # include #endif -// #define strcmp strcasecmp #include -#include +#include +#include #include -// #include "analysis.h" -#include #include "solver.hpp" #include "BasicAnalysisBuilder.h" -// analysis -#include -#include -#include - // system of eqn and solvers #include #include @@ -39,18 +40,6 @@ #include #include -#ifdef _CUDA -# include -# include -#endif - -#ifdef _CULAS4 -# include -#endif - -#ifdef _CULAS5 -# include -#endif #if defined(_PARALLEL_PROCESSING) // parallel soe & solvers @@ -69,46 +58,37 @@ # include #endif -// TODO: remove -// extern DirectIntegrationAnalysis *theTransientAnalysis; -// extern LinearSOE *theSOE; -// LinearSOE* -// G3Parse_newLinearSOE(G3_Runtime*, int, G3_Char **); LinearSOE* -// G3Parse_newLinearSOE(G3_Runtime* rt, int argc, G3_Char ** const argv) G3Parse_newLinearSOE(ClientData, Tcl_Interp* interp, int, G3_Char **const); LinearSOE* TclDispatch_newPetscSOE(ClientData, Tcl_Interp *interp, int, G3_Char **const); -#if 0 // TODO: implement AnalysisBuilder->getLinearSOE(); + int TclCommand_systemSize(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { assert(clientData != nullptr); LinearSOE *theSOE = ((BasicAnalysisBuilder *)clientData)->getLinearSOE(); - char buffer[20]; - - if (theSOE == 0) { - sprintf(buffer, "NO SYSTEM SET"); + if (theSOE == nullptr) { + opserr << "No system has been set"; return TCL_OK; } - sprintf(buffer, "%d", theSOE->getNumEqn()); - Tcl_SetResult(interp, buffer, TCL_VOLATILE); + Tcl_SetObjResult(interp, Tcl_NewIntObj(theSOE->getNumEqn())); return TCL_OK; } -#endif + int specifySysOfEqnTable(ClientData clientData, Tcl_Interp *interp, int argc, G3_Char ** const argv) { // make sure at least one other argument to contain type of system if (argc < 2) { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "need to specify a system type" << "\n"; return TCL_ERROR; } @@ -125,8 +105,10 @@ specifySysOfEqnTable(ClientData clientData, Tcl_Interp *interp, int argc, G3_Cha } + LinearSOE* -G3Parse_newLinearSOE(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char ** const argv) +G3Parse_newLinearSOE(ClientData clientData, Tcl_Interp* interp, Tcl_Size argc, + G3_Char ** const argv) { G3_Runtime* rt = G3_getRuntime(interp); @@ -139,26 +121,18 @@ G3Parse_newLinearSOE(ClientData clientData, Tcl_Interp* interp, int argc, G3_Cha if (ctor != soe_table.end()) { return ctor->second.ss(rt, argc, argv); + } + +#if defined(XARA_USE_MUMPS) + else if (strcasecmp(argv[1], "mumps") == 0) { + return TclDispatch_newMumpsLinearSOE(clientData, interp, argc, argv); + } +#endif - } else if (strcasecmp(argv[1], "Umfpack")==0) { + else if (strcasecmp(argv[1], "Umfpack")==0) { // TODO: if "umfpack" is in solver.hpp, this wont be reached return TclDispatch_newUmfpackLinearSOE(clientData, interp, argc, argv); - } -#if 0 - else if (strcmp(argv[2],"Thread") == 0) { - int blockSize = 4; - int numThreads = 1; - if (argc == 5) { - if (Tcl_GetInt(interp, argv[3], &blockSize) != TCL_OK) - return nullptr; //TCL_ERROR; - if (Tcl_GetInt(interp, argv[4], &numThreads) != TCL_OK) - return nullptr; //TCL_ERROR; - } - return new ProfileSPDLinSOE( - *new ProfileSPDLinDirectThreadSolver(numThreads,blockSize,1.0e-12) - ); - } -#endif + } #if defined(OPS_PETSC) else if (strcmp(argv[1], "petsc")==0 || @@ -186,7 +160,9 @@ G3Parse_newLinearSOE(ClientData clientData, Tcl_Interp* interp, int argc, G3_Cha #endif else { - opserr << G3_ERROR_PROMPT << " system '" << argv[1] << "' is unknown or not installed\n"; + opserr << OpenSees::PromptValueError + << " system '" + << argv[1] << "' is unknown or not installed\n"; return nullptr; } @@ -267,7 +243,7 @@ specifySparseGen(G3_Runtime* rt, int argc, G3_Char ** const argv) count++; } - int permSpec = 0; + int permSpec = 1; int panelSize = 6; int relax = 6; @@ -290,7 +266,9 @@ specifySparseGen(G3_Runtime* rt, int argc, G3_Char ** const argv) char symmetric = 'N'; double drop_tol = 0.0; while (count < argc) { - if (strcmp(argv[count], "s") == 0 || strcmp(argv[count], "symmetric") || + if (strcmp(argv[count], "s") == 0 || + strcmp(argv[count], "symmetric") || + strcmp(argv[count], "-symmetric") || strcmp(argv[count], "-symm")) { symmetric = 'Y'; } @@ -307,136 +285,3 @@ specifySparseGen(G3_Runtime* rt, int argc, G3_Char ** const argv) #endif } - -#if 0 // Some misc solvers i play with - -else if (strcmp(argv[2],"Block") == 0) { - int blockSize = 4; - if (argc == 4) { - if (Tcl_GetInt(interp, argv[3], &blockSize) != TCL_OK) - return TCL_ERROR; - } - theSolver = theSolver = new ProfileSPDLinDirectBlockSolver(1.0e-12,blockSize); -} - - - int blockSize = 4; - int numThreads = 1; - if (argc == 5) { - if (Tcl_GetInt(interp, argv[3], &blockSize) != TCL_OK) - return TCL_ERROR; - if (Tcl_GetInt(interp, argv[4], &numThreads) != TCL_OK) - return TCL_ERROR; - } - theSolver = new ProfileSPDLinDirectThreadSolver(numThreads,blockSize,1.0e-12); - - } else if (strcmp(argv[2],"Thread") == 0) { - int blockSize = 4; - int numThreads = 1; - if (argc == 5) { - if (Tcl_GetInt(interp, argv[3], &blockSize) != TCL_OK) - return TCL_ERROR; - if (Tcl_GetInt(interp, argv[4], &numThreads) != TCL_OK) - return TCL_ERROR; - } - theSolver = new ProfileSPDLinDirectThreadSolver(numThreads,blockSize,1.0e-12); -} - -else if (strcmp(argv[2],"Skypack") == 0) { - if (argc == 5) { - int mCols, mRows; - if (Tcl_GetInt(interp, argv[3], &mCols) != TCL_OK) - return TCL_ERROR; - if (Tcl_GetInt(interp, argv[4], &mRows) != TCL_OK) - return TCL_ERROR; - theSolver = new ProfileSPDLinDirectSkypackSolver(mCols, mRows); - } else - theSolver = new ProfileSPDLinDirectSkypackSolver(); -} -else - theSolver = new ProfileSPDLinDirectSolver(); - -#endif // misc solvers - - -#if defined(_CULAS4) || defined(_CULAS5) -// CULA SPARSE -else if ((strcmp(argv[1], "CulaSparse") == 0)) { - double absTol = 1.0e-6; - double relTol = 1e-6; - - int maxInteration = 100000; - - int preCond = 5; // fainv -# ifdef _CULAS4 - preCond = 1; -# endif - int solver = 0; // cg - int count = 2; - int single = 0; - int host = 0; - - while (count < argc) { - - if (strcmp(argv[count], "-rTol") == 0) { - count++; - if (count < argc) - if (Tcl_GetDouble(interp, argv[count], &relTol) != TCL_OK) - return TCL_ERROR; - } else if ((strcmp(argv[count], "-mInt") == 0)) { - count++; - if (count < argc) - if (Tcl_GetInt(interp, argv[count], &maxInteration) != TCL_OK) - return TCL_ERROR; - } else if ((strcmp(argv[count], "-pre") == 0)) { - count++; - if (count < argc) - if ((strcmp(argv[count], "none") == 0)) - preCond = 0; - else if ((strcmp(argv[count], "jacobi") == 0)) - preCond = 1; - else if ((strcmp(argv[count], "blockjacobi") == 0)) - preCond = 2; - else if ((strcmp(argv[count], "ilu0") == 0)) - preCond = 3; - else if ((strcmp(argv[count], "ainv") == 0)) - preCond = 4; - else if ((strcmp(argv[count], "fainv") == 0)) - preCond = 5; - else - return TCL_ERROR; - } else if ((strcmp(argv[count], "-solver") == 0)) { - count++; - if (count < argc) - if ((strcmp(argv[count], "cg") == 0)) - solver = 0; - else if ((strcmp(argv[count], "bicg") == 0)) - solver = 1; - else if ((strcmp(argv[count], "blockstab") == 0)) - solver = 2; - else if ((strcmp(argv[count], "blockstabl") == 0)) - solver = 3; - else if ((strcmp(argv[count], "gmres") == 0)) - solver = 4; - else if ((strcmp(argv[count], "minres") == 0)) - solver = 5; - else - return TCL_ERROR; - } else if ((strcmp(argv[count], "-single") == 0)) { - single = 1; - } else if ((strcmp(argv[count], "-host") == 0)) { - host = 1; - } - count++; - } - -# ifdef _CULAS5 - CulaSparseSolverS5 *theSolver = new CulaSparseSolverS5( - relTol, maxInteration, preCond, solver, single, host); -# else - CulaSparseSolverS4 *theSolver = - new CulaSparseSolverS4(relTol, maxInteration, preCond, solver); -# endif - theSOE = new SparseGenRowLinSOE(*theSolver); -} -#endif diff --git a/SRC/runtime/commands/analysis/solver.hpp b/SRC/runtime/commands/analysis/solver.hpp index 83224f00fd..27cd7ea9d6 100644 --- a/SRC/runtime/commands/analysis/solver.hpp +++ b/SRC/runtime/commands/analysis/solver.hpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -12,10 +21,7 @@ #include #include #include -// analysis -#include -#include -#include + // system of eqn and solvers #include #include @@ -41,35 +47,9 @@ #include // #include -// #include -// #include #include #include -#include -#include -#include -#include -// -#ifdef _CUSP -# include -#endif - -#ifdef _CULAS4 -#include -#endif -#ifdef _CULAS5 -#include -#endif - -#if 1 || defined(_PETSC) -LinearSOE *TclCommand_newPetscSOE(int, TCL_Char**); -#endif - -#ifdef _CUDA -# include -# include -#endif #if defined(_PARALLEL_PROCESSING) // parallel soe & solvers @@ -96,10 +76,9 @@ typedef LinearSOE*(G3_SysOfEqnSpecifier)(G3_Runtime*, int, G3_Char**); // Specifiers defined in solver.cpp G3_SysOfEqnSpecifier specify_SparseSPD; G3_SysOfEqnSpecifier specifySparseGen; -TclDispatch TclDispatch_newMumpsLinearSOE; -// TclDispatch TclDispatch_newUmfpackLinearSOE; -LinearSOE* TclDispatch_newUmfpackLinearSOE(ClientData, Tcl_Interp*, int, const char** const); -LinearSOE* TclDispatch_newItpackLinearSOE(ClientData, Tcl_Interp*, int, const char** const); +LinearSOE* TclDispatch_newMumpsLinearSOE(ClientData, Tcl_Interp*, Tcl_Size, const char** const); +LinearSOE* TclDispatch_newUmfpackLinearSOE(ClientData, Tcl_Interp*, Tcl_Size, const char** const); +LinearSOE* TclDispatch_newItpackLinearSOE(ClientData, Tcl_Interp*, Tcl_Size, const char** const); // Helpers to automatically create constructors for systems/solvers // that do not take arguments when they are constructed. @@ -115,9 +94,13 @@ struct soefps {fn ss, sp, mp;}; std::unordered_map soe_table = { {"bandspd", { G3_SOE(BandSPDLinLapackSolver, BandSPDLinSOE), +#if 1 + SP_SOE(BandSPDLinLapackSolver, BandSPDLinSOE), + MP_SOE(BandSPDLinLapackSolver, BandSPDLinSOE)}}, +#else SP_SOE(BandSPDLinLapackSolver, DistributedBandSPDLinSOE), MP_SOE(BandSPDLinLapackSolver, DistributedBandSPDLinSOE)}}, - +#endif {"bandgeneral", { // BandGen, BandGEN G3_SOE(BandGenLinLapackSolver, BandGenLinSOE), SP_SOE(BandGenLinLapackSolver, DistributedBandGenLinSOE), @@ -126,13 +109,6 @@ std::unordered_map soe_table = { G3_SOE(BandGenLinLapackSolver, BandGenLinSOE), SP_SOE(BandGenLinLapackSolver, DistributedBandGenLinSOE), MP_SOE(BandGenLinLapackSolver, DistributedBandGenLinSOE)}}, -#if 0 - // TODO: Umfpack - {"umfpack", { - G3_SOE(BandGenLinLapackSolver, BandGenLinSOE), - SP_SOE(BandGenLinLapackSolver, DistributedBandGenLinSOE), - MP_SOE(BandGenLinLapackSolver, DistributedBandGenLinSOE)}}, -#endif {"sparsegen", {specifySparseGen, nullptr, nullptr}}, {"sparsegeneral", {specifySparseGen, nullptr, nullptr}}, @@ -162,13 +138,17 @@ std::unordered_map soe_table = { {"profilespd", { G3_SOE(ProfileSPDLinDirectSolver, ProfileSPDLinSOE), +#ifndef PARALLEL_PROFILESPD + SP_SOE(ProfileSPDLinDirectSolver, ProfileSPDLinSOE), + MP_SOE(ProfileSPDLinDirectSolver, ProfileSPDLinSOE)}}, +#else SP_SOE(ProfileSPDLinDirectSolver, DistributedProfileSPDLinSOE), MP_SOE(ProfileSPDLinDirectSolver, DistributedProfileSPDLinSOE)}}, {"parallelprofilespd", { nullptr, nullptr, MP_SOE(ProfileSPDLinDirectSolver, DistributedProfileSPDLinSOE)}}, - +#endif {"fullgeneral", { G3_SOE(FullGenLinLapackSolver, FullGenLinSOE), SP_SOE(FullGenLinLapackSolver, FullGenLinSOE), diff --git a/SRC/runtime/runtime/SectionBuilder/patch/QuadPatch.h b/SRC/runtime/commands/analysis/spectrum.cpp similarity index 53% rename from SRC/runtime/runtime/SectionBuilder/patch/QuadPatch.h rename to SRC/runtime/commands/analysis/spectrum.cpp index 83fb453d95..95da08d271 100644 --- a/SRC/runtime/runtime/SectionBuilder/patch/QuadPatch.h +++ b/SRC/runtime/commands/analysis/spectrum.cpp @@ -17,59 +17,61 @@ ** Filip C. Filippou (filippou@ce.berkeley.edu) ** ** ** ** ****************************************************************** */ + +// $Revision: 1.0 $ +// $Date: 2020-11-27 18:07:11 $ +// $Source: /usr/local/cvs/OpenSees/SRC/analysis/analysis/ResponseSpectrumAnalysis.h,v $ + +// Written: Massimo Petracca (ASDEA Software) +// Created: Fri Nov 27 18:07:11: 2020 +// Revision: A // -// File: QuadPatch.h -// Written by Remo M. de Souza -// December 1998 +// Description: This file contains the class definition for ResponseSpectrumAnalysis. // -#ifndef QuadPatch_h -#define QuadPatch_h +// What: "@(#) ResponseSpectrumAnalysis.h, revA" -#include -#include -#include -class Cell; -class Matrix; +#include +class Domain; +class TimeSeries; -class QuadPatch: public Patch +class ResponseSpectrumAnalysis { - public: - - QuadPatch(); - QuadPatch(int materialID, int numSubdivIJ, int numSubdivJK, - const Matrix &vertexCoords); - - ~QuadPatch(); - - // edition functions +public: + ResponseSpectrumAnalysis( + DomainModalProperties&, + TimeSeries*, + const std::vector& Tn, + const std::vector& Sa, + int theDirection, + double scale + ); + ~ResponseSpectrumAnalysis(); - void setMaterialID (int materialID); - void setDiscretization (int numSubdivIJ, int numSubdivJK); - void setVertCoords (const Matrix &vertexCoords); +public: + int analyze(); + int analyze(int mode_id); - // reinforcing bar inquiring functions - - int getMaterialID (void) const; - int getNumCells (void) const; - Cell **getCells (void) const; - Patch *getCopy (void) const; +private: + int check(); + int beginMode(); + int endMode(); + int solveMode(); + double getSa(double T) const; - void getDiscretization (int &numSubdivIJ, int &numSubdivJK) const; - const Matrix &getVertCoords (void) const; - - void Print(OPS_Stream &s, int flag =0) const; - friend OPS_Stream &operator<<(OPS_Stream &s, QuadPatch &quadPatch); - - protected: - - private: - int matID; - int nDivIJ, nDivJK; - Matrix vertCoord; +private: + DomainModalProperties& mp; + Domain* m_domain; + // the response spectrum function + TimeSeries* m_function; + std::vector m_Tn; + std::vector m_Sa; + // the direction 1 to 3 (for 2D models) or 1 to 6 (for 3D models) + int m_direction; + // the scale factor for the computed displacement field + double m_scale; + // current mode + int m_current_mode; }; -#endif - - diff --git a/SRC/runtime/commands/analysis/transient.cpp b/SRC/runtime/commands/analysis/transient.cpp index 3016b5deea..1c8f2039d6 100644 --- a/SRC/runtime/commands/analysis/transient.cpp +++ b/SRC/runtime/commands/analysis/transient.cpp @@ -1,25 +1,37 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // // Written: cmp and cc // #include -#include -#include +#include +#include +#include #include #include #include TransientIntegrator* -TclCommand_newNewmarkIntegrator(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char ** const argv) +TclCommand_newNewmarkIntegrator(ClientData clientData, Tcl_Interp* interp, + Tcl_Size argc, G3_Char ** const argv) { if (argc < 4) { - opserr << G3_ERROR_PROMPT << " incorrect number of args want Newmark $gamma $beta " + opserr << OpenSees::PromptValueError + << " incorrect number of args want Newmark $gamma $beta " "<-form $typeUnknown>\n"; opserr << " got "; for (int i=0; i " - " \n"; + double gamma; + double beta; + double alphaM, betaK, betaKi, betaKc; + if (argc != 4 && argc != 8) { + opserr << "WARNING integrator Newmark1 gamma beta " + " \n"; + return nullptr; + } + if (Tcl_GetDouble(interp, argv[2], &gamma) != TCL_OK) { + opserr << "WARNING integrator Newmark1 gamma beta - undefined gamma\n"; + return nullptr; + } + if (Tcl_GetDouble(interp, argv[3], &beta) != TCL_OK) { + opserr << "WARNING integrator Newmark1 gamma beta - undefined beta\n"; + return nullptr; + } + + if (argc == 8 || argc == 7) { + if (Tcl_GetDouble(interp, argv[4], &alphaM) != TCL_OK) { + opserr << "WARNING integrator Newmark1 gamma beta alphaM betaK betaKi " + "betaKc - alphaM\n"; return nullptr; } - if (Tcl_GetDouble(interp, argv[2], &gamma) != TCL_OK) { - opserr << "WARNING integrator Newmark1 gamma beta - undefined gamma\n"; + if (Tcl_GetDouble(interp, argv[5], &betaK) != TCL_OK) { + opserr << "WARNING integrator Newmark1 gamma beta alphaM betaK betaKi " + "betaKc - betaK\n"; return nullptr; } - if (Tcl_GetDouble(interp, argv[3], &beta) != TCL_OK) { - opserr << "WARNING integrator Newmark1 gamma beta - undefined beta\n"; + if (Tcl_GetDouble(interp, argv[6], &betaKi) != TCL_OK) { + opserr << "WARNING integrator Newmark1 gamma beta alphaM betaK betaKi " + "betaKc - betaKi\n"; return nullptr; } - - if (argc == 8 || argc == 7) { - if (Tcl_GetDouble(interp, argv[4], &alphaM) != TCL_OK) { - opserr << "WARNING integrator Newmark1 gamma beta alphaM betaK betaKi " - "betaKc - alphaM\n"; - return nullptr; - } - if (Tcl_GetDouble(interp, argv[5], &betaK) != TCL_OK) { - opserr << "WARNING integrator Newmark1 gamma beta alphaM betaK betaKi " - "betaKc - betaK\n"; - return nullptr; - } - if (Tcl_GetDouble(interp, argv[6], &betaKi) != TCL_OK) { - opserr << "WARNING integrator Newmark1 gamma beta alphaM betaK betaKi " - "betaKc - betaKi\n"; - return nullptr; - } - if (Tcl_GetDouble(interp, argv[7], &betaKc) != TCL_OK) { - opserr << "WARNING integrator Newmark1 gamma beta alphaM betaK betaKi " - "betaKc - betaKc\n"; - return nullptr; - } + if (Tcl_GetDouble(interp, argv[7], &betaKc) != TCL_OK) { + opserr << "WARNING integrator Newmark1 gamma beta alphaM betaK betaKi " + "betaKc - betaKc\n"; + return nullptr; } - if (argc == 4) - return new Newmark1(gamma, beta); - else - return new Newmark1(gamma, beta, alphaM, betaK, betaKi, betaKc); + } + if (argc == 4) + return new Newmark1(gamma, beta); + else + return new Newmark1(gamma, beta, alphaM, betaK, betaKi, betaKc); } diff --git a/SRC/runtime/commands/domain/TclUpdateMaterialCommand.cpp b/SRC/runtime/commands/domain/TclUpdateMaterialCommand.cpp deleted file mode 100644 index bb838c9c89..0000000000 --- a/SRC/runtime/commands/domain/TclUpdateMaterialCommand.cpp +++ /dev/null @@ -1,91 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// OpenSees - Open System for Earthquake Engineering Simulation -// -//===----------------------------------------------------------------------===// -// -// Description: This command is used to update the parameters of -// PressureDependMultiYield or PressureIndependMultiYield material. Currently, -// two material parameters, reference low-strain shear modulus Gr and reference -// bulk modulus Br, can be modified during an analysis. -// -// Written: fmk -// -#include -#include -#include -#include -// #include -#include - - -int -TclCommand_UpdateMaterialsCommand(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) -{ - assert(clientData != nullptr); - Domain* theDomain = static_cast(clientData); - - if (argc < 5) { - opserr << "WARNING insufficient number of UpdateMaterialStage arguments\n"; - opserr << "Want: UpdateMaterialStage material matTag? stage value?" - << endln; - return TCL_ERROR; - } - - if (strcmp(argv[1], "-material") != 0) { - opserr << "WARNING UpdateMaterialStage: Only accept parameter '-material' " - "for now" - << endln; - return TCL_ERROR; - } - - int materialTag, value; - double valueD; - - if (Tcl_GetInt(interp, argv[2], &materialTag) != TCL_OK) { - opserr << "WARNING MYSstage: invalid material tag" << endln; - return TCL_ERROR; - } - - int parTag = theDomain->getNumParameters(); - parTag++; - - if (argc > 5) { - if (strcmp(argv[5], "-parameter") == 0) { - if (Tcl_GetInt(interp, argv[6], &parTag) != TCL_OK) { - opserr << "WARNING UpdateMaterialStage: invalid parameter tag" << endln; - return TCL_ERROR; - } - } - } - - MatParameter *theParameter = new MatParameter(parTag, materialTag, argv[3]); - - if (theDomain->addParameter(theParameter) == false) { - opserr << "WARNING could not add updateMaterialStage - " - "MaterialStageParameter to domain" - << endln; - return TCL_ERROR; - } - - int res = 0; - if (Tcl_GetInt(interp, argv[4], &value) != TCL_OK) { - - if (Tcl_GetDouble(interp, argv[4], &valueD) != TCL_OK) { - opserr << "WARNING UpdateMaterialStage: could not read value" << endln; - return TCL_ERROR; - } else { - - res = theDomain->updateParameter(parTag, valueD); - - theDomain->removeParameter(parTag); - } - } else { - - res = theDomain->updateParameter(parTag, value); - - theDomain->removeParameter(parTag); - } - return res; -} diff --git a/SRC/runtime/commands/domain/TclUpdateMaterialStageCommand.cpp b/SRC/runtime/commands/domain/TclUpdateMaterialStageCommand.cpp deleted file mode 100644 index ace1e656d7..0000000000 --- a/SRC/runtime/commands/domain/TclUpdateMaterialStageCommand.cpp +++ /dev/null @@ -1,216 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// OpenSees - Open System for Earthquake Engineering Simulation -// -//===----------------------------------------------------------------------===// -// -// Description: This command is used to update a PressureDependMultiYield, -// PressureDependMultiYield02, PressureIndependMultiYield, or FluidSolidPorous -// material. To conduct a seismic analysis, two stages should be followed. -// First, during the application of gravity load (and static loads if any), set -// material stage to 0, and material behavior is linear elastic (with Gr and Br -// as elastic moduli). A FluidSolidPorous material does not contribute to the -// material response if its stage is set to 0. After the application of gravity -// load, set material stage to 1 or 2. In case of stage 2, all the elastic -// material properties are then internally determined at the current effective -// confinement, and remain constant thereafter. In the subsequent dynamic -// (fast) loading phase(s), the deviatoric stress-strain response is -// elastic-plastic (stage 1) or linear-elastic (stage 2), and the volumetric -// response remains linear-elastic. Please visit -// http://cyclic.ucsd.edu/opensees for examples. -// -// Written: ZHY -// -// $Revision: 1.16 $ -// $Date: 2007-10-16 00:15:07 $ -// -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -int -TclCommand_updateMaterialStage(ClientData clientData, - Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - - BasicModelBuilder* builder = (BasicModelBuilder*)clientData; - Domain* domain = builder->getDomain(); - - if (argc < 5) { - opserr << "WARNING insufficient number of UpdateMaterialStage arguments\n"; - opserr << "Want: UpdateMaterialStage material matTag? stage value?" - << endln; - return TCL_ERROR; - } - - if (strcmp(argv[1], "-material") != 0) { - opserr << "WARNING UpdateMaterialStage: Only accept parameter '-material' " - "for now" - << endln; - return TCL_ERROR; - } - - int materialTag, value; - - if (Tcl_GetInt(interp, argv[2], &materialTag) != TCL_OK) { - opserr << "WARNING MYSstage: invalid material tag" << endln; - return TCL_ERROR; - } - - int parTag = domain->getNumParameters(); - parTag++; - - if (argc > 6) { - if (strcmp(argv[5], "-parameter") == 0) { - if (Tcl_GetInt(interp, argv[6], &parTag) != TCL_OK) { - opserr << "WARNING UpdateMaterialStage: invalid parameter tag used" - << endln; - return TCL_ERROR; - } - } - } - - MaterialStageParameter *theParameter = - new MaterialStageParameter(parTag, materialTag); - if (domain->addParameter(theParameter) == false) { - opserr << "WARNING could not add updateMaterialStage - " - "MaterialStageParameter to domain" - << endln; - return TCL_ERROR; - } - - if (strcmp(argv[3], "-stage") != 0) { - opserr - << "WARNING UpdateMaterialStage: Only accept parameter '-stage' for now" - << endln; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[4], &value) != TCL_OK) { - opserr << "WARNING UpdateMaterialStage: invalid parameter value" << endln; - return TCL_ERROR; - } - - domain->updateParameter(parTag, value); - - domain->removeParameter(parTag); - - delete theParameter; - - return TCL_OK; -} - - -int -TclBasicBuilderUpdateParameterCommand(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) -{ - - BasicModelBuilder* builder = (BasicModelBuilder*)clientData; - - if (argc < 5) { - opserr << "WARNING insufficient number of updateParameter arguments\n"; - opserr << "Want: updateParameter -material matNum? -param? newValue?" - << endln; - return TCL_ERROR; - } - - if (strcmp(argv[1], "-material") != 0) { - opserr - << "WARNING UpdateParameter: Only accept parameter '-material' for now" - << endln; - return TCL_ERROR; - } - - int tag, id; - double value; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING UpdateParameter: invalid material tag" << endln; - return TCL_ERROR; - } - - // TODO: This will print an error message if not found; maybe - // getTypedObject should accept flag that tells it not to print - NDMaterial *a = builder->getTypedObject(tag); - - if (a == 0) { - // opserr << "WARNING UpdateParameter: couldn't get NDmaterial tagged: " << - // tag << endln; return TCL_ERROR; - UniaxialMaterial *a = builder->getTypedObject(tag); - if (a == 0) { - opserr - << "WARNING UpdateParameter: couldn't get Uniaxialmaterial tagged: " - << tag << endln; - return TCL_ERROR; - } - if (strcmp(argv[3], "-E") == 0) { - if (Tcl_GetDouble(interp, argv[4], &value) != TCL_OK) { - opserr << "WARNING UpdateParameter: invalid parameter value" << endln; - return TCL_ERROR; - } - Information info; - info.setDouble(value); - a->updateParameter(0, info); - } else if (strcmp(argv[3], "-fy") == 0) { - if (Tcl_GetDouble(interp, argv[4], &value) != TCL_OK) { - opserr << "WARNING UpdateParameter: invalid parameter value" << endln; - return TCL_ERROR; - } - Information info; - info.setDouble(value); - a->updateParameter(1, info); - } else { - opserr << "WARNING UpdateParameter: Only accept parameter '-E' or '-fy' " - "for now" - << endln; - return TCL_ERROR; - } - return TCL_OK; - } - - if (strcmp(argv[3], "-refG") == 0) - id = 10; - else if (strcmp(argv[3], "-refB") == 0) - id = 11; - else { - opserr << "WARNING UpdateParameter: Only accept parameter '-refG' or " - "'-refB' for now" - << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[4], &value) != TCL_OK) { - opserr << "WARNING UpdateParameter: invalid parameter value" << endln; - return TCL_ERROR; - } - - const char *c = a->getType(); - - if (strcmp(c, "PlaneStrain") == 0 || strcmp(c, "ThreeDimensional") == 0) { - Information info; - info.setDouble(value); - a->updateParameter(id, info); - } else { - opserr << "WARNING UpdateParameter: The tagged is not a " << endln; - opserr << "PressureDependMultiYield/PressureIndependMultiYield/" - "FluidSolidPorous material. " - << endln; - return TCL_ERROR; - } - - return TCL_OK; -} diff --git a/SRC/runtime/commands/domain/commands.cpp b/SRC/runtime/commands/domain/commands.cpp index ef81a54f1f..b35d00a0fc 100644 --- a/SRC/runtime/commands/domain/commands.cpp +++ b/SRC/runtime/commands/domain/commands.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -8,8 +17,8 @@ // the interpreter when the appropriate command name is specified. // #include -#include -#include +#include +#include #include #include // @@ -45,12 +54,8 @@ #include #include // Analysis -#include -#include -#include #include #include -#include #include #include #include @@ -65,8 +70,6 @@ // class ModelBuilder; ModelBuilder *theBuilder = nullptr; -VariableTimeStepDirectIntegrationAnalysis - *theVariableTimeStepTransientAnalysis = nullptr; // // Forward declarations // @@ -89,6 +92,35 @@ G3_AddTclDomainCommands(Tcl_Interp *interp, Domain* the_domain) ClientData domain = (ClientData)the_domain; + { + using namespace OpenSees::DomainCommands; + // Domain + Tcl_CreateObjCommand(interp, "fixedNodes", &fixedNodes, domain, nullptr); + Tcl_CreateObjCommand(interp, "fixedDOFs", &fixedDOFs, domain, nullptr); + Tcl_CreateObjCommand(interp, "constrainedNodes", &constrainedNodes, domain, nullptr); + Tcl_CreateObjCommand(interp, "constrainedDOFs", &constrainedDOFs, domain, nullptr); + Tcl_CreateObjCommand(interp, "domainChange", &domainChange, domain, nullptr); + Tcl_CreateObjCommand(interp, "remove", &removeObject, domain, nullptr); + Tcl_CreateCommand(interp, "retainedNodes", &retainedNodes, domain, nullptr); + Tcl_CreateCommand(interp, "retainedDOFs", &retainedDOFs, domain, nullptr); + // Elements + Tcl_CreateCommand(interp, "localForce", &localForce, domain, nullptr); + Tcl_CreateCommand(interp, "eleType", &eleType, domain, nullptr); + Tcl_CreateCommand(interp, "eleNodes", &eleNodes, domain, nullptr); + Tcl_CreateCommand(interp, "getEleTags", &getEleTags, domain, nullptr); + Tcl_CreateCommand(interp, "getNumElements", &getNumElements, domain, nullptr); + Tcl_CreateCommand(interp, "getEleClassTags", &getEleClassTags, domain, nullptr); + Tcl_CreateCommand(interp, "eleForce", &eleForce, domain, nullptr); + Tcl_CreateCommand(interp, "eleResponse", &eleResponse, domain, nullptr); + Tcl_CreateCommand(interp, "eleDynamicalForce", &eleDynamicalForce, domain, nullptr); + Tcl_CreateCommand(interp, "updateElementDomain", &updateElementDomain, nullptr, nullptr); + // damping + Tcl_CreateCommand(interp, "setElementRayleighDampingFactors", &addElementRayleigh, domain, nullptr); + Tcl_CreateCommand(interp, "setElementRayleighFactors", &addElementRayleigh, domain, nullptr); + // Modal + Tcl_CreateCommand(interp, "modalProperties", &modalProperties, domain, nullptr); + } + Tcl_CreateCommand(interp, "loadConst", &TclCommand_setLoadConst, domain, nullptr); Tcl_CreateCommand(interp, "recorder", &TclAddRecorder, domain, nullptr); Tcl_CreateCommand(interp, "region", &TclCommand_addMeshRegion, domain, nullptr); @@ -101,21 +133,14 @@ G3_AddTclDomainCommands(Tcl_Interp *interp, Domain* the_domain) // DAMPING Tcl_CreateCommand(interp, "rayleigh", &rayleighDamping, domain, nullptr); - - Tcl_CreateCommand(interp, "setElementRayleighDampingFactors", &TclCommand_addElementRayleigh, domain, nullptr); - Tcl_CreateCommand(interp, "setElementRayleighFactors", &TclCommand_addElementRayleigh, domain, nullptr); + Tcl_CreateCommand(interp, "getLoadFactor", &getLoadFactor, domain, nullptr); - Tcl_CreateCommand(interp, "localForce", &localForce, domain, nullptr); - Tcl_CreateCommand(interp, "eleType", &eleType, domain, nullptr); - Tcl_CreateCommand(interp, "eleNodes", &eleNodes, domain, nullptr); - Tcl_CreateCommand(interp, "getEleTags", &TclCommand_getEleTags, domain, nullptr); + + // Tcl_CreateCommand(interp, "basicDeformation", &basicDeformation, domain, nullptr); Tcl_CreateCommand(interp, "basicForce", &basicForce, domain, nullptr); Tcl_CreateCommand(interp, "basicStiffness", &basicStiffness, domain, nullptr); - Tcl_CreateCommand(interp, "eleForce", &eleForce, domain, nullptr); - Tcl_CreateCommand(interp, "eleResponse", &eleResponse, domain, nullptr); - Tcl_CreateCommand(interp, "eleDynamicalForce", &eleDynamicalForce, domain, nullptr); Tcl_CreateCommand(interp, "nodeDOFs", &nodeDOFs, domain, nullptr); Tcl_CreateCommand(interp, "nodeCoord", &nodeCoord, domain, nullptr); @@ -129,35 +154,27 @@ G3_AddTclDomainCommands(Tcl_Interp *interp, Domain* the_domain) Tcl_CreateCommand(interp, "findNodeWithID", &findID, domain, nullptr); Tcl_CreateCommand(interp, "nodeUnbalance", &nodeUnbalance, domain, nullptr); Tcl_CreateCommand(interp, "nodeEigenvector", &nodeEigenvector, domain, nullptr); - Tcl_CreateCommand(interp, "nodeReaction", &nodeReaction, domain, nullptr); + Tcl_CreateCommand(interp, "reactions", &calculateNodalReactions, domain, nullptr); Tcl_CreateCommand(interp, "setNodeVel", &setNodeVel, domain, nullptr); Tcl_CreateCommand(interp, "setNodeDisp", &setNodeDisp, domain, nullptr); Tcl_CreateCommand(interp, "setNodeAccel", &setNodeAccel, domain, nullptr); Tcl_CreateCommand(interp, "setNodeCoord", &setNodeCoord, domain, nullptr); - - Tcl_CreateCommand(interp, "getEleTags", &getEleTags, domain, nullptr); + Tcl_CreateCommand(interp, "nodeRotation", &nodeRotation, domain, nullptr); Tcl_CreateCommand(interp, "getNodeTags", &getNodeTags, domain, nullptr); + + Tcl_CreateCommand(interp, "getParamTags", &getParamTags, domain, nullptr); Tcl_CreateCommand(interp, "getParamValue", &getParamValue, domain, nullptr); Tcl_CreateCommand(interp, "parameter", &TclCommand_parameter, domain, nullptr); Tcl_CreateCommand(interp, "addToParameter", &TclCommand_parameter, domain, nullptr); Tcl_CreateCommand(interp, "updateParameter", &TclCommand_parameter, domain, nullptr); + Tcl_CreateCommand(interp, "setParameter", &TclCommand_setParameter, domain, nullptr); + - Tcl_CreateObjCommand(interp, "fixedNodes", &fixedNodes, domain, nullptr); - Tcl_CreateObjCommand(interp, "fixedDOFs", &fixedDOFs, domain, nullptr); - Tcl_CreateObjCommand(interp, "constrainedNodes", &constrainedNodes, domain, nullptr); - Tcl_CreateObjCommand(interp, "constrainedDOFs", &constrainedDOFs, domain, nullptr); - Tcl_CreateObjCommand(interp, "domainChange", &domainChange, domain, nullptr); - Tcl_CreateObjCommand(interp, "remove", &removeObject, domain, nullptr); - Tcl_CreateCommand(interp, "retainedNodes", &retainedNodes, domain, nullptr); - Tcl_CreateCommand(interp, "retainedDOFs", &retainedDOFs, domain, nullptr); - - Tcl_CreateCommand(interp, "getNumElements", &getNumElements, domain, nullptr); - Tcl_CreateCommand(interp, "getEleClassTags", &getEleClassTags, domain, nullptr); Tcl_CreateCommand(interp, "getEleLoadTags", &getEleLoadTags, domain, nullptr); Tcl_CreateCommand(interp, "getEleLoadData", &getEleLoadData, domain, nullptr); Tcl_CreateCommand(interp, "getEleLoadClassTags", &getEleLoadClassTags, domain, nullptr); @@ -175,13 +192,21 @@ G3_AddTclDomainCommands(Tcl_Interp *interp, Domain* the_domain) Tcl_CreateCommand(interp, "recorderValue", &OPS_recorderValue, domain, nullptr); Tcl_CreateCommand(interp, "record", &TclCommand_record, domain, nullptr); - Tcl_CreateCommand(interp, "updateElementDomain", &updateElementDomain, nullptr, nullptr); - Tcl_CreateCommand(interp, "InitialStateAnalysis", &InitialStateAnalysis, nullptr, nullptr); + // sensitivity + Tcl_CreateCommand(interp, "computeGradients", &computeGradients, (ClientData)domain, (Tcl_CmdDeleteProc *)NULL); + Tcl_CreateCommand(interp, "sensitivityAlgorithm", &TclCommand_sensitivityAlgorithm, (ClientData)domain, (Tcl_CmdDeleteProc *)NULL); + Tcl_CreateCommand(interp, "sensNodeDisp", &sensNodeDisp, (ClientData)domain, (Tcl_CmdDeleteProc *)NULL); +//Tcl_CreateCommand(interp, "sensLambda", &sensLambda, (ClientData)domain, (Tcl_CmdDeleteProc *)NULL); // Abbas + Tcl_CreateCommand(interp, "sensNodeVel", &sensNodeVel, (ClientData)domain, (Tcl_CmdDeleteProc *)NULL); + Tcl_CreateCommand(interp, "sensNodeAccel", &sensNodeAccel, (ClientData)domain, (Tcl_CmdDeleteProc *)NULL); + Tcl_CreateCommand(interp, "sensSectionForce", &sensSectionForce, (ClientData)domain, (Tcl_CmdDeleteProc *)NULL); + Tcl_CreateCommand(interp, "sensNodePressure", &sensNodePressure, (ClientData)domain, (Tcl_CmdDeleteProc *)NULL); + + // TODO: cmp, moved definition to packages/optimization; need to link in optionally -// Tcl_CreateCommand(interp, "setParameter", &setParameter, nullptr, nullptr); // Tcl_CreateCommand(interp, "sdfResponse", &sdfResponse, nullptr, nullptr); // Tcl_CreateCommand(interp, "database", &addDatabase, nullptr, nullptr); @@ -193,26 +218,28 @@ G3_AddTclDomainCommands(Tcl_Interp *interp, Domain* the_domain) int -getLoadFactor(ClientData clientData, Tcl_Interp *interp, int argc, +getLoadFactor(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); Domain* domain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "no load pattern supplied -- getLoadFactor\n"; + opserr << OpenSees::PromptValueError + << "no load pattern supplied -- getLoadFactor\n"; return TCL_ERROR; } int pattern; if (Tcl_GetInt(interp, argv[1], &pattern) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "reading load pattern tag -- getLoadFactor\n"; + opserr << OpenSees::PromptValueError + << "reading load pattern tag -- getLoadFactor\n"; return TCL_ERROR; } LoadPattern *the_pattern = domain->getLoadPattern(pattern); if (the_pattern == nullptr) { - opserr << G3_ERROR_PROMPT << "load pattern with tag " << pattern + opserr << OpenSees::PromptValueError << "load pattern with tag " << pattern << " not found in domain -- getLoadFactor\n"; return TCL_ERROR; } @@ -227,7 +254,7 @@ getLoadFactor(ClientData clientData, Tcl_Interp *interp, int argc, // added by C.McGann, U.Washington int -InitialStateAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, +InitialStateAnalysis(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -236,12 +263,12 @@ InitialStateAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, if (argc < 2) { opserr << "WARNING: Incorrect number of arguments for InitialStateAnalysis " "command" - << endln; + << "\n"; return TCL_ERROR; } if (strcmp(argv[1], "on") == 0) { - opserr << "InitialStateAnalysis ON" << endln; + opserr << "InitialStateAnalysis ON" << "\n"; // set global variable to true // FMK changes for parallel: @@ -254,7 +281,7 @@ InitialStateAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, return TCL_OK; } else if (strcmp(argv[1], "off") == 0) { - opserr << "InitialStateAnalysis OFF" << endln; + opserr << "InitialStateAnalysis OFF" << "\n"; // call revert to start to zero the displacements the_domain->revertToStart(); @@ -271,46 +298,47 @@ InitialStateAnalysis(ClientData clientData, Tcl_Interp *interp, int argc, } else { opserr << "WARNING: Incorrect arguments - want InitialStateAnalysis on, or " "InitialStateAnalysis off" - << endln; + << "\n"; return TCL_ERROR; } } int -rayleighDamping(ClientData clientData, Tcl_Interp *interp, int argc, +rayleighDamping(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { - + // + // rayleigh alphaM? betaK? betaK0? betaKc? + // if (argc < 3) { - opserr << G3_ERROR_PROMPT - << "rayleigh alphaM? betaK? betaK0? betaKc? - not enough " - "arguments to command\n"; + opserr << OpenSees::PromptValueError + << "not enough arguments to command\n"; return TCL_ERROR; } double alphaM, betaK, betaK0=0.0, betaKc=0.0; if (Tcl_GetDouble(interp, argv[1], &alphaM) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rayleigh alphaM? betaK? betaK0? betaKc? - could not " - "read alphaM? \n"; + opserr << OpenSees::PromptValueError + << "could not read alphaM? \n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[2], &betaK) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rayleigh alphaM? betaK? betaK0? betaKc? - could not " - "read betaK? \n"; + opserr << OpenSees::PromptValueError + << "could not read betaK? \n"; return TCL_ERROR; } if (argc > 3 && Tcl_GetDouble(interp, argv[3], &betaK0) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rayleigh alphaM? betaK? betaK0? betaKc? - could not " - "read betaK0? \n"; + opserr << OpenSees::PromptValueError + << "could not read betaK0? \n"; return TCL_ERROR; } if (argc > 4 && Tcl_GetDouble(interp, argv[4], &betaKc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rayleigh alphaM? betaK? betaK0? betaKc? - could not " - "read betaKc? \n"; + opserr << OpenSees::PromptValueError + << "could not read betaKc? \n"; return TCL_ERROR; } @@ -322,48 +350,12 @@ rayleighDamping(ClientData clientData, Tcl_Interp *interp, int argc, int -getEleClassTags(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - assert(clientData != nullptr); - Domain *the_domain = (Domain*)clientData; - - if (argc == 1) { - Element *theEle; - ElementIter &eleIter = the_domain->getElements(); - - char buffer[20]; - - while ((theEle = eleIter()) != nullptr) { - sprintf(buffer, "%d ", theEle->getClassTag()); - Tcl_AppendResult(interp, buffer, NULL); - } - } else if (argc == 2) { - int eleTag; - - if (Tcl_GetInt(interp, argv[1], &eleTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "getParamValue -- could not read paramTag \n"; - return TCL_ERROR; - } - - Element *theEle = the_domain->getElement(eleTag); - - char buffer[20]; - sprintf(buffer, "%d ", theEle->getClassTag()); - Tcl_AppendResult(interp, buffer, NULL); - - } else { - opserr << G3_ERROR_PROMPT << "want - getEleClassTags \n" << endln; - return TCL_ERROR; - } - - return TCL_OK; -} - -int -getEleLoadClassTags(ClientData clientData, Tcl_Interp *interp, int argc, +getEleLoadClassTags(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { + // + // getEleLoadClassTags + // assert(clientData != nullptr); Domain *the_domain = (Domain*)clientData; @@ -382,34 +374,37 @@ getEleLoadClassTags(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_AppendResult(interp, buffer, NULL); } } - - } else if (argc == 2) { + } + else if (argc == 2) { int patternTag; if (Tcl_GetInt(interp, argv[1], &patternTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "getEleLoadClassTags -- could not read patternTag\n"; + opserr << OpenSees::PromptValueError << "failed to read patternTag\n"; return TCL_ERROR; } LoadPattern *thePattern = the_domain->getLoadPattern(patternTag); if (thePattern == nullptr) { - opserr << G3_ERROR_PROMPT << "load pattern with tag " << patternTag - << " not found in domain -- getEleLoadClassTags\n"; + opserr << OpenSees::PromptValueError + << "load pattern with tag " << patternTag + << " not found in domain" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } ElementalLoadIter theEleLoads = thePattern->getElementalLoads(); - ElementalLoad *theLoad; char buffer[20]; + ElementalLoad *theLoad; while ((theLoad = theEleLoads()) != nullptr) { sprintf(buffer, "%d ", theLoad->getClassTag()); Tcl_AppendResult(interp, buffer, NULL); } } else { - opserr << G3_ERROR_PROMPT << "want - getEleLoadClassTags \n" << endln; + opserr << OpenSees::PromptValueError << "unexpected arguments\n" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -417,9 +412,12 @@ getEleLoadClassTags(ClientData clientData, Tcl_Interp *interp, int argc, } int -getEleLoadTags(ClientData clientData, Tcl_Interp *interp, int argc, +getEleLoadTags(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { + // + // getEleLoadTags + // assert(clientData != nullptr); Domain *the_domain = (Domain*)clientData; @@ -427,30 +425,31 @@ getEleLoadTags(ClientData clientData, Tcl_Interp *interp, int argc, LoadPattern *thePattern; LoadPatternIter &thePatterns = the_domain->getLoadPatterns(); - char buffer[20]; + Tcl_Obj *result = Tcl_NewListObj(0, nullptr); while ((thePattern = thePatterns()) != nullptr) { ElementalLoadIter theEleLoads = thePattern->getElementalLoads(); ElementalLoad *theLoad; while ((theLoad = theEleLoads()) != nullptr) { - sprintf(buffer, "%d ", theLoad->getElementTag()); - Tcl_AppendResult(interp, buffer, NULL); + Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(theLoad->getElementTag())); } } + Tcl_SetObjResult(interp, result); + } else if (argc == 2) { int patternTag; if (Tcl_GetInt(interp, argv[1], &patternTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "getEleLoadTags -- could not read patternTag \n"; + opserr << OpenSees::PromptValueError << "failed to read patternTag \n"; return TCL_ERROR; } LoadPattern *thePattern = the_domain->getLoadPattern(patternTag); if (thePattern == nullptr) { - opserr << G3_ERROR_PROMPT << "load pattern with tag " << patternTag - << " not found in domain -- getEleLoadTags\n"; + opserr << OpenSees::PromptValueError << "load pattern with tag " << patternTag + << " not found in domain\n"; return TCL_ERROR; } @@ -465,7 +464,7 @@ getEleLoadTags(ClientData clientData, Tcl_Interp *interp, int argc, } } else { - opserr << G3_ERROR_PROMPT << "want - getEleLoadTags \n" << endln; + opserr << OpenSees::PromptValueError << "unexpectd arguments\n" << "\n"; return TCL_ERROR; } @@ -473,9 +472,10 @@ getEleLoadTags(ClientData clientData, Tcl_Interp *interp, int argc, } int -getEleLoadData(ClientData clientData, Tcl_Interp *interp, int argc, +getEleLoadData(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { + // getLoadData assert(clientData != nullptr); Domain *the_domain = (Domain*)clientData; @@ -494,26 +494,26 @@ getEleLoadData(ClientData clientData, Tcl_Interp *interp, int argc, const Vector &eleLoadData = theLoad->getData(typeEL, 1.0); int eleLoadDataSize = eleLoadData.Size(); - opserr << "eleLoadDataSize: " << eleLoadDataSize << "\n"; for (int i = 0; i < eleLoadDataSize; ++i) { sprintf(buffer, "%35.20f ", eleLoadData(i)); Tcl_AppendResult(interp, buffer, NULL); } } } - - } else if (argc == 2) { + } + + else if (argc == 2) { int patternTag; if (Tcl_GetInt(interp, argv[1], &patternTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "getEleLoadData -- could not read patternTag \n"; + opserr << OpenSees::PromptValueError << "failed to read patternTag\n"; return TCL_ERROR; } LoadPattern *thePattern = the_domain->getLoadPattern(patternTag); if (thePattern == nullptr) { - opserr << G3_ERROR_PROMPT << "load pattern with tag " << patternTag - << " not found in domain -- getEleLoadData\n"; + opserr << OpenSees::PromptValueError << "load pattern with tag " << patternTag + << " not found in domain\n"; return TCL_ERROR; } @@ -534,31 +534,10 @@ getEleLoadData(ClientData clientData, Tcl_Interp *interp, int argc, } } else { - opserr << G3_ERROR_PROMPT << "want - getEleLoadTags \n" << endln; + opserr << OpenSees::PromptValueError + << "want - getEleLoadTags " << "\n"; return TCL_ERROR; } return TCL_OK; } - -int -getEleTags(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - // NOTE: Maybe this can use a base class of ElementIter so we only need - // to work in terms of tagged object - assert(clientData != nullptr); - Domain *the_domain = (Domain*)clientData; - - Element *theEle; - ElementIter &eleIter = the_domain->getElements(); - - char buffer[20]; - - while ((theEle = eleIter()) != nullptr) { - sprintf(buffer, "%d ", theEle->getTag()); - Tcl_AppendResult(interp, buffer, NULL); - } - - return TCL_OK; -} - diff --git a/SRC/runtime/commands/domain/commands.h b/SRC/runtime/commands/domain/commands.h index 736f117319..ea8953c42e 100644 --- a/SRC/runtime/commands/domain/commands.h +++ b/SRC/runtime/commands/domain/commands.h @@ -1,10 +1,18 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // - // domain/node.cpp Tcl_CmdProc nodeCoord; Tcl_CmdProc nodeDOFs; @@ -15,19 +23,14 @@ Tcl_CmdProc nodeReaction; Tcl_CmdProc nodeUnbalance; Tcl_CmdProc nodeEigenvector; Tcl_CmdProc setNodeCoord; +Tcl_CmdProc nodeRotation; // domain/region.cpp Tcl_CmdProc TclCommand_addMeshRegion; +// domain/recorder.cpp +Tcl_CmdProc OPS_recorderValue; -// domain/element.cpp -Tcl_CmdProc TclCommand_addElementRayleigh; -Tcl_CmdProc TclCommand_getEleTags; -Tcl_CmdProc getNumElements; -Tcl_CmdProc getEleClassTags; -Tcl_CmdProc getEleLoadClassTags; -Tcl_CmdProc getEleLoadTags; -Tcl_CmdProc getEleLoadData; // domain/section.cpp Tcl_CmdProc sectionForce; @@ -39,6 +42,81 @@ Tcl_CmdProc sectionWeight; Tcl_CmdProc sectionTag; Tcl_CmdProc sectionDisplacement; + + +namespace OpenSees { +namespace DomainCommands { + // domain.cpp + Tcl_ObjCmdProc removeObject; + Tcl_ObjCmdProc fixedNodes; + Tcl_ObjCmdProc constrainedNodes; + Tcl_ObjCmdProc fixedDOFs; + Tcl_ObjCmdProc constrainedDOFs; + Tcl_ObjCmdProc domainChange; + Tcl_CmdProc retainedDOFs; + Tcl_CmdProc updateElementDomain; + + // domain/element.cpp + Tcl_CmdProc addElementRayleigh; + Tcl_CmdProc getEleTags; + Tcl_CmdProc getNumElements; + Tcl_CmdProc getEleClassTags; + Tcl_CmdProc eleNodes; + Tcl_CmdProc eleType; + Tcl_CmdProc eleForce; + Tcl_CmdProc localForce; + Tcl_CmdProc eleDynamicalForce; + Tcl_CmdProc eleResponse; + + // modal.cpp + Tcl_CmdProc modalProperties; +} +} + +// parameter.cpp +Tcl_CmdProc getParamTags; +Tcl_CmdProc TclCommand_parameter; +Tcl_CmdProc getParamValue; +Tcl_CmdProc TclCommand_setParameter; + + +// + + +// sensitivity.cpp +Tcl_CmdProc computeGradients; +Tcl_CmdProc sensNodeDisp; +Tcl_CmdProc sensLambda; // Abbas +Tcl_CmdProc sensNodeVel; +Tcl_CmdProc sensNodeAccel; +Tcl_CmdProc sensNodePressure; +Tcl_CmdProc sensSectionForce; +Tcl_CmdProc TclCommand_sensitivityAlgorithm; +// Tcl_CmdProc sensitivityIntegrator; + + +// Tcl_CmdProc startTimer; +// Tcl_CmdProc stopTimer; +Tcl_CmdProc TclCommand_getTime; +Tcl_CmdProc TclCommand_setTime; + +Tcl_CmdProc rayleighDamping; + +Tcl_CmdProc modalDamping; + +Tcl_CmdProc modalDampingQ; + +Tcl_CmdProc basicDeformation; + +Tcl_CmdProc basicForce; + +Tcl_CmdProc basicStiffness; + +// added: Chris McGann, U.Washington for initial state analysis of nDMaterials +Tcl_CmdProc InitialStateAnalysis; + + + Tcl_CmdProc setLoadConst; Tcl_CmdProc setCreep; @@ -60,24 +138,15 @@ Tcl_CmdProc playbackAlgorithmRecorders; Tcl_CmdProc groundExcitation; -Tcl_CmdProc eleForce; - -Tcl_CmdProc localForce; - -Tcl_CmdProc eleDynamicalForce; +Tcl_CmdProc getEleLoadData; +Tcl_CmdProc getEleLoadClassTags; +Tcl_CmdProc getEleLoadTags; -Tcl_CmdProc eleResponse; Tcl_CmdProc findID; -Tcl_CmdProc eleType; - -Tcl_CmdProc eleNodes; - -Tcl_CmdProc getEleTags; - // Tcl_CmdProc nodeBounds; @@ -96,59 +165,4 @@ Tcl_CmdProc nodeResponse; Tcl_CmdProc calculateNodalReactions; Tcl_CmdProc getNodeTags; -Tcl_CmdProc retainedNodes; - -// domain.cpp -Tcl_ObjCmdProc removeObject; -Tcl_ObjCmdProc fixedNodes; -Tcl_ObjCmdProc constrainedNodes; -Tcl_ObjCmdProc fixedDOFs; -Tcl_ObjCmdProc constrainedDOFs; -Tcl_ObjCmdProc domainChange; -Tcl_CmdProc retainedDOFs; -Tcl_CmdProc updateElementDomain; - -// parameter.cpp -Tcl_CmdProc getParamTags; -Tcl_CmdProc TclCommand_parameter; -Tcl_CmdProc getParamValue; - - -// - - -// AddingSensitivity:BEGIN ///////////////////////////////////////////////// -Tcl_CmdProc computeGradients; -Tcl_CmdProc sensNodeDisp; -Tcl_CmdProc sensLambda; // Abbas -Tcl_CmdProc sensNodeVel; -Tcl_CmdProc sensNodeAccel; -Tcl_CmdProc sensNodePressure; -Tcl_CmdProc sensSectionForce; -Tcl_CmdProc sensitivityAlgorithm; -// Tcl_CmdProc sensitivityIntegrator; -// AddingSensitivity:END /////////////////////////////////////////////////// - -// Tcl_CmdProc startTimer; -// Tcl_CmdProc stopTimer; -Tcl_CmdProc TclCommand_getTime; -Tcl_CmdProc TclCommand_setTime; - -Tcl_CmdProc rayleighDamping; - -Tcl_CmdProc modalDamping; - -Tcl_CmdProc modalDampingQ; - -Tcl_CmdProc basicDeformation; - -Tcl_CmdProc basicForce; - -Tcl_CmdProc basicStiffness; - -// added: Chris McGann, U.Washington for initial state analysis of nDMaterials -Tcl_CmdProc InitialStateAnalysis; - -// domain/recorder.cpp -Tcl_CmdProc OPS_recorderValue; - +Tcl_CmdProc retainedNodes; \ No newline at end of file diff --git a/SRC/runtime/commands/domain/database/TclBerkeleyDB.cpp b/SRC/runtime/commands/domain/database/TclBerkeleyDB.cpp deleted file mode 100644 index aeb48fe544..0000000000 --- a/SRC/runtime/commands/domain/database/TclBerkeleyDB.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// OpenSees - Open System for Earthquake Engineering Simulation -// -//===----------------------------------------------------------------------===// -// -// -// Description: This file contains the function invoked when the user invokes -// the MySQL command in the interpreter. -// -// Written: fmk -// -#include -#include -#include -#include - -#include - -#ifdef _USRDLL -#define DllExport _declspec(dllexport) -#else -#define DllExport -#endif - -extern "C" DllExport int -TclCommand_BerkeleyDB(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv, Domain *theDomain, - FEM_ObjectBroker *theBroker, FE_Datastore **theDatabase) -{ - - // delete the old database - if (*theDatabase != 0) - delete (*theDatabase); - - (*theDatabase) = new BerkeleyDbDatastore(argv[2], *theDomain, *theBroker); - - if (*theDatabase == 0) { - opserr << "WARNING database MySql dabaseName? - out of memory\n"; - return TCL_ERROR; - } - - return TCL_OK; -} - diff --git a/SRC/runtime/commands/domain/database/TclDatabaseCommands.cpp b/SRC/runtime/commands/domain/database/TclDatabaseCommands.cpp deleted file mode 100644 index 0ac2048bed..0000000000 --- a/SRC/runtime/commands/domain/database/TclDatabaseCommands.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ -// -// Written: fmk -// Created: 03/00 -// Revision: A -// -// Description: This file contains the function that is invoked -// by the interpreter when the comand 'database' is invoked by the -// user. -// -// What: "@(#) commands.C, revA" - -#include - -#include -#include -#include -#include - -#include -#include - -// known databases -#include - -// linked list of struct for other types of -// databases that can be added dynamically - -#include - -typedef struct databasePackageCommand { - char *funcName; - int (*funcPtr)(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv, Domain *, FEM_ObjectBroker *, - FE_Datastore **); - struct databasePackageCommand *next; -} DatabasePackageCommand; - -// static variables -static DatabasePackageCommand *theDatabasePackageCommands = NULL; -static bool createdDatabaseCommands = false; - -int save(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv); - -int restore(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv); - -extern FE_Datastore *theDatabase; - -int -TclAddDatabase(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv, - Domain &theDomain, FEM_ObjectBroker &theBroker) -{ - if (createdDatabaseCommands == false) { - - // create the commands to commit and reset - Tcl_CreateCommand(interp, "save", save, (ClientData)NULL, - (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateCommand(interp, "restore", restore, (ClientData)NULL, - (Tcl_CmdDeleteProc *)NULL); - - createdDatabaseCommands = true; - } - - // make sure at least one other argument to contain integrator - if (argc < 2) { - opserr << "WARNING need to specify a Database type; valid type File, " - "MySQL, BerkeleyDB \n"; - return TCL_ERROR; - } - - // - // check argv[1] for type of Database, parse in rest of arguments - // needed for the type of Database, create the object and add to Domain - // - - // a File Database - if (strcmp(argv[1], "File") == 0) { - if (argc < 3) { - opserr << "WARNING database File fileName? "; - return TCL_ERROR; - } - - // delete the old database - if (theDatabase != 0) - delete theDatabase; - - theDatabase = new FileDatastore(argv[2], theDomain, theBroker); - // check we instantiated a database .. if not ran out of memory - if (theDatabase == nullptr) { - opserr << "WARNING ran out of memory - database File " << argv[2] - << endln; - return TCL_ERROR; - } - - return TCL_OK; - } else { - - // - // maybe a database package - // - - // try existing loaded packages - - DatabasePackageCommand *dataCommands = theDatabasePackageCommands; - bool found = false; - while (dataCommands != NULL && found == false) { - if (strcmp(argv[1], dataCommands->funcName) == 0) { - int result = (*(dataCommands->funcPtr))( - clientData, interp, argc, argv, &theDomain, &theBroker, &theDatabase); - return result; - } else - dataCommands = dataCommands->next; - } - - // load new package - - void *libHandle; - int (*funcPtr)(ClientData, Tcl_Interp *, int , - TCL_Char ** const argv, Domain *, FEM_ObjectBroker *, - FE_Datastore **); - int databaseNameLength = strlen(argv[1]); - char *tclFuncName = new char[databaseNameLength + 12]; - strcpy(tclFuncName, "TclCommand_"); - strcpy(&tclFuncName[11], argv[1]); - - int res = - getLibraryFunction(argv[1], tclFuncName, &libHandle, (void **)&funcPtr); - - if (res == 0) { - char *databaseName = new char[databaseNameLength + 1]; - strcpy(databaseName, argv[1]); - DatabasePackageCommand *theDataCommand = new DatabasePackageCommand; - theDataCommand->funcPtr = funcPtr; - theDataCommand->funcName = databaseName; - theDataCommand->next = theDatabasePackageCommands; - theDatabasePackageCommands = theDataCommand; - - int result = (*funcPtr)(clientData, interp, argc, argv, &theDomain, - &theBroker, &theDatabase); - return result; - } - } - opserr << "WARNING No database type exists "; - opserr << "for database of type:" << argv[1] << "valid database type File\n"; - - return TCL_ERROR; -} - -int -save(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - - if (theDatabase == nullptr) { - opserr << "WARNING: save - no database has been constructed\n"; - return TCL_OK; - } - - // make sure at least one other argument to contain type of system - if (argc < 2) { - opserr << "WARNING save no commit tag - want save commitTag?"; - return TCL_OK; - } - - // check argv[1] for commitTag - int commitTag; - if (Tcl_GetInt(interp, argv[1], &commitTag) != TCL_OK) { - opserr << "WARNING - save could not read commitTag " << argv[1] << endln; - return TCL_OK; - } - - if (theDatabase->commitState(commitTag) < 0) { - opserr << "WARNING - database failed to commitState \n"; - return TCL_ERROR; - } - - return TCL_OK; -} - -int -restore(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - - if (theDatabase == 0) { - opserr << "WARNING: restore - no database has been constructed\n"; - return TCL_OK; - } - - // make sure at least one other argument to contain type of system - if (argc < 2) { - opserr << "WARNING restore no commit tag - want restore commitTag?"; - return TCL_OK; - } - - // check argv[1] for commitTag - int commitTag; - if (Tcl_GetInt(interp, argv[1], &commitTag) != TCL_OK) { - opserr << "WARNING - restore could not read commitTag " << argv[1] << endln; - return TCL_OK; - } - - if (theDatabase->restoreState(commitTag) < 0) { - opserr << "WARNING - database failed to restoreState \n"; - return TCL_ERROR; - } - - return TCL_OK; -} diff --git a/SRC/runtime/commands/domain/database/TclMySQL.cpp b/SRC/runtime/commands/domain/database/TclMySQL.cpp deleted file mode 100644 index 1dc5c91003..0000000000 --- a/SRC/runtime/commands/domain/database/TclMySQL.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ -// -// Written: fmk -// -// Description: This file contains the function invoked when the user invokes -// the MySQL command in the interpreter. -// -// What: "@(#) TclCommand_MySQL.C, revA" - -#include -#include -#include -#include - -#include - -#ifdef _USRDLL -#define DllExport _declspec(dllexport) -#else -#define DllExport -#endif - -extern "C" DllExport int -TclCommand_MySQL(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv, Domain *theDomain, - FEM_ObjectBroker *theBroker, FE_Datastore **theDatabase) -{ - - if (argc < 3) { - opserr << "WARNING database MySql dabaseName? "; - return TCL_ERROR; - } - - // delete the old database - if (*theDatabase != 0) - delete (*theDatabase); - - if (argc == 3) - (*theDatabase) = new MySqlDatastore(argv[2], *theDomain, *theBroker); - else { - const char *database = argv[2]; - const char *host = NULL; - const char *user = NULL; - const char *passwd = NULL; - const char *socket = NULL; - int port = 0; - int clientFlag = 0; - - int counter = 3; - while (counter < argc) { - if (strcmp(argv[counter], "-host") == 0) { - host = argv[counter + 1]; - counter += 2; - } else if (strcmp(argv[counter], "-user") == 0) { - user = argv[counter + 1]; - counter += 2; - } else if (strcmp(argv[counter], "-passwd") == 0) { - passwd = argv[counter + 1]; - counter += 2; - } else if (strcmp(argv[counter], "-socket") == 0) { - socket = argv[counter + 1]; - counter += 2; - } else if (strcmp(argv[counter], "-port") == 0) { - if (Tcl_GetInt(interp, argv[counter + 1], &port) != TCL_OK) - return TCL_ERROR; - counter += 2; - } else if (strcmp(argv[counter], "-clientFlag") == 0) { - if (Tcl_GetInt(interp, argv[counter + 1], &clientFlag) != TCL_OK) - return TCL_ERROR; - counter += 2; - } else { - counter++; - } - } - (*theDatabase) = - new MySqlDatastore(database, host, user, passwd, port, socket, - clientFlag, *theDomain, *theBroker); - } - - if (*theDatabase == 0) { - opserr << "WARNING database MySql dabaseName? - out of memory\n"; - return TCL_ERROR; - } - - return TCL_OK; -} diff --git a/SRC/runtime/commands/domain/database/database.cpp b/SRC/runtime/commands/domain/database/database.cpp deleted file mode 100644 index f09305980f..0000000000 --- a/SRC/runtime/commands/domain/database/database.cpp +++ /dev/null @@ -1,12 +0,0 @@ - -extern int TclAddDatabase(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv, Domain &theDomain, - FEM_ObjectBroker &theBroker); - -int -addDatabase(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - return TclAddDatabase(clientData, interp, argc, argv, theDomain, theBroker); -} - diff --git a/SRC/runtime/commands/domain/domain.cpp b/SRC/runtime/commands/domain/domain.cpp index 56d8527d9e..17a5724398 100644 --- a/SRC/runtime/commands/domain/domain.cpp +++ b/SRC/runtime/commands/domain/domain.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -18,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -36,6 +45,8 @@ #define MAX_NDF 6 +namespace OpenSees { +namespace DomainCommands { int domainChange(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const *objv) @@ -75,32 +86,7 @@ removeObject(ClientData clientData, Tcl_Interp *interp, int argc, } Element *theEle = the_domain->removeElement(tag); if (theEle != nullptr) { -#if 0 - // we also have to remove any elemental loads from the domain - LoadPatternIter &theLoadPatterns = the_domain->getLoadPatterns(); - LoadPattern *thePattern; - - // go through all load patterns - while ((thePattern = theLoadPatterns()) != 0) { - ElementalLoadIter theEleLoads = thePattern->getElementalLoads(); - ElementalLoad *theLoad; - - // go through all elemental loads in the pattern - while ((theLoad = theEleLoads()) != 0) { - - // remove & destroy elemental from elemental load if there - // note - if last element in load, remove the load and delete it - - /* ***************** - int numLoadsLeft = theLoad->removeElement(tag); - if (numLoadsLeft == 0) { - thePattern->removeElementalLoad(theLoad->getTag()); - delete theLoad; - } - *********************/ - } - } -#endif + // finally invoke the destructor on the element delete theEle; } @@ -123,25 +109,7 @@ removeObject(ClientData clientData, Tcl_Interp *interp, int argc, delete thePattern; } } -#if 0 - else if ((strcmp(remove_type, "TimeSeries") == 0) || - (strcmp(remove_type, "timeSeries") == 0)) { - if (argc < 3) { - opserr << "WARNING want - remove loadPattern patternTag?\n"; - return TCL_ERROR; - } - if (Tcl_GetIntFromObj(interp, objv[2], &tag) != TCL_OK) { - opserr << "WARNING remove loadPattern tag? failed to read tag: " - << Tcl_GetString(objv[2]) << "\n"; - return TCL_ERROR; - } - bool ok = OPS_removeTimeSeries(tag); - if (ok == true) - return TCL_OK; - else - return TCL_ERROR; - } -#endif + else if (strcmp(remove_type, "parameter") == 0) { if (argc < 3) { opserr << "WARNING want - remove parameter paramTag?\n"; @@ -184,18 +152,18 @@ removeObject(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(remove_type, "recorder") == 0) { if (argc < 3) { - opserr << G3_ERROR_PROMPT << "want - remove recorder recorderTag?\n"; + opserr << OpenSees::PromptValueError << "want - remove recorder recorderTag?\n"; return TCL_ERROR; } int tag; if (Tcl_GetIntFromObj(interp, objv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "remove recorder tag? failed to read tag: " << Tcl_GetString(objv[2]) << "\n"; return TCL_ERROR; } if (the_domain->removeRecorder(tag) != 0) { - opserr << G3_ERROR_PROMPT << "No recorder found with tag " << tag << "\n"; + opserr << OpenSees::PromptValueError << "No recorder found with tag " << tag << "\n"; return TCL_ERROR; } return TCL_OK; @@ -204,9 +172,46 @@ removeObject(ClientData clientData, Tcl_Interp *interp, int argc, else if ((strcmp(remove_type, "SPconstraint") == 0) || (strcmp(remove_type, "sp") == 0)) { - return TCL_ERROR; - // + if (argc < 3) { + opserr << "WARNING want - remove SPconstraint spTag? -or- remove SPconstraint nodeTag? dofTag? \n"; + return TCL_ERROR; + } + if (argc == 3) { + if (Tcl_GetIntFromObj(interp, objv[2], &tag) != TCL_OK) { + opserr << "WARNING remove sp tag? failed to read tag: " << objv[2] << "\n"; + return TCL_ERROR; + } + + SP_Constraint *theSPconstraint = the_domain->removeSP_Constraint(tag); + if (theSPconstraint != nullptr) + delete theSPconstraint; + + } else { + int nodeTag, dofTag; + int patternTag = -1; + + if (Tcl_GetIntFromObj(interp, objv[2], &nodeTag) != TCL_OK) { + opserr << "WARNING remove sp tag? failed to read node tag: " << objv[2] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetIntFromObj(interp, objv[3], &dofTag) != TCL_OK) { + opserr << "WARNING remove sp tag? failed to read dof tag: " << objv[3] << "\n"; + return TCL_ERROR; + } + + if (argc == 5) { + if (Tcl_GetIntFromObj(interp, objv[4], &patternTag) != TCL_OK) { + opserr << "WARNING remove sp tag? failed to read pattern tag: " << objv[4] << "\n"; + return TCL_ERROR; + } + } + dofTag--; // one for C++ indexing of dof + + the_domain->removeSP_Constraint(nodeTag, dofTag, patternTag); + return TCL_OK; + } + // // const char** const args = new const char*[argc+1]; // args[0] = objv[1]; @@ -260,45 +265,6 @@ removeObject(ClientData clientData, Tcl_Interp *interp, int argc, } } -#ifdef _RELIABILITY - // AddingSensitivity:BEGIN /////////////////////////////////////// - else if (strcmp(Tcl_GetString(objv[1]), "randomVariable") == 0) { - int rvTag; - if (Tcl_GetIntFromObj(interp, objv[2], &rvTag) != TCL_OK) { - opserr << "WARNING invalid input: rvTag \n"; - return TCL_ERROR; - } - ReliabilityDomain *theReliabilityDomain = - theReliabilityBuilder->getReliabilityDomain(); - theReliabilityDomain->removeRandomVariable(rvTag); - } else if (strcmp(Tcl_GetString(objv[1]), "performanceFunction") == 0) { - int lsfTag; - if (Tcl_GetIntFromObj(interp, objv[2], &lsfTag) != TCL_OK) { - opserr << "WARNING invalid input: lsfTag \n"; - return TCL_ERROR; - } - ReliabilityDomain *theReliabilityDomain = - theReliabilityBuilder->getReliabilityDomain(); - theReliabilityDomain->removeLimitStateFunction(lsfTag); - } else if (strcmp(Tcl_GetString(objv[1]), "cutset") == 0) { - int cutTag; - if (Tcl_GetIntFromObj(interp, objv[2], &cutTag) != TCL_OK) { - opserr << "WARNING invalid input: cutTag \n"; - return TCL_ERROR; - } - ReliabilityDomain *theReliabilityDomain = - theReliabilityBuilder->getReliabilityDomain(); - theReliabilityDomain->removeCutset(cutTag); - } else if (strcmp(Tcl_GetString(objv[1]), "sensitivityAlgorithm") == 0) { - if (theSensitivityAlgorithm != 0) { - // the_static_analysis->setSensitivityAlgorithm(0); - theSensitivityAlgorithm = 0; - theSensitivityIntegrator = 0; - } - } -// AddingSensitivity:END /////////////////////////////////////// -#endif - else opserr << "WARNING remove " << Tcl_GetString(objv[1]) << " not supported" << "\n"; @@ -359,7 +325,7 @@ fixedDOFs(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Obj *const *o Node *node = theDomain->getNode(fNode); if (node == nullptr) { - opserr << G3_ERROR_PROMPT << " fixedDOFs fNode? - could not find node with tag " << fNode << "\n"; + opserr << OpenSees::PromptValueError << " fixedDOFs fNode? - could not find node with tag " << fNode << "\n"; return TCL_ERROR; } @@ -504,18 +470,20 @@ int retainedDOFs(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { + // + // retainedDOFs rNode? + // assert(clientData != nullptr); Domain *domain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - retainedDOFs rNode? \n"; + opserr << OpenSees::PromptValueError << "want - retainedDOFs rNode? \n"; return TCL_ERROR; } int rNode; if (Tcl_GetInt(interp, argv[1], &rNode) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "retainedDOFs rNode? - could not read " - "rNode? \n"; + opserr << OpenSees::PromptValueError << "could not read rNode? \n"; return TCL_ERROR; } @@ -523,8 +491,7 @@ retainedDOFs(ClientData clientData, Tcl_Interp *interp, int argc, bool allNodes = 1; if (argc > 2) { if (Tcl_GetInt(interp, argv[2], &cNode) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "retainedDOFs rNode? - could not read " - "cNode? \n"; + opserr << OpenSees::PromptValueError << "could not read cNode? \n"; return TCL_ERROR; } allNodes = 0; @@ -534,8 +501,8 @@ retainedDOFs(ClientData clientData, Tcl_Interp *interp, int argc, bool allDOFs = 1; if (argc > 3) { if (Tcl_GetInt(interp, argv[3], &cDOF) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "retainedDOFs rNode? - could not read " - "cDOF? \n"; + opserr << OpenSees::PromptValueError + << "could not read cDOF? \n"; return TCL_ERROR; } cDOF--; @@ -595,4 +562,5 @@ updateElementDomain(ClientData clientData, Tcl_Interp *interp, int argc, return 0; } - +} +} diff --git a/SRC/runtime/commands/domain/element.cpp b/SRC/runtime/commands/domain/element.cpp index 59dc1cc431..6cf6661b3a 100644 --- a/SRC/runtime/commands/domain/element.cpp +++ b/SRC/runtime/commands/domain/element.cpp @@ -1,9 +1,17 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// // #include #include @@ -11,23 +19,30 @@ #include #include #include -#include +#include + +namespace OpenSees { +namespace DomainCommands { int -TclCommand_getEleTags(ClientData clientData, Tcl_Interp *interp, int argc, +getEleTags(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { + // NOTE: Maybe this can use a base class of ElementIter so we only need + // to work in terms of tagged object + assert(clientData != nullptr); Domain *the_domain = (Domain*)clientData; ElementIter &elemIter = the_domain->getElements(); + Tcl_Obj* result = Tcl_NewListObj(the_domain->getNumElements(), nullptr); + Element *elem; - char buffer[128]; - while ((elem = elemIter()) != nullptr) { - sprintf(buffer, "%d ", elem->getTag()); - Tcl_AppendResult(interp, buffer, NULL); - } + while ((elem = elemIter()) != nullptr) + Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(elem->getTag())); + + Tcl_SetObjResult(interp, result); return TCL_OK; } @@ -44,9 +59,8 @@ getNumElements(ClientData clientData, Tcl_Interp *interp, int argc, } - int -TclCommand_addElementRayleigh(ClientData clientData, Tcl_Interp *interp, +addElementRayleigh(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { @@ -72,25 +86,25 @@ TclCommand_addElementRayleigh(ClientData clientData, Tcl_Interp *interp, double alphaM, betaK, betaKinit, betaKcomm; if (Tcl_GetDouble(interp, argv[2], &alphaM) != TCL_OK) { - opserr << "WARNING : setElementRayleighFactors invalid "; + opserr << "WARNING : invalid "; opserr << "alphaM: " << argv[2] << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[3], &betaK) != TCL_OK) { - opserr << "WARNING : setElementRayleighFactors invalid "; + opserr << "WARNING : invalid "; opserr << "betaK: " << argv[3] << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &betaKinit) != TCL_OK) { - opserr << "WARNING : setElementRayleighFactors invalid "; + opserr << "WARNING : invalid "; opserr << "betaKinit: " << argv[4] << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &betaKcomm) != TCL_OK) { - opserr << "WARNING : setElementRayleighFactors invalid "; + opserr << "WARNING : invalid "; opserr << "betaKcomm: " << argv[5] << "\n"; return TCL_ERROR; } @@ -98,11 +112,11 @@ TclCommand_addElementRayleigh(ClientData clientData, Tcl_Interp *interp, Element *elePtr = theTclDomain->getElement(eleTag); if (elePtr == nullptr) - opserr << "WARNING : setElementRayleighFactors invalid eleTag: " << eleTag + opserr << "WARNING : invalid eleTag: " << eleTag << " the element does not exist in the domain \n"; if (elePtr->setRayleighDampingFactors(alphaM, betaK, betaKinit, betaKcomm) != 0) { - opserr << "ERROR : setElementRayleighFactors: FAILED to add damping " + opserr << "ERROR :: Failed to add damping " "factors for element " << eleTag << "\n"; } @@ -110,55 +124,6 @@ TclCommand_addElementRayleigh(ClientData clientData, Tcl_Interp *interp, return TCL_OK; } -#if 0 -int -setElementRayleighDampingFactors(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) -{ - assert(clientData != nullptr); - Domain *the_domain = (Domain*)clientData; - - if (argc < 6) { - opserr << G3_ERROR_PROMPT << "setElementRayleighDampingFactors eleTag? alphaM? betaK? " - "betaK0? betaKc? - not enough arguments to command\n"; - return TCL_ERROR; - } - - int eleTag; - double alphaM, betaK, betaK0, betaKc; - - if (Tcl_GetInt(interp, argv[1], &eleTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rayleigh alphaM? betaK? betaK0? betaKc? - could not " - "read eleTag? \n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[2], &alphaM) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rayleigh alphaM? betaK? betaK0? betaKc? - could not " - "read alphaM? \n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[3], &betaK) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rayleigh alphaM? betaK? betaK0? betaKc? - could not " - "read betaK? \n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[4], &betaK0) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rayleigh alphaM? betaK? betaK0? betaKc? - could not " - "read betaK0? \n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[5], &betaKc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rayleigh alphaM? betaK? betaK0? betaKc? - could not " - "read betaKc? \n"; - return TCL_ERROR; - } - - Element *theEle = the_domain->getElement(eleTag); - theEle->setRayleighDampingFactors(alphaM, betaK, betaK0, betaKc); - return TCL_OK; -} -#endif int eleForce(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char** const argv) @@ -167,7 +132,7 @@ eleForce(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char** const a Domain *domain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - eleForce eleTag? \n"; + opserr << OpenSees::PromptValueError << "want - eleForce eleTag? \n"; return TCL_ERROR; } @@ -175,27 +140,19 @@ eleForce(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char** const a int dof = -1; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "eleForce eleTag? dof? - could not read nodeTag? \n"; + opserr << OpenSees::PromptValueError << "eleForce eleTag? dof? - could not read nodeTag? \n"; return TCL_ERROR; } if (argc > 2) { if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "eleForce eleTag? dof? - could not read dof? \n"; + opserr << OpenSees::PromptValueError << "eleForce eleTag? dof? - could not read dof? \n"; return TCL_ERROR; } } dof--; -#if 0 - Element *theEle = the_domain->getElement(tag); - if (theEle == 0) - return TCL_ERROR; - - const Vector &force = theEle->getResistingForce(); -#endif - const char *myArgv[1]; char myArgv0[8]; strcpy(myArgv0, "forces"); @@ -213,14 +170,17 @@ eleForce(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char** const a Tcl_SetObjResult(interp, Tcl_NewDoubleObj((*force)(dof))); } else { - char buffer[128]; - for (int i = 0; i < size; ++i) { - sprintf(buffer, "%35.20f", (*force)(i)); - Tcl_AppendResult(interp, buffer, NULL); - } + Tcl_Obj* result = Tcl_NewListObj(size, nullptr); + for (int i = 0; i < size; ++i) + Tcl_ListObjAppendElement(interp, result, Tcl_NewDoubleObj((*force)(i))); + + Tcl_SetObjResult(interp, result); } + } else { - opserr << G3_ERROR_PROMPT << "- failed to retrieve element force.\n"; + opserr << OpenSees::PromptValueError + << "- failed to retrieve element force." + << OpenSees::SignalMessageEnd; return TCL_ERROR; } return TCL_OK; @@ -233,7 +193,8 @@ localForce(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char** const Domain *theDomain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - localForce eleTag? \n"; + opserr << OpenSees::PromptValueError + << "want - localForce eleTag? \n"; return TCL_ERROR; } @@ -241,13 +202,15 @@ localForce(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char** const int dof = -1; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "localForce eleTag? dof? - could not read eleTag? \n"; + opserr << OpenSees::PromptValueError + << "localForce eleTag? dof? - could not read eleTag? \n"; return TCL_ERROR; } if (argc > 2) { if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "localForce eleTag? dof? - could not read dof? \n"; + opserr << OpenSees::PromptValueError + << "localForce eleTag? dof? - could not read dof? \n"; return TCL_ERROR; } } @@ -292,7 +255,7 @@ eleDynamicalForce(ClientData clientData, Tcl_Interp *interp, int argc, Domain *theDomain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - eleForce eleTag? \n"; + opserr << OpenSees::PromptValueError << "want - eleForce eleTag? \n"; return TCL_ERROR; } @@ -300,13 +263,13 @@ eleDynamicalForce(ClientData clientData, Tcl_Interp *interp, int argc, int dof = -1; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "eleForce eleTag? dof? - could not read nodeTag? \n"; + opserr << OpenSees::PromptValueError << "eleForce eleTag? dof? - could not read nodeTag? \n"; return TCL_ERROR; } if (argc > 2) { if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "eleForce eleTag? dof? - could not read dof? \n"; + opserr << OpenSees::PromptValueError << "eleForce eleTag? dof? - could not read dof? \n"; return TCL_ERROR; } } @@ -345,14 +308,13 @@ eleResponse(ClientData clientData, Tcl_Interp *interp, int argc, Domain* the_domain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - eleResponse eleTag? eleArgs...\n"; + opserr << OpenSees::PromptValueError << "want - eleResponse tag? eleArgs...\n"; return TCL_ERROR; } int tag; - if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "eleResponse eleTag? args? - could not read eleTag? \n"; + opserr << OpenSees::PromptValueError << "eleResponse tag? args? - could not read tag? \n"; return TCL_ERROR; } @@ -376,14 +338,14 @@ eleNodes(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const Domain *the_domain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - eleNodes eleTag?\n"; + opserr << OpenSees::PromptValueError << "want - eleNodes eleTag?\n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "eleNodes eleTag? \n"; + opserr << OpenSees::PromptValueError << "eleNodes eleTag? \n"; return TCL_ERROR; } @@ -391,7 +353,7 @@ eleNodes(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "eleNodes ele " << tag << " not found" << "\n"; + opserr << OpenSees::PromptValueError << "eleNodes ele " << tag << " not found" << "\n"; return TCL_ERROR; } int numTags = theElement->getNumExternalNodes(); @@ -411,20 +373,20 @@ eleType(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const a Domain *the_domain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - eleType eleTag?\n"; + opserr << OpenSees::PromptValueError << "want - eleType eleTag?\n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "eleType eleTag? \n"; + opserr << OpenSees::PromptValueError << "eleType eleTag? \n"; return TCL_ERROR; } Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "eleType ele " << tag << " not found" << "\n"; + opserr << OpenSees::PromptValueError << "eleType ele " << tag << " not found" << "\n"; return TCL_ERROR; } const char *type = theElement->getClassType(); @@ -434,3 +396,48 @@ eleType(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const a return TCL_OK; } + +int +getEleClassTags(ClientData clientData, Tcl_Interp *interp, int argc, + TCL_Char ** const argv) +{ + assert(clientData != nullptr); + Domain *the_domain = (Domain*)clientData; + + if (argc == 1) { + Element *theEle; + ElementIter &eleIter = the_domain->getElements(); + + char buffer[20]; + + while ((theEle = eleIter()) != nullptr) { + sprintf(buffer, "%d ", theEle->getClassTag()); + Tcl_AppendResult(interp, buffer, NULL); + } + + } else if (argc == 2) { + int eleTag; + + if (Tcl_GetInt(interp, argv[1], &eleTag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "getParamValue -- could not read paramTag \n"; + return TCL_ERROR; + } + + Element *theEle = the_domain->getElement(eleTag); + + char buffer[20]; + sprintf(buffer, "%d ", theEle->getClassTag()); + Tcl_AppendResult(interp, buffer, NULL); + + } else { + opserr << OpenSees::PromptValueError + << "want - getEleClassTags \n" << "\n"; + return TCL_ERROR; + } + + return TCL_OK; +} + +} // namespace DomainCommands +} // namespace OpenSees diff --git a/SRC/runtime/commands/domain/loading/TclSeriesIntegratorCommand.cpp b/SRC/runtime/commands/domain/loading/TclSeriesIntegratorCommand.cpp index ca26411179..ac496d0f87 100644 --- a/SRC/runtime/commands/domain/loading/TclSeriesIntegratorCommand.cpp +++ b/SRC/runtime/commands/domain/loading/TclSeriesIntegratorCommand.cpp @@ -1,11 +1,17 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // -// Description: This file contains the function invoked when the user invokes -// the groundMotion command in the interpreter. +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// // // Written: fmk // Created: 11/00 diff --git a/SRC/runtime/commands/domain/loading/drm/TclPatternCommand.cpp b/SRC/runtime/commands/domain/loading/drm/TclPatternCommand.cpp index 8569e9a14f..7b42790979 100644 --- a/SRC/runtime/commands/domain/loading/drm/TclPatternCommand.cpp +++ b/SRC/runtime/commands/domain/loading/drm/TclPatternCommand.cpp @@ -24,7 +24,8 @@ // #include -#include +#include +#include #include #include #include @@ -46,6 +47,7 @@ #include #include + extern SimulationInformation simulationInfo; extern const char *getInterpPWD(Tcl_Interp *interp); // interpreter.cpp @@ -67,7 +69,7 @@ TclPatternCommand(ClientData clientData, Tcl_Interp *interp, int argc, // make sure at least one other argument to contain integrator if (argc < 4) { - opserr << G3_ERROR_PROMPT << "invalid command - want: pattern type "; + opserr << OpenSees::PromptValueError << "invalid command - want: pattern type "; opserr << " {list of load and sp constraints commands}\n"; opserr << " valid types: Plain, UniformExcitation, MultiSupport\n"; @@ -163,7 +165,7 @@ TclPatternCommand(ClientData clientData, Tcl_Interp *interp, int argc, currentArg++; velSeries = TclSeriesCommand(clientData, interp, argv[currentArg]); - if (velSeries == 0) { + if (velSeries == nullptr) { opserr << "WARNING invalid vel series: " << argv[currentArg]; opserr << " pattern UniformExcitation -vel {series}\n"; return TCL_ERROR; diff --git a/SRC/runtime/commands/domain/loading/element_load.cpp b/SRC/runtime/commands/domain/loading/element_load.cpp index 321428cd6e..8382febd92 100644 --- a/SRC/runtime/commands/domain/loading/element_load.cpp +++ b/SRC/runtime/commands/domain/loading/element_load.cpp @@ -1,12 +1,22 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // // #include #include +#include #include #include #include @@ -14,6 +24,7 @@ #include #include +#include #include #include #include @@ -31,22 +42,266 @@ #include #include - int -TclCommand_addElementalLoad(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char **const argv) +TclCommand_addFrameLoad(ClientData clientData, Tcl_Interp *interp, int argc, + TCL_Char **const argv) { BasicModelBuilder *builder = static_cast(clientData); Domain *domain = builder->getDomain(); - static int eleLoadTag = 0; // TODO: this is ugly - // ensure the destructor has not been called + std::vector tags; + std::vector n(1); + std::vector m(1); + std::vector r(1); + int shape, basis=FrameLoad::Reference; + enum class Position : int { + Force, End + }; + ArgumentTracker tracker; + + + LoadPattern *pattern = builder->getEnclosingPattern(); + + // eleLoad FrameForce $shape -n $n -offset $r -pattern $pattern -basis $basis -ele $ele + + if (argc < 3) { + opserr << "WARNING eleLoad FrameLoad $shape -force $n -couple $m -offset r -pattern pattern -basis $basis\n"; + return TCL_ERROR; + } + + if (strcmp(argv[2], "Dirac") == 0) + shape = FrameLoad::Dirac; + else if (strcmp(argv[2], "Heaviside") == 0) + shape = FrameLoad::Heaviside; + else if (strcmp(argv[2], "Lagrange") == 0) { + shape = FrameLoad::Lagrange; + opserr << "Lagrange shape not yet implemented\n"; + return TCL_ERROR; + } + else { + opserr << "WARNING unknown shape for FrameLoad " << argv[2] << "\n"; + return TCL_ERROR; + } + + // Keywords + for (int i=0; igetDomain()->getLoadPattern(ptag); + if (pattern == nullptr) { + opserr << "WARNING pattern " << argv[i+1] << " not found\n"; + return TCL_ERROR; + } + i++; + } + else if (strcmp(argv[i], "-basis") == 0) { + if (i == argc-1) { + opserr << "WARNING -basis paramter missing required argument\n"; + return TCL_ERROR; + } + if (strcmp(argv[i+1], "global") == 0) + basis = FrameLoad::Embedding; + else if ((strcmp(argv[i+1], "reference") == 0) || + (strcmp(argv[i+1], "local") == 0)) + basis = FrameLoad::Reference; + else if (strcmp(argv[i+1], "director") == 0) + basis = FrameLoad::Director; + else { + opserr << "WARNING unknown basis for FrameLoad " << argv[i+1] << "\n"; + return TCL_ERROR; + } + i++; + } + else if (strcmp(argv[i], "-force") == 0) { + if (i == argc-1) { + opserr << "WARNING -force paramter missing required argument\n"; + return TCL_ERROR; + } + int list_argc; + TCL_Char **list_argv; + if (Tcl_SplitList(interp, argv[i+1], &list_argc, &list_argv) != TCL_OK) { + opserr << "WARNING force parameter expected list of floats\n"; + return TCL_ERROR; + } + if (list_argc != 3) { + opserr << "WARNING force parameter expected list of 3 floats\n"; + Tcl_Free((char *) list_argv); + return TCL_ERROR; + } + Vector3D force; + for (int j = 0; j < 3; j++) { + if (Tcl_GetDouble(interp, list_argv[j], &force[j]) != TCL_OK) { + opserr << "WARNING force parameter expected list of 3 floats\n"; + Tcl_Free((char *) list_argv); + return TCL_ERROR; + } + } + // n.push_back(force); + n[0] = force; + Tcl_Free((char *) list_argv); + + tracker.consume(Position::Force); + } + else if (strcmp(argv[i], "-couple") == 0) { + if (i == argc-1) { + opserr << "WARNING -couple paramter missing required argument\n"; + return TCL_ERROR; + } + int list_argc; + TCL_Char **list_argv; + if (Tcl_SplitList(interp, argv[i+1], &list_argc, &list_argv) != TCL_OK) { + opserr << "WARNING couple parameter expected list of floats\n"; + return TCL_ERROR; + } + if (list_argc != 3) { + opserr << "WARNING couple parameter expected list of 3 floats\n"; + Tcl_Free((char *) list_argv); + return TCL_ERROR; + } + Vector3D couple; + for (int j = 0; j < 3; j++) { + if (Tcl_GetDouble(interp, list_argv[j], &couple[j]) != TCL_OK) { + opserr << "WARNING couple parameter expected list of 3 floats\n"; + Tcl_Free((char *) list_argv); + return TCL_ERROR; + } + } + // m.push_back(couple); + m[0] = couple; + Tcl_Free((char *) list_argv); + + tracker.consume(Position::Force); + } + else if (strcmp(argv[i], "-offset") == 0) { + if (i == argc-1) { + opserr << "WARNING -offset paramter missing required argument\n"; + return TCL_ERROR; + } + int list_argc; + TCL_Char **list_argv; + if (Tcl_SplitList(interp, argv[i+1], &list_argc, &list_argv) != TCL_OK) { + opserr << "WARNING offset parameter expected list of floats\n"; + return TCL_ERROR; + } + if (list_argc != 3) { + opserr << "WARNING offset parameter expected list of 3 floats\n"; + Tcl_Free((char *) list_argv); + return TCL_ERROR; + } + Vector3D offset; + for (int j = 0; j < 3; j++) { + if (Tcl_GetDouble(interp, list_argv[j], &offset[j]) != TCL_OK) { + opserr << "WARNING offset parameter expected list of 3 floats\n"; + Tcl_Free((char *) list_argv); + return TCL_ERROR; + } + } + // r.push_back(offset); + r[0] = offset; + Tcl_Free((char *) list_argv); + } + else if (strcmp(argv[i], "-elements") == 0) { + if (i == argc-1) { + opserr << "WARNING -elements paramter missing required argument\n"; + return TCL_ERROR; + } + int list_argc; + TCL_Char **list_argv; + if (Tcl_SplitList(interp, argv[i+1], &list_argc, &list_argv) != TCL_OK) { + opserr << "WARNING elements parameter expected list of integers\n"; + return TCL_ERROR; + } + for (int j = 0; j < list_argc; j++) { + int tag; + if (Tcl_GetInt(interp, list_argv[j], &tag) != TCL_OK) { + opserr << "WARNING elements parameter expected list of integers\n"; + Tcl_Free((char *) list_argv); + return TCL_ERROR; + } + tags.push_back(tag); + } + Tcl_Free((char *) list_argv); + } + } + + // Make sure we got everything we need. + if (tracker.current() != Position::End) { + opserr << OpenSees::PromptParseError + << "missing required arguments: "; + while (tracker.current() != Position::End) { + switch (tracker.current()) { + case Position::Force : + opserr << "force "; + break; + case Position::End: + break; + } + if (tracker.current() == Position::End) + break; + tracker.consume(tracker.current()); + } + opserr << "\n"; + return TCL_ERROR; + } + + if (pattern == nullptr) { + opserr << "WARNING no current load pattern\n"; + return TCL_ERROR; + } + + FrameLoad *load = new FrameLoad(basis, shape, n, m, r, *pattern); + + for (int i : tags) { + Element *elem = domain->getElement(i); + if (elem == nullptr) { + opserr << "WARNING eleLoad - no element with tag " << i << "\n"; + delete load; + return TCL_ERROR; + } + if (load->addElement(*elem) != 0) { + opserr << "WARNING eleLoad - could not add load to element\n"; + delete load; + return TCL_ERROR; + } + } + + if (domain->addElementalLoad(load, pattern->getTag()) == false) { + opserr + << "WARNING eleLoad - could not add load to domain\n "; + delete load; + return TCL_ERROR; + } + + return TCL_OK; +} + - if (builder == 0 || clientData == 0) { - opserr << "WARNING current builder has been destroyed - eleLoad\n"; +int +TclCommand_addElementalLoad(ClientData clientData, Tcl_Interp *interp, int argc_main, + TCL_Char **const argv_main) +{ + if (argc_main < 2) { + opserr << "WARNING eleLoad - expecting eleLoad type\n"; return TCL_ERROR; } + if (strcmp(argv_main[1], "Frame") == 0) { + return TclCommand_addFrameLoad(clientData, interp, argc_main, argv_main); + } + + + BasicModelBuilder *builder = static_cast(clientData); + Domain *domain = builder->getDomain(); + static int eleLoadTag = 0; // TODO: this is ugly + int ndm = builder->getNDM(); bool explicitPatternPassed = false; @@ -54,69 +309,84 @@ TclCommand_addElementalLoad(ClientData clientData, Tcl_Interp *interp, int argc, std::vector element_tags; int loadPatternTag = 0; - // First create an ID containing the ele tags of all elements + // Arguments argv_main will be copied into argv. + // We initialize with two placeholders for "-type" and $typeName. + // Everything else will be appended. + std::vector argv{nullptr, nullptr}; + + int typeIndex = -1; + // Create an ID containing the ele tags of all elements // for which the load applies. int count = 1; - int doneEle = 0; - int typeIndex = -1; - while (doneEle == 0 && count < argc) { + while (count < argc_main) { // Element tags - if (strcmp(argv[count], "-ele") == 0) { + if (strcmp(argv_main[count], "-ele") == 0) { count++; int eleStart = count; int eleEnd = 0; int eleID; - while (count < argc && eleEnd == 0) { - if (Tcl_GetInt(interp, argv[count], &eleID) != TCL_OK) + while (count < argc_main && eleEnd == 0) { + if (Tcl_GetInt(interp, argv_main[count], &eleID) != TCL_OK) eleEnd = count; else count++; } if (eleStart != eleEnd) { for (int i = eleStart; i < eleEnd; ++i) { - Tcl_GetInt(interp, argv[i], &eleID); + Tcl_GetInt(interp, argv_main[i], &eleID); element_tags.push_back(eleID); } } } - else if (strcmp(argv[count], "-range") == 0) { + + else if (strcmp(argv_main[count], "-range") == 0) { count++; int eleStart, eleEnd; - if (Tcl_GetInt(interp, argv[count], &eleStart) != TCL_OK) { - opserr << "WARNING eleLoad -range invalid eleStart " << argv[count] + if (Tcl_GetInt(interp, argv_main[count], &eleStart) != TCL_OK) { + opserr << "WARNING eleLoad -range invalid eleStart " << argv_main[count] << "\n"; return TCL_ERROR; } count++; - if (Tcl_GetInt(interp, argv[count], &eleEnd) != TCL_OK) { - opserr << "WARNING eleLoad -range invalid eleEnd " << argv[count] << "\n"; + if (Tcl_GetInt(interp, argv_main[count], &eleEnd) != TCL_OK) { + opserr << "WARNING eleLoad -range invalid eleEnd " << argv_main[count] << "\n"; return TCL_ERROR; } count++; for (int i = eleStart; i <= eleEnd; ++i) element_tags.push_back(i); + } - } - - else if (strcmp(argv[count], "-pattern") == 0) { - count++; - explicitPatternPassed = true; - if (Tcl_GetInt(interp, argv[count], &loadPatternTag) != TCL_OK) { - opserr << "WARNING eleLoad -range invalid eleStart " << argv[count] - << "\n"; + else if (strcmp(argv_main[count], "-pattern") == 0) { + if (count == argc_main - 1) { + opserr << "WARNING eleLoad -pattern paramter missing required argument\n"; + return TCL_ERROR; + } + int ptag; + if (Tcl_GetInt(interp, argv_main[++count], &ptag) != TCL_OK) { + opserr << "WARNING eleLoad -pattern parameter expected integer\n"; return TCL_ERROR; } + explicitPatternPassed = true; + loadPatternTag = ptag; count++; + } - } - else if (strcmp(argv[count], "-type") == 0) { - typeIndex = count; - doneEle = 1; + else if (strcmp(argv_main[count], "-type") == 0) { + argv[0] = argv_main[count++]; + argv[1] = argv_main[count++]; + if (count >= argc_main) { + opserr << "WARNING eleLoad -type paramter missing required argument\n"; + return TCL_ERROR; + } + typeIndex = 0; - } else - doneEle = 1; + } else { + argv.push_back(argv_main[count++]); + } } + const int argc = static_cast(argv.size()); // If -pattern wasnt given explicitly, see if there is one // activated in the builder @@ -132,20 +402,20 @@ TclCommand_addElementalLoad(ClientData clientData, Tcl_Interp *interp, int argc, } - // - // Create the load - // - if ((typeIndex == -1) && (strcmp(argv[count], "-type") != 0)) { - opserr << "WARNING eleLoad - expecting -type option but got " << argv[count] + if (typeIndex == -1) { + opserr << "WARNING missing required -type option" << "\n"; return TCL_ERROR; } + // + // Create the load + // count = typeIndex+1; -//count++; - if (strcmp(argv[count], "-beamUniform") == 0 || - strcmp(argv[count], "beamUniform") == 0) { + if ((strcmp(argv[count], "-beamUniform") == 0) || + (strcmp(argv[count], "BeamUniform") == 0) || + (strcmp(argv[count], "beamUniform") == 0)) { // // see https://portwooddigital.com/2021/05/05/trapezoidal-beam-loads // @@ -623,24 +893,24 @@ TclCommand_addElementalLoad(ClientData clientData, Tcl_Interp *interp, int argc, else if (argc - count == 4) { if (Tcl_GetDouble(interp, argv[count], &t1) != TCL_OK) { opserr << "WARNING eleLoad - invalid T1 " << argv[count] - << " for -shellThermal\n"; + << OpenSees::SignalMessageEnd; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[count + 1], &locY1) != TCL_OK) { opserr << "WARNING eleLoad - invalid LocY1 " << argv[count + 1] - << " for -shellThermal\n"; + << OpenSees::SignalMessageEnd; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[count + 2], &t2) != TCL_OK) { opserr << "WARNING eleLoad - invalid T2 " << argv[count] - << " for -shellThermal\n"; + << OpenSees::SignalMessageEnd; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[count + 3], &locY2) != TCL_OK) { opserr << "WARNING eleLoad - invalid LocY2 " << argv[count + 1] - << " for -shellThermal\n"; + << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -650,11 +920,8 @@ TclCommand_addElementalLoad(ClientData clientData, Tcl_Interp *interp, int argc, element_tags[i]); // add the load to the domain - if (domain->addElementalLoad(theLoad, loadPatternTag) == - false) { - opserr << "WARNING eleLoad - could not add following load to " - "domain:\n "; - opserr << theLoad; + if (domain->addElementalLoad(theLoad, loadPatternTag) == false) { + opserr << "WARNING eleLoad - could not add load to domain\n "; delete theLoad; return TCL_ERROR; } @@ -723,7 +990,7 @@ TclCommand_addElementalLoad(ClientData clientData, Tcl_Interp *interp, int argc, int NodalTtag; if (Tcl_GetInt(interp, argv[count + i], &NodalTtag) != TCL_OK) { - opserr << "WARNING invalid nodeId: " << argv[1]; + opserr << "WARNING invalid nodeId " << argv[1]; return TCL_ERROR; } @@ -790,9 +1057,8 @@ TclCommand_addElementalLoad(ClientData clientData, Tcl_Interp *interp, int argc, } //end of for loop return 0; } - //------------------------end of using ThermalActionWrapper-------------------------- - //-----------------Adding tcl command for beam thermal action(2D&3D), 2013..[Begin]--------------- + //-----------------Adding tcl command for beam thermal action(2D&3D), 2013..[Begin]--------------- else if (strcmp(argv[count], "-beamThermal") == 0) { count++; //For two dimensional model @@ -889,7 +1155,7 @@ TclCommand_addElementalLoad(ClientData clientData, Tcl_Interp *interp, int argc, eleLoadTag++; } //end of for loop return 0; - } //end of + } // end of //--------------------------end for beam2DThermalAction with time series ---------------------------------------- } else { //(1) 9 temperature points, i.e. 8 layers @@ -1424,6 +1690,7 @@ TclCommand_addElementalLoad(ClientData clientData, Tcl_Interp *interp, int argc, eleLoadTag++; } } + // One twmp change give, uniform temp change in element else if (argc - count == 1) { if (Tcl_GetDouble(interp, argv[count], &temp1) != TCL_OK) { diff --git a/SRC/runtime/commands/domain/loading/groundExcitation.cpp b/SRC/runtime/commands/domain/loading/groundExcitation.cpp deleted file mode 100644 index 8b09138c18..0000000000 --- a/SRC/runtime/commands/domain/loading/groundExcitation.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// OpenSees - Open System for Earthquake Engineering Simulation -// -//===----------------------------------------------------------------------===// -// -// -#if 0 -int -groundExcitation(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - G3_Runtime *rt = G3_getRuntime(interp); - Domain* the_domain = G3_getDomain(rt); - - // make sure at least one other argument to contain integrator - if (argc < 2) { - opserr << "WARNING need to specify the commitTag \n"; - return TCL_ERROR; - } - - if (strcmp(argv[1],"Single") == 0) { - if (argc < 4) { - opserr << "WARNING quake single dof motion\n"; - return TCL_ERROR; - } - - int dof; - if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) - return TCL_ERROR; - - // read in the ground motion - GroundMotion *theMotion; - if (strcmp(argv[3],"ElCentro") == 0) { - double fact = 1.0; - if (argc == 5) { - if (Tcl_GetDouble(interp, argv[4], &fact) != TCL_OK) - return TCL_ERROR; - } - theMotion = new ElCentroGroundMotion(fact); - } else { - opserr << "WARNING quake Single motion - no motion type exists \n"; - return TCL_ERROR; - } - - Load *theLoad = new SingleExcitation(*theMotion, dof, nextTag++); - the_domain->addOtherLoad(theLoad); - return TCL_OK; - } - - else { - opserr << "WARNING No quake type exists \n"; - return TCL_ERROR; - } -} -#endif - diff --git a/SRC/runtime/commands/domain/loading/groundMotion.cpp b/SRC/runtime/commands/domain/loading/groundMotion.cpp index 24db3a1d49..b02332f5d0 100644 --- a/SRC/runtime/commands/domain/loading/groundMotion.cpp +++ b/SRC/runtime/commands/domain/loading/groundMotion.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -18,6 +27,7 @@ #include #include #include +#include extern TimeSeries *TclSeriesCommand(ClientData clientData, Tcl_Interp *interp, TCL_Char * const arg); @@ -27,7 +37,7 @@ extern TimeSeriesIntegrator *TclDispatch_newSeriesIntegrator(ClientData clientDa TCL_Char * const arg); static int -TclCommand_newGroundMotion(G3_Runtime* rt, +TclCommand_newGroundMotion(ClientData, Tcl_Interp*, int argc, TCL_Char ** const argv, MultiSupportPattern *thePattern); @@ -37,7 +47,6 @@ TclCommand_addGroundMotion(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { - G3_Runtime *rt = G3_getRuntime(interp); MultiSupportPattern* pattern = (MultiSupportPattern *)Tcl_GetAssocData(interp,"theTclMultiSupportPattern", NULL); @@ -45,33 +54,33 @@ TclCommand_addGroundMotion(ClientData clientData, Tcl_Interp *interp, opserr << "ERROR no multi-support pattern\n"; return TCL_ERROR; } - return TclCommand_newGroundMotion(rt, argc, argv, pattern); + return TclCommand_newGroundMotion(clientData, interp, argc, argv, pattern); } static int -TclCommand_newGroundMotion(G3_Runtime* rt, int argc, +TclCommand_newGroundMotion(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char ** const argv, MultiSupportPattern *thePattern) { - int gMotionTag; - GroundMotion *theMotion = nullptr; - Tcl_Interp *interp = G3_getInterpreter(rt); + BasicModelBuilder *builder = static_cast(clientData); // make sure at least one other argument to contain integrator if (argc < 4) { - opserr << "WARNING invalid command - want: groundMotion tag type \n"; + opserr << OpenSees::PromptValueError << "invalid command - want: groundMotion tag type \n"; opserr << " valid types: AccelRecord and Interpolated \n"; return TCL_ERROR; } + int gMotionTag; if (Tcl_GetInt(interp, argv[1], &gMotionTag) != TCL_OK) { - opserr << "WARNING invalid tag: groundMotion tag type \n"; + opserr << OpenSees::PromptValueError << "invalid tag: groundMotion tag type \n"; return TCL_ERROR; } int startArg = 2; + GroundMotion *theMotion = nullptr; if ((strcmp(argv[startArg], "Series") == 0) || (strcmp(argv[startArg], "Plain") == 0)) { @@ -89,10 +98,10 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, (strcmp(argv[currentArg], "-acceleration") == 0)) { currentArg++; - accelSeries = TclSeriesCommand((ClientData)0, interp, argv[currentArg]); + accelSeries = TclSeriesCommand(clientData, interp, argv[currentArg]); - if (accelSeries == 0) { - opserr << "WARNING invalid accel series: " << argv[currentArg]; + if (accelSeries == nullptr) { + opserr << OpenSees::PromptValueError << "invalid accel series: " << argv[currentArg]; opserr << " groundMotion tag Series -accel {series}\n"; return TCL_ERROR; } @@ -102,10 +111,10 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, (strcmp(argv[currentArg], "-velocity") == 0)) { currentArg++; - velSeries = TclSeriesCommand((ClientData)0, interp, argv[currentArg]); + velSeries = TclSeriesCommand(clientData, interp, argv[currentArg]); - if (velSeries == 0) { - opserr << "WARNING invalid vel series: " << argv[currentArg]; + if (velSeries == nullptr) { + opserr << OpenSees::PromptValueError << "invalid vel series: " << argv[currentArg]; opserr << " groundMotion tag Series -vel {series}\n"; return TCL_ERROR; } @@ -115,10 +124,10 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, (strcmp(argv[currentArg], "-displacement") == 0)) { currentArg++; - dispSeries = TclSeriesCommand((ClientData)0, interp, argv[currentArg]); + dispSeries = TclSeriesCommand(clientData, interp, argv[currentArg]); - if (dispSeries == 0) { - opserr << "WARNING invalid disp series: " << argv[currentArg]; + if (dispSeries == nullptr) { + opserr << OpenSees::PromptValueError << "invalid disp series: " << argv[currentArg]; opserr << " groundMotion tag Series -disp {series}\n"; return TCL_ERROR; } @@ -130,8 +139,8 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, currentArg++; seriesIntegrator = TclDispatch_newSeriesIntegrator((ClientData)0, interp, argv[currentArg]); - if (seriesIntegrator == 0) { - opserr << "WARNING invalid series integrator: " << argv[currentArg]; + if (seriesIntegrator == nullptr) { + opserr << OpenSees::PromptValueError << "invalid series integrator: " << argv[currentArg]; opserr << " - groundMotion tag Series -int {Series Integrator}\n"; return TCL_ERROR; } @@ -144,7 +153,7 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, currentArg++; if (Tcl_GetDouble(interp, argv[currentArg], &dtInt) != TCL_OK) { - opserr << "WARNING invalid dtInt: " << argv[currentArg]; + opserr << OpenSees::PromptValueError << "invalid dtInt: " << argv[currentArg]; opserr << " - groundMotion tag Series -dtInt dt\n"; return TCL_ERROR; } @@ -157,7 +166,7 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, currentArg++; if (Tcl_GetDouble(interp, argv[currentArg], &fact) != TCL_OK) { - opserr << "WARNING invalid factor: " << argv[currentArg]; + opserr << OpenSees::PromptValueError << "invalid factor: " << argv[currentArg]; opserr << " - groundMotion tag Series -fact factor\n"; return TCL_ERROR; } @@ -168,14 +177,6 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, theMotion = new GroundMotion(dispSeries, velSeries, accelSeries, seriesIntegrator, dtInt, fact); - - if (theMotion == 0) { - opserr << "WARNING ran out of memory creating ground motion - pattern " - "UniformExcitation "; - opserr << gMotionTag << endln; - - return TCL_ERROR; - } } else if (strcmp(argv[startArg], "Interpolated") == 0) { @@ -201,7 +202,7 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, GroundMotion *theMotion1 = thePattern->getMotion(motionID); if (theMotion1 == nullptr) { - opserr << "WARNING no groundMotion with tag " << motionID << " :"; + opserr << OpenSees::PromptValueError << "no groundMotion with tag " << motionID << " :"; opserr << " pattern MultiSupport gMotion1? gMotion? .. "; opserr << "-fact fact1? fact2? .. \n"; return TCL_ERROR; @@ -210,7 +211,7 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, theMotions[i - 3] = theMotion1; } } else { - opserr << "WARNING no gMotionTags want :"; + opserr << OpenSees::PromptValueError << "no gMotionTags want :"; opserr << " pattern MultiSupport gMotion1? gMotion? .. "; opserr << "-fact fact1? fact2? .. \n"; return TCL_ERROR; @@ -228,7 +229,7 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, } else { - opserr << "WARNING unknown pattern type " << argv[1]; + opserr << OpenSees::PromptValueError << "unknown pattern type " << argv[1]; opserr << " - want: pattern patternType " << gMotionTag; opserr << " \t valid types: Plain, UniformExcitation \n"; return TCL_ERROR; @@ -237,7 +238,7 @@ TclCommand_newGroundMotion(G3_Runtime* rt, int argc, // now add the load pattern to the modelBuilder if (theMotion != nullptr) { if (thePattern->addMotion(*theMotion, gMotionTag) < 0) { - opserr << "WARNING could not add ground motion with tag " << gMotionTag; + opserr << OpenSees::PromptValueError << "could not add ground motion with tag " << gMotionTag; opserr << " to pattern\n "; delete theMotion; // free the memory, pattern destroys the time series return TCL_ERROR; diff --git a/SRC/runtime/commands/domain/loading/pattern.cpp b/SRC/runtime/commands/domain/loading/pattern.cpp index 1feb9e3a32..405d0ed676 100644 --- a/SRC/runtime/commands/domain/loading/pattern.cpp +++ b/SRC/runtime/commands/domain/loading/pattern.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -26,11 +35,10 @@ #include #include #include -#include #include -#include - +#include +#include #include #include @@ -48,7 +56,7 @@ #endif #ifdef _H5DRM -# include +# include #endif #include //L.Jiang [SIF] @@ -84,7 +92,7 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, // make sure at least one other argument to contain integrator if (argc < 3) { - opserr << G3_ERROR_PROMPT << "invalid command - want: pattern type "; + opserr << OpenSees::PromptValueError << "invalid command - want: pattern type "; opserr << " {list of load and sp constraints commands}\n"; opserr << " valid types: Plain, UniformExcitation, MultiSupport\n"; return TCL_ERROR; @@ -96,13 +104,13 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, int patternID; if (Tcl_GetInt(interp, argv[2], &patternID) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid patternID: " << argv[2] << "\n"; + opserr << OpenSees::PromptValueError << "invalid patternID: " << argv[2] << "\n"; return TCL_ERROR; } if (strcmp(argv[1], "Plain") == 0) { if (argc < 4) { - opserr << G3_ERROR_PROMPT << "Invalid command for Plain pattern.\n"; + opserr << OpenSees::PromptValueError << "Invalid command for Plain pattern.\n"; return TCL_ERROR; } @@ -114,7 +122,7 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, (strcmp(argv[commandEndMarker], "-factor") == 0)) { if (Tcl_GetDouble(interp, argv[++commandEndMarker], &fact) != TCL_OK) { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "invalid factor: " << argv[commandEndMarker] << "\n"; return TCL_ERROR; } @@ -133,8 +141,8 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, theSeries = TclSeriesCommand(clientData, interp, series_arg); if (theSeries == nullptr) { - opserr << G3_ERROR_PROMPT << "problem creating TimeSeries for LoadPattern " - << patternID << endln; + opserr << OpenSees::PromptValueError << "problem creating TimeSeries for LoadPattern " + << patternID << "\n"; // clean up the memory and return an error if (thePattern != nullptr) @@ -150,7 +158,7 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, int dir; if (Tcl_GetInt(interp, argv[3], &dir) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid patternID: pattern type " << argv[2] + opserr << OpenSees::PromptValueError << "invalid patternID: pattern type " << argv[2] << "\n"; return TCL_ERROR; } @@ -254,7 +262,7 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, } if (dispSeries == nullptr && velSeries == nullptr && accelSeries == nullptr) { - opserr << G3_ERROR_PROMPT << "invalid series, expected:\n pattern UniformExcitation"; + opserr << OpenSees::PromptValueError << "invalid series, expected:\n pattern UniformExcitation"; opserr << "-disp {dispSeries} -vel {velSeries} -accel {accelSeries} "; opserr << "-int {Series Integrator}" << "\n"; return TCL_ERROR; @@ -285,7 +293,7 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, if (Tcl_GetDouble(interp, argv[i + 2], &dt) != TCL_OK) { opserr << OpenSees::PromptValueError << "problem reading ground motion " << "time interval - pattern UniformExcitation: " << patternID - << endln; + << "\n"; return TCL_ERROR; } numInputs -= 3; @@ -321,7 +329,7 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, break; default: opserr << OpenSees::PromptValueError << "cannot read direction for excitation \n"; - opserr << "UniformExcitation " << patternID << " dir factor" << endln; + opserr << "UniformExcitation " << patternID << " dir factor" << "\n"; return TCL_ERROR; break; } @@ -339,8 +347,8 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, // Read in the ground motion if (accelFileName == 0) { - opserr << G3_ERROR_PROMPT << "No ground motion data provided\n"; - opserr << "UniformExcitation tag: " << patternID << endln; + opserr << OpenSees::PromptValueError << "No ground motion data provided\n"; + opserr << "UniformExcitation tag: " << patternID << "\n"; return TCL_ERROR; } @@ -716,13 +724,13 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, opserr << "Creating H5DRM tag = " << tag << " filename = " << filename.c_str() << " factor = " << factor - << endln; + << "\n"; thePattern = new H5DRM(tag, filename, factor); opserr << "Done! Creating H5DRM tag = " << tag << " filename = " << filename.c_str() << " factor = " << factor - << endln; + << "\n"; domain->addLoadPattern(thePattern); return TCL_OK; @@ -738,7 +746,8 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, // now add the load pattern to the modelBuilder if (domain->addLoadPattern(thePattern) == false) { - opserr << OpenSees::PromptValueError << "could not add load pattern to the domain " + opserr << OpenSees::PromptValueError + << "could not add load pattern to the domain " << *thePattern; delete thePattern; return TCL_ERROR; @@ -762,7 +771,7 @@ TclCommand_addPattern(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_Eval(interp, "rename nodalLoad load;"); if (Tcl_Eval(interp, argv[commandEndMarker]) != TCL_OK) { // opserr << OpenSees::PromptValueError << "- error reading load pattern information in { }"; - opserr << G3_ERROR_PROMPT << Tcl_GetStringResult(interp); + opserr << OpenSees::PromptValueError << Tcl_GetStringResult(interp); // Tcl_Eval(interp, "puts $errorInfo; flush stdout;"); // Tcl_Exit(TCL_ERROR); return TCL_ERROR; @@ -798,7 +807,6 @@ TclCommand_addNodalLoad(ClientData clientData, Tcl_Interp *interp, int argc, TCL int loadPatternTag = 0; if (true) { - // make sure at least one other argument to contain type if (argc < (2 + ndf)) { opserr << OpenSees::PromptValueError << "bad command - want: load nodeId " << ndf << " forces\n"; return TCL_ERROR; @@ -808,7 +816,6 @@ TclCommand_addNodalLoad(ClientData clientData, Tcl_Interp *interp, int argc, TCL int nodeId; if (Tcl_GetInt(interp, argv[1], &nodeId) != TCL_OK) { opserr << OpenSees::PromptValueError << "invalid nodeId: " << argv[1]; - opserr << " - load nodeId " << ndf << " forces\n"; return TCL_ERROR; } @@ -817,7 +824,8 @@ TclCommand_addNodalLoad(ClientData clientData, Tcl_Interp *interp, int argc, TCL for (int i = 0; i < ndf; ++i) { double theForce; if (Tcl_GetDouble(interp, argv[2 + i], &theForce) != TCL_OK) { - opserr << OpenSees::PromptValueError << "invalid force " << i + 1 << " in load " << nodeId; + opserr << OpenSees::PromptValueError + << "invalid force " << i + 1 << " in load " << nodeId; opserr << ", got " << ndf << " forces\n"; return TCL_ERROR; } else @@ -837,8 +845,9 @@ TclCommand_addNodalLoad(ClientData clientData, Tcl_Interp *interp, int argc, TCL if (endMarker == argc || Tcl_GetInt(interp, argv[endMarker], &loadPatternTag) != TCL_OK) { - opserr << OpenSees::PromptValueError << "invalid patternTag - load " << nodeId << " "; - opserr << ndf << " forces pattern patterntag\n"; + opserr << OpenSees::PromptValueError + << "invalid patternTag " << argv[endMarker] + << "\n"; return TCL_ERROR; } } @@ -848,8 +857,8 @@ TclCommand_addNodalLoad(ClientData clientData, Tcl_Interp *interp, int argc, TCL // get the current pattern tag if no tag given in i/p if (explicitPatternPassed == false) { if (theTclLoadPattern == nullptr) { - opserr << OpenSees::PromptParseError << "no current load pattern - load " << nodeId; - opserr << " " << ndf << " forces\n"; + opserr << OpenSees::PromptParseError + << "no current load pattern\n"; return TCL_ERROR; } else loadPatternTag = theTclLoadPattern->getTag(); diff --git a/SRC/runtime/commands/domain/loading/series.cpp b/SRC/runtime/commands/domain/loading/series.cpp index 018da6dfeb..c98cb25b4d 100644 --- a/SRC/runtime/commands/domain/loading/series.cpp +++ b/SRC/runtime/commands/domain/loading/series.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -16,11 +25,9 @@ #include #include -#include #include #include #include -// #include #include #include @@ -31,19 +38,8 @@ #include #include #include -// #include -// #include - -// extern OPS_Routine OPS_ConstantSeries; -// extern OPS_Routine OPS_LinearSeries; -// extern OPS_Routine OPS_TrigSeries; -// extern OPS_Routine OPS_PulseSeries; -// extern OPS_Routine OPS_PeerMotion; -// extern OPS_Routine OPS_PeerNGAMotion; -// extern OPS_Routine OPS_TriangleSeries; -// extern OPS_Routine OPS_RectangularSeries; extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, Tcl_Interp *interp, int cArg, int mArg, TCL_Char ** const argv, @@ -62,7 +58,7 @@ TclDispatch_newLinearSeries(ClientData clientData, Tcl_Interp* interp, int argc, if (numRemainingArgs == 1 || numRemainingArgs == 3) { if (Tcl_GetInt(interp, argv[0], &tag) != 0) { - opserr << G3_ERROR_PROMPT << "invalid series tag in LinearSeries tag? <-factor " + opserr << OpenSees::PromptValueError << "invalid series tag in LinearSeries tag? <-factor " "factor?>" << "\n"; return nullptr; @@ -73,12 +69,12 @@ TclDispatch_newLinearSeries(ClientData clientData, Tcl_Interp* interp, int argc, if (numRemainingArgs > 1) { const char *argvS = argv[1]; if (argvS == 0) { - opserr << G3_ERROR_PROMPT << "string error in LinearSeries with tag: " << tag + opserr << OpenSees::PromptValueError << "string error in LinearSeries with tag: " << tag << "\n"; return nullptr; } if (Tcl_GetDouble(interp, argv[2], &cFactor) != 0) { - opserr << G3_ERROR_PROMPT << "invalid factor in LinearSeries with tag: " << tag + opserr << OpenSees::PromptValueError << "invalid factor in LinearSeries with tag: " << tag << "\n"; return nullptr; } @@ -117,12 +113,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T endMarker++; } - theSeries = new ConstantSeries(cFactor); - - -// void *theResult = OPS_ConstantSeries(rt, argc, argv); -// if (theResult != nullptr) -// theSeries = (TimeSeries *)theResult; + theSeries = new ConstantSeries(cFactor); } else if (strcmp(argv[0],"Trig") == 0 || @@ -142,7 +133,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T if (argc == 5 || argc == 7 || argc == 9 || argc == 11) { if (Tcl_GetInt(interp, argv[argi++], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid series tag in Trig tag?" << "\n"; + opserr << OpenSees::PromptValueError << "invalid series tag in Trig tag?" << "\n"; return nullptr; } } @@ -199,19 +190,6 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T } -#if 0 - else if ((strcmp(argv[0], "Trig") == 0) || - (strcmp(argv[0], "TrigSeries") == 0) || - (strcmp(argv[0], "Sine") == 0) || - (strcmp(argv[0], "SineSeries") == 0)) { - - void *theResult = OPS_TrigSeries(rt, argc, argv); - if (theResult != nullptr) - theSeries = (TimeSeries *)theResult; - - } -#endif - else if ((strcmp(argv[0], "Linear") == 0) || (strcmp(argv[0], "LinearSeries") == 0)) { @@ -410,38 +388,12 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T theSeries = new RectangularSeries(tStart, tFinish, cFactor); } -#if 0 - else if (strcmp(argv[0], "Rectangular") == 0) { - - void *theResult = OPS_RectangularSeries(rt, argc, argv); - if (theResult != 0) - theSeries = (TimeSeries *)theResult; - - } - else if ((strcmp(argv[0], "Pulse") == 0) || - (strcmp(argv[0], "PulseSeries") == 0)) { - - void *theResult = OPS_PulseSeries(rt, argc, argv); - if (theResult != 0) - theSeries = (TimeSeries *)theResult; - - } - else if ((strcmp(argv[0], "Triangle") == 0) || - (strcmp(argv[0], "TriangleSeries") == 0)) { - - void *theResult = OPS_TriangleSeries(rt, argc, argv); - if (theResult != 0) - theSeries = (TimeSeries *)theResult; - - } -#endif - else if ((strcmp(argv[0], "Series") == 0) || (strcmp(argv[0], "Path") == 0)) { double cFactor = 1.0; if (argc < 3) { - opserr << G3_ERROR_PROMPT << "not enough args - "; + opserr << OpenSees::PromptValueError << "not enough args - "; opserr << " Series -dt timeIncr -values {list of points }\n"; return 0; } @@ -473,7 +425,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T if (endMarker == argc || Tcl_GetDouble(interp, argv[endMarker], &timeIncr) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid dt " << argv[endMarker] << " - "; + opserr << OpenSees::PromptValueError << "invalid dt " << argv[endMarker] << " - "; opserr << " Series -dt dt ... \n"; return 0; } @@ -485,7 +437,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T if (endMarker == argc || Tcl_GetInt(interp, argv[endMarker], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid tag " << argv[endMarker] << " - "; + opserr << OpenSees::PromptValueError << "invalid tag " << argv[endMarker] << " - "; return 0; } } @@ -496,7 +448,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T if (endMarker == argc || Tcl_GetDouble(interp, argv[endMarker], &cFactor) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid cFactor " << argv[endMarker] << " - "; + opserr << OpenSees::PromptValueError << "invalid scale factor " << argv[endMarker] << " - "; opserr << " Series -factor ... \n"; return 0; } @@ -508,7 +460,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T if (endMarker != argc) { fileName = endMarker; // argv[endMarker]; if (stat(argv[endMarker], &fileInfo ) != 0) { - opserr << G3_ERROR_PROMPT << "Cannot open file " + opserr << OpenSees::PromptValueError << "Cannot open file " << argv[endMarker] << "\n"; return nullptr; } @@ -521,7 +473,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T if (endMarker != argc) { filePathName = endMarker; // argv[endMarker]; if (stat(argv[endMarker], &fileInfo ) != 0) { - opserr << G3_ERROR_PROMPT << "Cannot open file " + opserr << OpenSees::PromptValueError << "Cannot open file " << argv[endMarker] << "\n"; return nullptr; } @@ -534,7 +486,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T if (endMarker != argc) { fileTimeName = endMarker; // argv[endMarker]; if (stat(argv[endMarker], &fileInfo ) != 0) { - opserr << G3_ERROR_PROMPT << "Cannot open file " + opserr << OpenSees::PromptValueError << "Cannot open file " << argv[endMarker] << "\n"; return nullptr; } @@ -551,7 +503,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T if (Tcl_SplitList(interp, argv[endMarker], &pathSize, &pathStrings) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem splitting path list " << argv[endMarker] + opserr << OpenSees::PromptValueError << "problem splitting path list " << argv[endMarker] << " - "; opserr << " Series -values {path} ... \n"; return nullptr; @@ -561,7 +513,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T for (int i = 0; i < pathSize; ++i) { double value; if (Tcl_GetDouble(interp, pathStrings[i], &value) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem reading path data value " + opserr << OpenSees::PromptValueError << "problem reading path data value " << pathStrings[i] << " - "; opserr << " Series -values {path} ... \n"; Tcl_Free((char *)pathStrings); @@ -584,7 +536,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T if (Tcl_SplitList(interp, argv[endMarker], &pathSize, &pathStrings) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem spltting time path " << argv[endMarker] + opserr << OpenSees::PromptValueError << "problem spltting time path " << argv[endMarker] << " - "; opserr << " Series -time {times} ... \n"; return 0; @@ -594,7 +546,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T for (int i = 0; i < pathSize; ++i) { double value; if (Tcl_GetDouble(interp, pathStrings[i], &value) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem reading time path value " + opserr << OpenSees::PromptValueError << "problem reading time path value " << pathStrings[i] << " - "; opserr << " Series -values {path} ... \n"; @@ -623,7 +575,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T if (endMarker == argc || Tcl_GetDouble(interp, argv[endMarker], &startTime) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid tStart " << argv[endMarker] << " - "; + opserr << OpenSees::PromptValueError << "invalid tStart " << argv[endMarker] << " - "; opserr << " Series -startTime tStart ... \n"; return 0; } @@ -651,7 +603,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T } else if (dataPath != 0 && dataTime != 0) { if (dataTime->Size() != dataPath->Size()) { - opserr << G3_ERROR_PROMPT << "size of time vector (" << dataTime->Size() + opserr << OpenSees::PromptValueError << "size of time vector (" << dataTime->Size() << ") must be equal to size of values (" << dataPath->Size() << ")\n"; return nullptr; } @@ -661,7 +613,7 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T delete dataTime; } else { - opserr << G3_ERROR_PROMPT << "choice of options for Path Series invalid - valid " + opserr << OpenSees::PromptValueError << "choice of options for Path Series invalid - valid " "options for "; opserr << " Path are\n"; opserr << " \t -fileT fileTimeName -fileP filePathName \n"; @@ -674,200 +626,8 @@ TclDispatch_newTimeSeries(ClientData clientData, Tcl_Interp *interp, int argc, T } -#if 0 - else if ((strcmp(argv[0], "PeerDatabase") == 0) || - (strcmp(argv[0], "PeerMotion") == 0)) { - - void *theResult = OPS_PeerMotion(rt, argc, argv); - if (theResult != 0) - theSeries = (TimeSeries *)theResult; - - PeerMotion *thePeerMotion = (PeerMotion *)theSeries; - - if (argc > 4 && theSeries != 0) { - int argCount = 4; - - while (argCount + 1 < argc) { - if ((strcmp(argv[argCount], "-dT") == 0) || - (strcmp(argv[argCount], "-dt") == 0) || - (strcmp(argv[argCount], "-DT") == 0)) { - const char *variableName = argv[argCount + 1]; - double dT = thePeerMotion->getDt(); - char string[30]; - sprintf(string, "set %s %.18e", variableName, dT); - if (Tcl_Eval(interp, string) != TCL_OK) { - opserr << G3_WARN_PROMPT << Tcl_GetStringResult(interp); - Tcl_Exit(TCL_ERROR); - } - argCount += 2; - } else if ((strcmp(argv[argCount], "-nPts") == 0) || - (strcmp(argv[argCount], "-NPTS") == 0)) { - const char *variableName = argv[argCount + 1]; - int nPts = thePeerMotion->getNPts(); - char string[30]; - sprintf(string, "set %s %d", variableName, nPts); - if (Tcl_Eval(interp, string) != TCL_OK) { - opserr << G3_WARN_PROMPT << Tcl_GetStringResult(interp); - Tcl_Exit(TCL_ERROR); - } - argCount += 2; - } else - argCount++; - } - } - } -#endif - - -#if 0 - else if ((strcmp(argv[0], "PeerNGADatabase") == 0) || - (strcmp(argv[0], "PeerNGAMotion") == 0)) { - - void *theResult = OPS_PeerNGAMotion(rt, argc, argv); - if (theResult != 0) - theSeries = (TimeSeries *)theResult; - - PeerNGAMotion *thePeerMotion = (PeerNGAMotion *)(theSeries); - - if (argc > 3 && theSeries != 0) { - int argCount = 3; - - while (argCount + 1 < argc) { - if ((strcmp(argv[argCount], "-dT") == 0) || - (strcmp(argv[argCount], "-dt") == 0) || - (strcmp(argv[argCount], "-DT") == 0)) { - const char *variableName = argv[argCount + 1]; - double dT = thePeerMotion->getDt(); - char string[30]; - sprintf(string, "set %s %.18e", variableName, dT); - if (Tcl_Eval(interp, string) != TCL_OK) { - opserr << G3_WARN_PROMPT << Tcl_GetStringResult(interp); - Tcl_Exit(TCL_ERROR); - } - argCount += 2; - - } else if ((strcmp(argv[argCount], "-nPts") == 0) || - (strcmp(argv[argCount], "-NPTS") == 0)) { - const char *variableName = argv[argCount + 1]; - int nPts = thePeerMotion->getNPts(); - char string[30]; - sprintf(string, "set %s %d", variableName, nPts); - if (Tcl_Eval(interp, string) != TCL_OK) { - opserr << G3_WARN_PROMPT << Tcl_GetStringResult(interp); - Tcl_Exit(TCL_ERROR); - } - argCount += 2; - } else - argCount++; - } - } - } -#endif - -#ifdef _RELIABILITY - - else if (strcmp(argv[0], "DiscretizedRandomProcess") == 0) { - - double mean, maxStdv; - ModulatingFunction *theModFunc; - - if (Tcl_GetDouble(interp, argv[1], &mean) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid input: random process mean \n"; - return 0; - } - - if (Tcl_GetDouble(interp, argv[2], &maxStdv) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid input: random process max stdv \n"; - return 0; - } - - // Number of modulating functions - int argsBeforeModList = 3; - int numModFuncs = argc - argsBeforeModList; - - // Create an array to hold pointers to modulating functions - ModulatingFunction **theModFUNCS = new ModulatingFunction *[numModFuncs]; - - // For each modulating function, get the tag and ensure it exists - int tagI; - for (int i = 0; i < numModFuncs; ++i) { - if (Tcl_GetInt(interp, argv[i + argsBeforeModList], &tagI) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid modulating function tag. " << "\n"; - return 0; - } - - theModFunc = 0; - theModFunc = theReliabilityDomain->getModulatingFunction(tagI); - - if (theModFunc == 0) { - opserr << G3_ERROR_PROMPT << "modulating function number " - << argv[i + argsBeforeModList] << "does not exist...\n"; - delete[] theModFUNCS; - return 0; - } else { - theModFUNCS[i] = theModFunc; - } - } - - // Parsing was successful, create the random process series object - theSeries = new DiscretizedRandomProcessSeries(0, numModFuncs, theModFUNCS, - mean, maxStdv); - } - - else if (strcmp(argv[0], "SimulatedRandomProcess") == 0) { - - int spectrumTag, numFreqIntervals; - double mean; - - if (Tcl_GetInt(interp, argv[1], &spectrumTag) != TCL_OK) { - opserr << "WARNING invalid input to SimulatedRandomProcess: spectrumTag" - << "\n"; - return 0; - } - - if (Tcl_GetDouble(interp, argv[2], &mean) != TCL_OK) { - opserr << "WARNING invalid input to SimulatedRandomProcess: mean" - << "\n"; - return 0; - } - - if (Tcl_GetInt(interp, argv[3], &numFreqIntervals) != TCL_OK) { - opserr - << "WARNING invalid input to SimulatedRandomProcess: numFreqIntervals" - << "\n"; - return 0; - } - - // Check that the random number generator exists - if (theRandomNumberGenerator == 0) { - opserr << "WARNING: A random number generator must be instantiated " - "before SimulatedRandomProcess." - << "\n"; - return 0; - } - - // Check that the spectrum exists - Spectrum *theSpectrum = 0; - theSpectrum = theReliabilityDomain->getSpectrum(spectrumTag); - if (theSpectrum == 0) { - opserr << "WARNING: Could not find the spectrum for the " - "SimulatedRandomProcess." - << "\n"; - return 0; - } - - // Parsing was successful, create the random process series object - theSeries = new SimulatedRandomProcessSeries( - 0, theRandomNumberGenerator, theSpectrum, numFreqIntervals, mean); - } - -#endif - else { - for (int i = 0; i < argc; ++i) - opserr << argv[i] << ' '; - opserr << "\n"; - // type of load pattern type unknown + // type unknown opserr << "WARNING unknown Series type " << argv[0] << " - "; opserr << " valid types: Linear, Rectangular, Path, Constant, Trig, Sine\n"; return 0; diff --git a/SRC/runtime/commands/domain/nodes.cpp b/SRC/runtime/commands/domain/nodes.cpp index efca072f00..8ecacf2263 100644 --- a/SRC/runtime/commands/domain/nodes.cpp +++ b/SRC/runtime/commands/domain/nodes.cpp @@ -1,9 +1,18 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// // Description: This file implements commands for interacting with nodes // in the domain. // @@ -14,11 +23,14 @@ #include #include #include +// Framework #include #include +#include #include #include #include +#include #include #include #include @@ -33,7 +45,9 @@ static int resDataSize = 0; int -getNodeTags(ClientData clientData, Tcl_Interp *interp, int argc, +getNodeTags(ClientData clientData, + Tcl_Interp *interp, + Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -41,18 +55,19 @@ getNodeTags(ClientData clientData, Tcl_Interp *interp, int argc, NodeIter &nodeIter = the_domain->getNodes(); + Tcl_Obj* result = Tcl_NewListObj(the_domain->getNumNodes(), nullptr); + Node *node; - char buffer[20]; - while ((node = nodeIter()) != nullptr) { - sprintf(buffer, "%d ", node->getTag()); - Tcl_AppendResult(interp, buffer, NULL); - } + while ((node = nodeIter()) != nullptr) + Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(node->getTag())); + + Tcl_SetObjResult(interp, result); return TCL_OK; } int -findID(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +findID(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); Domain *theDomain = (Domain*)clientData; @@ -91,22 +106,27 @@ findID(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const ar } int -setNodeCoord(ClientData clientData, Tcl_Interp *interp, int argc, +setNodeCoord(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { + // + // setNodeCoord nodeTag? dim? value? + // assert(clientData != nullptr); Domain *domain = (Domain*)clientData; - if (argc < 4) { - opserr << "WARNING want - setNodeCoord nodeTag? dim? value?\n"; + opserr << OpenSees::PromptValueError + << "expected setNodeCoord nodeTag? dim? value?" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING setNodeCoord nodeTag? dim? value? - could not read " - "nodeTag? \n"; + opserr << OpenSees::PromptValueError + << "could not read nodeTag" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -114,8 +134,9 @@ setNodeCoord(ClientData clientData, Tcl_Interp *interp, int argc, double value; if (Tcl_GetInt(interp, argv[2], &dim) != TCL_OK) { - opserr - << "WARNING setNodeCoord nodeTag? dim? value? - could not read dim? \n"; + opserr << OpenSees::PromptValueError + << "could not read dim" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[3], &value) != TCL_OK) { @@ -127,78 +148,124 @@ setNodeCoord(ClientData clientData, Tcl_Interp *interp, int argc, Node *theNode = domain->getNode(tag); if (theNode == nullptr) { - // TODO: add error message + opserr << OpenSees::PromptValueError + << "Unable to find node with tag '" << tag << "'" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } // // TODO: Check dimensions + // Vector coords(theNode->getCrds()); coords(dim - 1) = value; theNode->setCrds(coords); + domain->domainChange(); return TCL_OK; } + +template int -nodeDisp(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +nodeResponseTemplate(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); - Domain *domain = (Domain*)clientData; + Domain *domain = static_cast(clientData); if (argc < 2) { - opserr << "WARNING want - nodeDisp nodeTag? \n"; + opserr << OpenSees::PromptValueError + << "Insufficient arguments" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } int tag; - int dof = -1; - if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING nodeDisp nodeTag? dof? - could not read nodeTag? \n"; + opserr << OpenSees::PromptValueError + << "Failed to read nodeTag" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } + int dof = -1; if (argc > 2) { if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << "WARNING nodeDisp nodeTag? dof? - could not read dof? \n"; + opserr << OpenSees::PromptValueError + << "Failed to read dof" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } } dof--; - const Vector *nodalResponse = domain->getNodeResponse(tag, NodeData::Disp); + const Vector *response = domain->getNodeResponse(tag, Response); - if (nodalResponse == nullptr) - // TODO: add error message + if (response == nullptr) { + opserr << OpenSees::PromptValueError + << "Node " << tag << " does not have a response of type " + << argv[1] + << OpenSees::SignalMessageEnd; return TCL_ERROR; + } - int size = nodalResponse->Size(); + Tcl_Size size = response->Size(); if (dof >= 0) { - if (dof >= size) { - opserr << "WARNING nodeDisp nodeTag? dof? - dofTag? too large\n"; + opserr << OpenSees::PromptValueError + << "dofTag too large" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } - Tcl_SetObjResult(interp, Tcl_NewDoubleObj((*nodalResponse)(dof))); + Tcl_SetObjResult(interp, Tcl_NewDoubleObj((*response)(dof))); + } + else { + Tcl_Obj* list = Tcl_NewListObj(size, nullptr); + for (int i = 0; i < size; ++i) + Tcl_ListObjAppendElement(interp, list, Tcl_NewDoubleObj((*response)(i))); - } else { - char buffer[40]; - for (int i = 0; i < size; ++i) { - sprintf(buffer, "%35.20f", (*nodalResponse)(i)); - Tcl_AppendResult(interp, buffer, NULL); - } + Tcl_SetObjResult(interp, list); } return TCL_OK; } +int +nodeDisp(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) +{ + return nodeResponseTemplate(clientData, interp, argc, argv); +} +int +nodeVel(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) +{ + return nodeResponseTemplate(clientData, interp, argc, argv); +} + +int +nodeAccel(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) +{ + return nodeResponseTemplate(clientData, interp, argc, argv); +} + int -nodeMass(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +nodeUnbalance(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) +{ + return nodeResponseTemplate(clientData, interp, argc, argv); +} + +int +nodeReaction(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) +{ + return nodeResponseTemplate(clientData, interp, argc, argv); +} + + +int +nodeMass(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); Domain *the_domain = (Domain*)clientData; @@ -223,12 +290,12 @@ nodeMass(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const Node *theNode = the_domain->getNode(tag); if (theNode == nullptr) { - opserr << "WARNING nodeMass node " << tag << " not found" << endln; + opserr << "WARNING nodeMass node " << tag << " not found" << "\n"; return TCL_ERROR; } int numDOF = theNode->getNumberDOF(); if (dof < 1 || dof > numDOF) { - opserr << "WARNING nodeMass dof " << dof << " not in range" << endln; + opserr << "WARNING nodeMass dof " << dof << " not in range" << "\n"; return TCL_ERROR; } else { const Matrix &mass = theNode->getMass(); @@ -240,7 +307,7 @@ nodeMass(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const } int -nodePressure(ClientData clientData, Tcl_Interp *interp, int argc, +nodePressure(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -265,7 +332,7 @@ nodePressure(ClientData clientData, Tcl_Interp *interp, int argc, } int -nodeBounds(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +nodeBounds(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); Domain *the_domain = (Domain*)clientData; @@ -294,67 +361,9 @@ nodeBounds(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** cons return TCL_OK; } -int -nodeVel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - assert(clientData != nullptr); - Domain *the_domain = (Domain*)clientData; - - if (argc < 2) { - opserr << "WARNING want - nodeVel nodeTag? \n"; - return TCL_ERROR; - } - - int tag; - int dof = -1; - - if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING nodeVel nodeTag? dof? - could not read nodeTag? \n"; - return TCL_ERROR; - } - if (argc > 2) { - if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << "WARNING nodeVel nodeTag? dof? - could not read dof? \n"; - return TCL_ERROR; - } - } - - dof--; - - const Vector *nodalResponse = the_domain->getNodeResponse(tag, NodeData::Vel); - - if (nodalResponse == nullptr) - // TODO: add error message - return TCL_ERROR; - - int size = nodalResponse->Size(); - - if (dof >= 0) { - if (size < dof) - // TODO: add error message - return TCL_ERROR; - - double value = (*nodalResponse)(dof); - - // now we copy the value to the tcl string that is returned - char buffer[40]; - sprintf(buffer, "%35.20f", value); - Tcl_SetResult(interp, buffer, TCL_VOLATILE); - - } else { - - char buffer[40]; - for (int i = 0; i < size; ++i) { - sprintf(buffer, "%35.20f", (*nodalResponse)(i)); - Tcl_AppendResult(interp, buffer, NULL); - } - } - - return TCL_OK; -} int -setNodeVel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +setNodeVel(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); Domain *the_domain = (Domain*)clientData; @@ -378,7 +387,7 @@ setNodeVel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** cons Node *theNode = the_domain->getNode(tag); if (theNode == nullptr) { opserr << "WARNING setNodeVel -- node with tag " << tag << " not found" - << endln; + << "\n"; return TCL_ERROR; } @@ -411,7 +420,7 @@ setNodeVel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** cons } int -setNodeDisp(ClientData clientData, Tcl_Interp *interp, int argc, +setNodeDisp(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -436,7 +445,7 @@ setNodeDisp(ClientData clientData, Tcl_Interp *interp, int argc, Node *theNode = the_domain->getNode(tag); if (theNode == nullptr) { opserr << "WARNING setNodeDisp -- node with tag " << tag << " not found" - << endln; + << "\n"; return TCL_ERROR; } @@ -471,7 +480,7 @@ setNodeDisp(ClientData clientData, Tcl_Interp *interp, int argc, int -setNodeAccel(ClientData clientData, Tcl_Interp *interp, int argc, +setNodeAccel(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -497,7 +506,7 @@ setNodeAccel(ClientData clientData, Tcl_Interp *interp, int argc, Node *theNode = the_domain->getNode(tag); if (theNode == nullptr) { opserr << "WARNING setNodeAccel -- node with tag " << tag << " not found" - << endln; + << "\n"; return TCL_ERROR; } @@ -530,118 +539,45 @@ setNodeAccel(ClientData clientData, Tcl_Interp *interp, int argc, return TCL_OK; } -int -nodeAccel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - assert(clientData != nullptr); - Domain *the_domain = (Domain *)clientData; - - if (argc < 2) { - opserr << "WARNING want - nodeAccel nodeTag? dof?\n"; - return TCL_ERROR; - } - - int tag; - int dof = -1; - - if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING nodeAccel nodeTag? dof? - could not read nodeTag? \n"; - return TCL_ERROR; - } - if (argc > 2) { - if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << "WARNING nodeAccel nodeTag? dof? - could not read dof? \n"; - return TCL_ERROR; - } - } - - dof--; - - const Vector *nodalResponse = the_domain->getNodeResponse(tag, NodeData::Accel); - if (nodalResponse == nullptr) - // TODO: add error message - return TCL_ERROR; - - int size = nodalResponse->Size(); - - if (dof >= 0) { - if (size < dof) - return TCL_ERROR; - - Tcl_SetObjResult(interp, Tcl_NewDoubleObj((*nodalResponse)(dof))); - - } else { - char buffer[40]; - for (int i = 0; i < size; ++i) { - sprintf(buffer, "%35.20f", (*nodalResponse)(i)); - Tcl_AppendResult(interp, buffer, NULL); - } - } - - return TCL_OK; -} int -nodeUnbalance(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) +nodeRotation(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, + TCL_Char ** const argv) { assert(clientData != nullptr); - Domain *domain = (Domain*)clientData; + Domain *the_domain = (Domain*)clientData; if (argc < 2) { - opserr << "WARNING want - nodeUnbalance nodeTag? \n"; + opserr << "WARNING want - nodeRotation tag\n"; return TCL_ERROR; } int tag; - int dof = -1; - if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr - << "WARNING nodeUnbalance nodeTag? dof? - could not read nodeTag? \n"; + opserr << "WARNING could not read nodeTag? \n"; return TCL_ERROR; } - if (argc > 2) { - if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << "WARNING nodeUnbalance nodeTag? dof? - could not read dof? \n"; - return TCL_ERROR; - } - } - - dof--; - - const Vector *nodalResponse = domain->getNodeResponse(tag, NodeData::UnbalancedLoad); - - if (nodalResponse == nullptr) - // TODO: add error message + // TODO: This may need some adjusting for PartitionedDomains and parallel + Node *theNode = the_domain->getNode(tag); + if (theNode == nullptr) return TCL_ERROR; - int size = nodalResponse->Size(); + Versor rotation = theNode->getTrialRotation(); - if (dof >= 0) { + Tcl_Obj* list = Tcl_NewListObj(4, nullptr); + for (int i = 0; i < 3; ++i) + Tcl_ListObjAppendElement(interp, list, Tcl_NewDoubleObj(rotation.vector[i])); + Tcl_ListObjAppendElement(interp, list, Tcl_NewDoubleObj(rotation.scalar)); - if (dof >= size) { - opserr << "WARNING nodeUnbalance nodeTag? dof? - dofTag? too large\n"; - return TCL_ERROR; - } - - Tcl_SetObjResult(interp, Tcl_NewDoubleObj((*nodalResponse)(dof))); - - } else { - char buffer[40]; - for (int i = 0; i < size; ++i) { - sprintf(buffer, "%35.20f", (*nodalResponse)(i)); - Tcl_AppendResult(interp, buffer, NULL); - } - } + Tcl_SetObjResult(interp, list); return TCL_OK; } int -nodeResponse(ClientData clientData, Tcl_Interp *interp, int argc, +nodeResponse(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -655,25 +591,48 @@ nodeResponse(ClientData clientData, Tcl_Interp *interp, int argc, int tag, dof, responseID; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING nodeResponse nodeTag? dof? - could not read nodeTag? \n"; + opserr << "WARNING could not read nodeTag? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << "WARNING nodeResponse nodeTag? dof? - could not read dof? \n"; + opserr << "WARNING could not read dof? \n"; return TCL_ERROR; } + if (Tcl_GetInt(interp, argv[3], &responseID) != TCL_OK) { - opserr << "WARNING nodeResponse nodeTag? dof? responseID? - could not read " - "responseID? \n"; - return TCL_ERROR; + if (strcmp(argv[3], "displacement") == 0) + responseID = (int)NodeData::Disp; + else if (strcmp(argv[3], "velocity") == 0) + responseID = (int)NodeData::Vel; + else if (strcmp(argv[3], "acceleration") == 0) + responseID = (int)NodeData::Accel; + else if (strcmp(argv[3], "resiudal") == 0) + responseID = (int)NodeData::UnbalancedLoad; + else if (strcmp(argv[3], "reactionForce") == 0) + responseID = (int)NodeData::Reaction; + else { + opserr << "WARNING unknown response " << argv[3] << "\n"; + return TCL_ERROR; + } } dof--; - const Vector *nodalResponse = - the_domain->getNodeResponse(tag, (NodeData)responseID); + const Vector *nodalResponse = nullptr; + if (false) { + // This would need some adjusting for PartitionedDomain + Node *theNode = the_domain->getNode(tag); + if (theNode == nullptr) + return TCL_ERROR; + + nodalResponse = theNode->getResponse((NodeData)responseID); + + } else + nodalResponse = + the_domain->getNodeResponse(tag, (NodeData)responseID); - if (nodalResponse == 0 || nodalResponse->Size() < dof || dof < 0) + + if (nodalResponse == nullptr || nodalResponse->Size() < dof || dof < 0) // TODO: add error message return TCL_ERROR; @@ -683,7 +642,7 @@ nodeResponse(ClientData clientData, Tcl_Interp *interp, int argc, } int -nodeEigenvector(ClientData clientData, Tcl_Interp *interp, int argc, +nodeEigenvector(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -757,7 +716,7 @@ nodeEigenvector(ClientData clientData, Tcl_Interp *interp, int argc, } int -calculateNodalReactions(ClientData clientData, Tcl_Interp *interp, int argc, +calculateNodalReactions(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -783,78 +742,22 @@ calculateNodalReactions(ClientData clientData, Tcl_Interp *interp, int argc, return TCL_OK; } -int -nodeReaction(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - assert(clientData != nullptr); - Domain *domain = (Domain*)clientData; - - if (argc < 2) { - opserr << "WARNING want - nodeReaction nodeTag? \n"; - return TCL_ERROR; - } - - int tag; - int dof = -1; - - if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING nodeReaction nodeTag? dof? - could not read nodeTag? \n"; - return TCL_ERROR; - } - - if (argc > 2) { - if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << "WARNING nodeReaction nodeTag? dof? - could not read dof? \n"; - return TCL_ERROR; - } - } - - dof--; - - const Vector *nodalResponse = domain->getNodeResponse(tag, NodeData::Reaction); - - if (nodalResponse == nullptr) - // TODO: add error message - return TCL_ERROR; - - int size = nodalResponse->Size(); - - if (dof >= 0) { - - if (dof >= size) { - opserr << "WARNING nodeReaction nodeTag? dof? - dofTag? too large\n"; - return TCL_ERROR; - } - - Tcl_SetObjResult(interp, Tcl_NewDoubleObj((*nodalResponse)(dof))); - - } else { - char buffer[40]; - for (int i = 0; i < size; ++i) { - sprintf(buffer, "%35.20f", (*nodalResponse)(i)); - Tcl_AppendResult(interp, buffer, NULL); - } - } - - return TCL_OK; -} int -nodeCoord(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +nodeCoord(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); Domain *the_domain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - nodeCoord nodeTag? \n"; + opserr << OpenSees::PromptValueError << "want - nodeCoord nodeTag? \n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "nodeCoord nodeTag? dim? - could not read nodeTag? \n"; + opserr << OpenSees::PromptValueError << "nodeCoord nodeTag? dim? - could not read nodeTag? \n"; return TCL_ERROR; } @@ -871,7 +774,9 @@ nodeCoord(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const strcmp(argv[2], "3") == 0) dim = 2; else { - opserr << G3_ERROR_PROMPT << "" << "nodeCoord nodeTag? dim? - could not read dim? \n"; + opserr << OpenSees::PromptValueError + << "could not read dim" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } } @@ -879,7 +784,9 @@ nodeCoord(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const Node *theNode = the_domain->getNode(tag); if (theNode == nullptr) { - opserr << G3_ERROR_PROMPT << "Unable to retrieve node with tag '" << tag << "'\n"; + opserr << OpenSees::PromptValueError + << "Unable to find node with tag '" << tag << "'" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -904,7 +811,7 @@ nodeCoord(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const } int -retainedNodes(ClientData clientData, Tcl_Interp *interp, int argc, +retainedNodes(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -913,7 +820,7 @@ retainedNodes(ClientData clientData, Tcl_Interp *interp, int argc, int cNode; if (argc > 1) { if (Tcl_GetInt(interp, argv[1], &cNode) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "retainedNodes - could not read cNode? \n"; + opserr << OpenSees::PromptValueError << "retainedNodes - could not read cNode? \n"; return TCL_ERROR; } all = 0; @@ -950,33 +857,39 @@ retainedNodes(ClientData clientData, Tcl_Interp *interp, int argc, int -nodeDOFs(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +nodeDOFs(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); Domain *the_domain = (Domain*)clientData; if (argc != 2) { - opserr << G3_ERROR_PROMPT << "expected - nodeDOFs nodeTag?\n"; + opserr << OpenSees::PromptValueError + << "Missing required arguments" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "nodeDOFs nodeTag?\n"; + opserr << OpenSees::PromptValueError << "nodeDOFs nodeTag?\n"; return TCL_ERROR; } Node *theNode = the_domain->getNode(tag); if (theNode == nullptr) { - opserr << G3_ERROR_PROMPT << "nodeDOFs node " << tag << " not found" << endln; + opserr << OpenSees::PromptValueError + << "node with tag " << tag << " not found" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } int numDOF = theNode->getNumberDOF(); DOF_Group *theDOFgroup = theNode->getDOF_GroupPtr(); if (theDOFgroup == nullptr) { - opserr << G3_ERROR_PROMPT << "nodeDOFs DOF group null" << endln; + opserr << OpenSees::PromptValueError + << "nodeDOFs DOF group null" + << OpenSees::SignalMessageEnd; return -1; } diff --git a/SRC/runtime/commands/domain/parameter.cpp b/SRC/runtime/commands/domain/parameter.cpp index 3f52fc2fc7..bd608b66ba 100644 --- a/SRC/runtime/commands/domain/parameter.cpp +++ b/SRC/runtime/commands/domain/parameter.cpp @@ -1,15 +1,25 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // #include #include +#include +#include #include #include #include -#include #include #include #include @@ -36,19 +46,18 @@ extern ReliabilityDomain *theReliabilityDomain; #endif +// parameter tag int -TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, +TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); - Domain* domain = (Domain*)clientData; + Domain* domain = static_cast(clientData); - // check at least two arguments so don't segemnt fault on strcmp + // ensure at least two arguments if (argc < 2) { opserr << "WARNING need to specify a parameter tag\n"; - opserr << "Want: parameter tag .. see manual for " - "valid parameter types and arguments\n"; return TCL_ERROR; } @@ -59,8 +68,6 @@ TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, } Parameter *theParameter = domain->getParameter(paramTag); - int eleTag = -1; - bool isele = false; // First, check special case of a blank parameter if (argc == 2 && strcmp(argv[0], "parameter") == 0) { @@ -94,8 +101,14 @@ TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, return TCL_OK; } - if (argc >= 6 && strcmp(argv[0], "parameter") == 0 && - strcmp(argv[2], "node") == 0 && strcmp(argv[4], "disp") == 0) { + int eleTag = -1; + bool isele = false; + + + if (argc >= 6 && + strcmp(argv[0], "parameter") == 0 && + strcmp(argv[2], "node") == 0 && + strcmp(argv[4], "disp") == 0) { int nodeTag; if (Tcl_GetInt(interp, argv[3], &nodeTag) != TCL_OK) { @@ -120,55 +133,42 @@ TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, return TCL_OK; } - if (argc >= 5 && strcmp(argv[0], "parameter") == 0 && - strcmp(argv[2], "pattern") == 0 && strcmp(argv[4], "lambda") == 0) { + if (argc >= 5 && + strcmp(argv[0], "parameter") == 0 && + strcmp(argv[2], "pattern") == 0 && + strcmp(argv[4], "lambda") == 0) { int patternTag; if (Tcl_GetInt(interp, argv[3], &patternTag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read pattern tag\n"; return TCL_ERROR; } + LoadPattern *thePattern = domain->getLoadPattern(patternTag); Parameter *newParameter = new LoadFactorParameter(paramTag, thePattern); domain->addParameter(newParameter); - char buffer[40]; - sprintf(buffer, "%d", paramTag); - Tcl_SetResult(interp, buffer, TCL_VOLATILE); + Tcl_SetObjResult(interp, Tcl_NewIntObj(paramTag)); return TCL_OK; } + // // Now handle the parameter according to which command is invoked + // if (strcmp(argv[0], "parameter") == 0 || strcmp(argv[0], "addToParameter") == 0) { - // RandomVariable *theRV = 0; - void *theRV = 0; + void *theRV = nullptr; MovableObject *theObject = nullptr; if (strstr(argv[2], "randomVariable") != 0) { -#ifdef _RELIABILITY - int rvTag; - if (Tcl_GetInt(interp, argv[3], &rvTag) != TCL_OK) { - return TCL_ERROR; - } - - if (theReliabilityDomain == 0) { - opserr << "ERROR parameter " << paramTag - << " -- reliability domain has not been created" << endln; - } - - theRV = theReliabilityDomain->getRandomVariablePtr(rvTag); - if (theRV == 0) { - opserr << "ERROR parameter " << paramTag - << " -- random variable with tag " << rvTag << " not defined" - << endln; - return TCL_ERROR; - } -#endif + // return TCL_ERROR; + // REMOVED } int argStart = (theRV) ? 4 : 2; @@ -212,8 +212,8 @@ TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, theObject = static_cast(domain->getNode(nodeTag)); argStart = (theRV) ? 6 : 4; - - } else if (argc > argStart && strstr(argv[argStart], "loadPattern") != 0) { + } + else if (argc > argStart && strstr(argv[argStart], "loadPattern") != 0) { if (argc < 4) { @@ -241,7 +241,7 @@ TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, return TCL_ERROR; } - /////////////////////////////////// + // Create new parameter if (strcmp(argv[0], "parameter") == 0) { @@ -267,7 +267,7 @@ TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, } else newParameter = new Parameter(paramTag, 0, 0, 0); - if (theRV != 0) { + if (theRV != nullptr) { #ifdef _RELIABILITY RVParameter *newRVParameter = new RVParameter(paramTag, theRV, newParameter); @@ -287,7 +287,7 @@ TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, // Add to an existing parameter else if (strcmp(argv[0], "addToParameter") == 0) { - if (theParameter == 0) { + if (theParameter == nullptr) { opserr << "WARNING addToParameter -- parameter with tag " << paramTag << " not found in domain\n"; return TCL_ERROR; @@ -298,8 +298,13 @@ TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, argc - argStart); else { theObject = static_cast(domain->getElement(eleTag)); + if (theObject == nullptr) { + opserr << OpenSees::PromptValueError << "failed to find element with tag " << eleTag << "\n"; + return TCL_ERROR; + } theParameter->addComponent(theObject, (const char **)&argv[argStart], argc - argStart); + // Sorry, Frank, had to change this -- MHS // theParameter->addComponent(eleTag, (const char **)&argv[argStart], // argc-argStart); @@ -313,7 +318,7 @@ TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(argv[0], "updateParameter") == 0) { // Cannot update a parameter that is not present - if (theParameter == 0) { + if (theParameter == nullptr) { opserr << "WARNING updateParameter -- parameter with tag " << paramTag << " not found in domain\n"; // return TCL_ERROR; @@ -333,7 +338,7 @@ TclCommand_parameter(ClientData clientData, Tcl_Interp *interp, int argc, } int -getParamTags(ClientData clientData, Tcl_Interp *interp, int argc, +getParamTags(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -342,18 +347,20 @@ getParamTags(ClientData clientData, Tcl_Interp *interp, int argc, Parameter *theParam; ParameterIter ¶mIter = the_domain->getParameters(); - char buffer[20]; + Tcl_Obj* result = Tcl_NewListObj(0, nullptr); + + while ((theParam = paramIter()) != nullptr) + Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(theParam->getTag())); - while ((theParam = paramIter()) != nullptr) { - sprintf(buffer, "%d ", theParam->getTag()); - Tcl_AppendResult(interp, buffer, NULL); - } + + Tcl_SetObjResult(interp, result); return TCL_OK; } + int -getParamValue(ClientData clientData, Tcl_Interp *interp, int argc, +getParamValue(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -367,7 +374,7 @@ getParamValue(ClientData clientData, Tcl_Interp *interp, int argc, int paramTag; if (Tcl_GetInt(interp, argv[1], ¶mTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "getParamValue -- could not read paramTag \n"; + opserr << OpenSees::PromptValueError << "getParamValue -- could not read paramTag \n"; return TCL_ERROR; } @@ -383,24 +390,25 @@ getParamValue(ClientData clientData, Tcl_Interp *interp, int argc, int -setParameter(ClientData clientData, Tcl_Interp *interp, int argc, +TclCommand_setParameter(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { Domain *theDomain = (Domain*)clientData; - int argLoc = 1; double newValue = 0.0; ID eleIDs(0, 32); int numEle = 0; int flag = 0; - if (strstr(argv[argLoc], "-val") != 0) { + int argLoc = 1; + if ((strstr(argv[argLoc], "-val") != 0) || + (strcmp(argv[argLoc], "-value") == 0)) { if (Tcl_GetDouble(interp, argv[argLoc + 1], &newValue) != TCL_OK) { - opserr << "WARNING setParameter: invalid parameter value\n"; + opserr << "WARNING invalid parameter value\n"; return TCL_ERROR; } } else { - opserr << "WARNING setParameter: -val not found " << endln; + opserr << "WARNING setParameter: -val not found\n"; return TCL_ERROR; } diff --git a/SRC/runtime/commands/domain/recorder.cpp b/SRC/runtime/commands/domain/recorder.cpp index 3fa09dcc11..bd30261f35 100644 --- a/SRC/runtime/commands/domain/recorder.cpp +++ b/SRC/runtime/commands/domain/recorder.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -23,8 +32,9 @@ #endif #define strcmp strcasecmp + #include -#include +#include #include #include #include @@ -178,29 +188,29 @@ getNodeDataFlag(const char *dataToStore, Domain& theDomain, int* dataIndex) NodeData dataFlag = NodeData::DisplTrial; // 10; if (dataToStore == nullptr) - dataFlag = NodeData::DisplTrial; // 0; + dataFlag = NodeData::DisplTrial; // 0; else if ((strcmp(dataToStore, "disp") == 0)) { - dataFlag = NodeData::DisplTrial; // 0 + dataFlag = NodeData::DisplTrial; // 0 } else if ((strcmp(dataToStore, "vel") == 0)) { - dataFlag = NodeData::VelocTrial; // 1 + dataFlag = NodeData::VelocTrial; // 1 } else if ((strcmp(dataToStore, "accel") == 0)) { - dataFlag = NodeData::AccelTrial; // 2 + dataFlag = NodeData::AccelTrial; // 2 } else if ((strcmp(dataToStore, "incrDisp") == 0)) { - dataFlag = NodeData::IncrDisp; // 3; + dataFlag = NodeData::IncrDisp; // 3; } else if ((strcmp(dataToStore, "incrDeltaDisp") == 0)) { - dataFlag = NodeData::IncrDeltaDisp; // 4; + dataFlag = NodeData::IncrDeltaDisp; // 4; } else if ((strcmp(dataToStore, "unbalance") == 0)) { - dataFlag = NodeData::UnbalancedLoad; // 5 + dataFlag = NodeData::UnbalancedLoad; // 5 } else if ((strcmp(dataToStore, "unbalanceInclInertia") == 0) || - (strcmp(dataToStore, "unbalanceIncInertia") == 0) || - (strcmp(dataToStore, "unbalanceIncludingInertia") == 0)) { + (strcmp(dataToStore, "unbalanceIncInertia") == 0) || + (strcmp(dataToStore, "unbalanceIncludingInertia") == 0)) { dataFlag = NodeData::UnbalanceInclInertia; // 6 } else if ((strcmp(dataToStore, "reaction") == 0)) { - dataFlag = NodeData::Reaction; // 7 + dataFlag = NodeData::Reaction; // 7 } else if (((strcmp(dataToStore, "reactionIncInertia") == 0)) || ((strcmp(dataToStore, "reactionInclInertia") == 0)) || ((strcmp(dataToStore, "reactionIncludingInertia") == 0))) { - dataFlag = NodeData::ReactionInclInertia; // 8; + dataFlag = NodeData::ReactionInclInertia; // 8; } else if (((strcmp(dataToStore, "rayleighForces") == 0)) || ((strcmp(dataToStore, "rayleighDampingForces") == 0))) { dataFlag = NodeData::ReactionInclRayleigh; // 9; @@ -221,8 +231,9 @@ getNodeDataFlag(const char *dataToStore, Domain& theDomain, int* dataIndex) dataFlag = NodeData::EigenVector; // 10 + mode; else dataFlag = NodeData::Empty; // 10; + } - } else if ((strncmp(dataToStore, "sensitivity",11) == 0)) { + else if ((strncmp(dataToStore, "sensitivity",11) == 0)) { int paramTag = atoi(&(dataToStore[11])); Parameter *theParameter = theDomain.getParameter(paramTag); int grad = -1; @@ -233,8 +244,9 @@ getNodeDataFlag(const char *dataToStore, Domain& theDomain, int* dataIndex) dataFlag = NodeData::DisplSensitivity; // 1000 + grad; else dataFlag = NodeData::Empty; // 10; + } - } else if ((strncmp(dataToStore, "velSensitivity",14) == 0)) { + else if ((strncmp(dataToStore, "velSensitivity",14) == 0)) { int paramTag = atoi(&(dataToStore[14])); Parameter *theParameter = theDomain.getParameter(paramTag); int grad = -1; @@ -246,8 +258,9 @@ getNodeDataFlag(const char *dataToStore, Domain& theDomain, int* dataIndex) dataFlag = NodeData::VelocSensitivity; // 2000 + grad; else dataFlag = NodeData::Empty; // 10; + } - } else if ((strncmp(dataToStore, "accSensitivity",14) == 0)) { + else if ((strncmp(dataToStore, "accSensitivity",14) == 0)) { int paramTag = atoi(&(dataToStore[14])); Parameter *theParameter = theDomain.getParameter(paramTag); int grad = -1; @@ -350,7 +363,7 @@ parseOutputOption(OutputOptions *options, Tcl_Interp* interp, int argc, TCL_Char options->filename = argv[loc + 1]; options->eMode = eMode; } else { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "expected file name after flag '" << argv[loc] << "\n"; return -1; } @@ -365,7 +378,9 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv, Domain &theDomain, Recorder **theRecorder) { assert(clientData != nullptr); - Domain* domain = (Domain*)clientData; + Domain* domain = static_cast(clientData); + // BasicModelBuilder *builder = static_cast(clientData); + // Domain* domain = builder->getDomain(); G3_Runtime *rt = G3_getRuntime(interp); (*theRecorder) = nullptr; @@ -388,6 +403,7 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, (strcmp(argv[1], "NormEnvelopeElement") == 0)) { OutputOptions options; + std::vector unused; int numEle = 0; int endEleIDs = 2; @@ -395,13 +411,11 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, double rTolDt = 1e-5; bool echoTime = false; int loc = endEleIDs; - int flags = 0; - int eleData = 0; ID *eleIDs = 0; ID *specificIndices = nullptr; - while (flags == 0 && loc < argc) { + while (loc < argc) { int consumed; if ((consumed = parseOutputOption(&options, interp, argc-loc, &argv[loc])) != 0) { if (consumed > 0) @@ -412,6 +426,10 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(argv[loc], "-rTolDt") == 0) { loc++; + if (loc == argc) { + opserr << OpenSees::PromptValueError << "flag -rTolDt is missing required argument\n"; + return TCL_ERROR; + } if (Tcl_GetDouble(interp, argv[loc], &rTolDt) != TCL_OK) return TCL_ERROR; loc++; @@ -430,7 +448,7 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, return TCL_ERROR; } - // read in a list of ele until end of command or other flag + // read in a list of integer tags until end of command or other flag loc++; int eleTag; eleIDs = new ID(0, 32); @@ -441,19 +459,13 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, } Tcl_ResetResult(interp); - if (loc == argc) { - opserr << "ERROR: No response type specified for element recorder. " - << endln; - delete eleIDs; - return TCL_ERROR; - } - - if (strcmp(argv[loc], "all") == 0) { + if (loc < argc && (strcmp(argv[loc], "all") == 0)) { eleIDs = nullptr; loc++; } + } - } else if ((strcmp(argv[loc], "-eleRange") == 0) || + else if ((strcmp(argv[loc], "-eleRange") == 0) || (strcmp(argv[loc], "-range") == 0)) { // ensure no segmentation fault if user messes up @@ -468,14 +480,14 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, if (Tcl_GetInt(interp, argv[loc + 1], &start) != TCL_OK) { opserr << "WARNING recorder Element -eleRange start? end? - invalid " "start " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[loc + 2], &end) != TCL_OK) { opserr << "WARNING recorder Element -eleRange start? end? - invalid end " - << argv[loc + 2] << endln; + << argv[loc + 2] << "\n"; return TCL_ERROR; } @@ -502,13 +514,13 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, int tag; if (Tcl_GetInt(interp, argv[loc + 1], &tag) != TCL_OK) { opserr << "WARNING recorder Element -region tag? - invalid tag " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } MeshRegion *theRegion = domain->getRegion(tag); if (theRegion == nullptr) { opserr << "WARNING recorder Element -region " << tag - << " - region does not exist" << endln; + << " - region does not exist" << "\n"; return TCL_ERROR; // was TCL_OK } const ID &eleRegion = theRegion->getElements(); @@ -541,62 +553,70 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, loc++; } Tcl_ResetResult(interp); + } - } else if ((strcmp(argv[loc], "-time") == 0) || + else if ((strcmp(argv[loc], "-time") == 0) || (strcmp(argv[loc], "-load") == 0)) { echoTime = true; loc++; } - else if (strcmp(argv[loc], "-dT") == 0) { + else if (strcasecmp(argv[loc], "-dT") == 0) { // allow user to specify time step size for recording loc++; + if (loc == argc) { + opserr << OpenSees::PromptValueError << "flag -dT is missing required argument\n"; + return TCL_ERROR; + } if (Tcl_GetDouble(interp, argv[loc], &dT) != TCL_OK) return TCL_ERROR; loc++; } else { - // TODO: handle the same as Node recorder; see Example1.1.py - // first unknown string then is assumed to start - // element response request starts - eleData = loc; - flags = 1; + unused.push_back(loc); + loc++; } } - if (eleData >= argc) { + if (unused.size() == 0) { opserr << "ERROR: No response type specified for element recorder. " - << endln; + << "\n"; return TCL_ERROR; } - const char **data = new const char *[argc - eleData]; - for (int i = eleData, j = 0; i < argc; i++, j++) - data[j] = argv[i]; + // Forward any unused arguments to the element + const char **data = new const char *[unused.size()]; + for (unsigned i=0; i< unused.size(); i++) + data[i] = argv[unused[i]]; // construct the DataHandler theOutputStream = createOutputStream(options); if (strcmp(argv[1], "Element") == 0) - (*theRecorder) = new ElementRecorder(eleIDs, data, argc - eleData, echoTime, *domain, + (*theRecorder) = new ElementRecorder(eleIDs, data, unused.size(), echoTime, *domain, *theOutputStream, dT, rTolDt, specificIndices); else if (strcmp(argv[1], "EnvelopeElement") == 0) - (*theRecorder) = new EnvelopeElementRecorder(eleIDs, data, argc - eleData, + (*theRecorder) = new EnvelopeElementRecorder(eleIDs, data, unused.size(), *domain, *theOutputStream, dT, rTolDt, echoTime, specificIndices); else if (strcmp(argv[1], "NormElement") == 0) - (*theRecorder) = new NormElementRecorder(eleIDs, data, argc - eleData, + (*theRecorder) = new NormElementRecorder(eleIDs, data, unused.size(), echoTime, *domain, *theOutputStream, dT, rTolDt, specificIndices); else - (*theRecorder) = new NormEnvelopeElementRecorder(eleIDs, data, argc - eleData, + (*theRecorder) = new NormEnvelopeElementRecorder(eleIDs, data, unused.size(), *domain, *theOutputStream, dT, 1e-6, echoTime, specificIndices); + if (*theRecorder != nullptr) { + opsdbg << G3_DEBUG_PROMPT << "Created recorder \n"; + (*theRecorder)->Print(opsdbg, 0); + } + if (eleIDs != nullptr) delete eleIDs; @@ -609,7 +629,9 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, (strcmp(argv[1], "elementDamage") == 0)) { ////////// By Arash Altoontash ///////////////// TCL_Char *filename = nullptr; - +#if 1 + +#else if (argc < 7) { opserr << "WARNING recorder ElementDamage eleID? <-time> " << "<-file filename?> <-section secID1? secID2? ...> <-dof " @@ -701,7 +723,7 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, } DamageModel *dmgPTR; - dmgPTR = OPS_getDamageModel(dmgID); + dmgPTR = builder->getTypedObject(dmgID); if (dmgPTR == NULL) { opserr << "WARNING recorder ElementDamage: specified damage model not " @@ -715,7 +737,7 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, // now construct the recorder (*theRecorder) = new DamageRecorder(eleID, secIDs, dofID, dmgPTR, *domain, echoTime, dT, 1e-6, *theOutput); - +#endif } else if (/* (strcmp(argv[1], "Remove") == 0) || */ @@ -730,7 +752,7 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, "secID1? secID2? ...> -crit crit1? value1?" << " <-crit crit2? value2?> <-time> <-file filename?> <-mass " "mass1? mass2? ...> <-g gAcc gDir? gPat?>?" - << endln; + << "\n"; return TCL_ERROR; } @@ -781,19 +803,18 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, if (Tcl_GetInt(interp, argv[loc + 1], &nodeTag) != TCL_OK) { opserr << "WARNING recorder Collapse -node - invalid node tag " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } Node *theNode = domain->getNode(nodeTag); if (theNode == nullptr) { opserr << "WARNING recorder Collapse -node - invalid node " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } loc += 2; } - // new else if (strcmp(argv[loc], "-file_infill") == 0) { filenameinf = argv[loc + 1]; @@ -803,17 +824,17 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(argv[loc], "-checknodes") == 0) { if (Tcl_GetInt(interp, argv[loc + 1], &nTagbotn) != TCL_OK) { opserr << "WARNING recorder Collapse -node - invalid node tag " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[loc + 2], &nTagmidn) != TCL_OK) { opserr << "WARNING recorder Collapse -node - invalid node tag " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[loc + 3], &nTagtopn) != TCL_OK) { opserr << "WARNING recorder Collapse -node - invalid node tag " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } loc += 4; @@ -823,14 +844,12 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, if (Tcl_GetInt(interp, argv[loc + 1], &globgrav) != TCL_OK) { opserr << "WARNING recorder Collapse -global_gravaxis - invalid " "global axis for gravity " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } loc += 2; } - // end of new - else if ((strcmp(argv[loc], "-slave") == 0) || (strcmp(argv[loc], "-secondary") == 0)) { secondaryFlag = true; @@ -849,7 +868,7 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, } // - // read in a list of ele until end of command or other flag + // read in a list of integer tags until end of command or other flag // loc++; int eleTag; @@ -864,10 +883,10 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_ResetResult(interp); - if (strcmp(argv[loc], "all") == 0) { + if (loc < argc && (strcmp(argv[loc], "all") == 0)) { ElementIter &theEleIter = domain->getElements(); Element *theEle; - while ((theEle = theEleIter()) != 0) + while ((theEle = theEleIter()) != nullptr) eleIDs[numEle++] = theEle->getTag(); loc++; } @@ -890,13 +909,13 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, if (Tcl_GetInt(interp, argv[loc + 1], &start) != TCL_OK) { opserr << "WARNING recorder Element -eleRange start? end? - invalid " "start " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[loc + 2], &end) != TCL_OK) { opserr << "WARNING recorder Element -eleRange start? end? - invalid end " - << argv[loc + 2] << endln; + << argv[loc + 2] << "\n"; return TCL_ERROR; } if (start > end) { @@ -925,13 +944,13 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, int tag; if (Tcl_GetInt(interp, argv[loc + 1], &tag) != TCL_OK) { opserr << "WARNING recorder Element -region tag? - invalid tag " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } MeshRegion *theRegion = domain->getRegion(tag); if (theRegion == 0) { opserr << "WARNING recorder Element -region " << tag - << " - region does not exist" << endln; + << " - region does not exist" << "\n"; return TCL_OK; } const ID &eleRegion = theRegion->getElements(); @@ -955,6 +974,10 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(argv[loc], "-dT") == 0) { // allow user to specify time step size for recording loc++; + if (loc == argc) { + opserr << OpenSees::PromptValueError << "flag -dT is missing required argument\n"; + return TCL_ERROR; + } if (Tcl_GetDouble(interp, argv[loc], &dT) != TCL_OK) return TCL_ERROR; loc++; @@ -994,21 +1017,21 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, if (Tcl_GetDouble(interp, argv[loc], &gAcc) != TCL_OK) { opserr << "WARNING recorder Remove -g gValue? gDir? gPat?... invalid " "gValue "; - opserr << argv[loc] << endln; + opserr << argv[loc] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[loc + 1], &gDir) != TCL_OK) { opserr << "WARNING recorder Remove -g gValue? gDir? gPat?... invalid " "gDir "; - opserr << argv[loc + 1] << endln; + opserr << argv[loc + 1] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[loc + 2], &gPat) != TCL_OK) { opserr << "WARNING recorder Remove -g gValue? gDir? gPat?... invalid " "gPat "; - opserr << argv[loc + 1] << endln; + opserr << argv[loc + 1] << "\n"; return TCL_ERROR; } loc += 3; @@ -1070,14 +1093,14 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, critTag = 7; else { opserr << "Error: RemoveRecorder - Removal Criteria " << argv[loc + 1] - << " not recognized" << endln; + << " not recognized" << "\n"; return TCL_ERROR; } if (critTag != 7) { if (Tcl_GetDouble(interp, argv[loc + 2], &critValue) != TCL_OK) { opserr << "WARNING recorder Remove -crit critTag? critValue?... " "invalid critValue "; - opserr << argv[loc + 1] << endln; + opserr << argv[loc + 1] << "\n"; return TCL_ERROR; } } @@ -1183,12 +1206,15 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(argv[pos], "-time") == 0) { echoTimeFlag = true; pos += 1; - } else if (strcmp(argv[pos], "-dT") == 0) { // allow user to specify time step size for recording pos++; + if (pos == argc) { + opserr << OpenSees::PromptValueError << "flag -dT is missing required argument\n"; + return TCL_ERROR; + } if (Tcl_GetDouble(interp, argv[pos], &dT) != TCL_OK) return TCL_ERROR; pos++; @@ -1248,7 +1274,7 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, if (iNodes.Size() != jNodes.Size()) { opserr << "WARNING recorder Drift - the number of iNodes and jNodes must " "be the same " - << iNodes << " " << jNodes << endln; + << iNodes << " " << jNodes << "\n"; return TCL_ERROR; } @@ -1292,104 +1318,6 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, (*theRecorder) = (Recorder *)OPS_GmshRecorder(rt, argc, argv); } - // else if (strcmp(argv[1],"gmshparallel") == 0 || - // strcmp(argv[1],"GMSHPARALLEL") == 0) { - // OPS_ResetInputNoBuilder(clientData, interp, 2, argc, argv, &theDomain); - // (*theRecorder) = (Recorder*) OPS_GmshRecorderParallel(); - // } - -#if 0 - else if (strcmp(argv[1], "mpco") == 0) { - OPS_ResetInputNoBuilder(clientData, interp, 2, argc, argv, &theDomain); - (*theRecorder) = (Recorder*)OPS_MPCORecorder(rt, argc, argv); - if (theRecorder == 0) { - return TCL_ERROR; - } - } -#endif - -#if 0 - else if (strcmp(argv[1],"GSA") == 0) { - if (argc < 3) { - opserr << argc; - opserr << "WARNING recorder GSA -file filename? -dT deltaT? - not enough arguments\n"; - return TCL_ERROR; - } - TCL_Char *filename = 0; - TCL_Char *title1 =0; - TCL_Char *title2 =0; - TCL_Char *title3 =0; - TCL_Char *jobno =0; - TCL_Char *initials =0; - TCL_Char *spec =0; - TCL_Char *currency =0; - TCL_Char *length =0; - TCL_Char *force =0; - TCL_Char *temp =0; - double dT = 0.0; - int loc = 2; - - while (loc < argc) { - if ((strcmp(argv[loc],"-file") == 0) || - (strcmp(argv[loc],"-file") == 0)) { - filename = argv[loc+1]; - loc += 2; - } else if ((strcmp(argv[loc],"-title1") == 0) || - (strcmp(argv[loc],"-Title1e") == 0)) { - title1 = argv[loc+1]; - loc += 2; - } else if ((strcmp(argv[loc],"-title2") == 0) || - (strcmp(argv[loc],"-Title2e") == 0)) { - title2 = argv[loc+1]; - loc += 2; - } else if ((strcmp(argv[loc],"-title3") == 0) || - (strcmp(argv[loc],"-Title3e") == 0)) { - title3 = argv[loc+1]; - loc += 2; - } else if ((strcmp(argv[loc],"-jobno") == 0) || - (strcmp(argv[loc],"-JobNo") == 0)) { - jobno = argv[loc+1]; - loc += 2; - } else if ((strcmp(argv[loc],"-initials") == 0) || - (strcmp(argv[loc],"-Initials") == 0)) { - initials = argv[loc+1]; - loc += 2; - } else if ((strcmp(argv[loc],"-spec") == 0) || - (strcmp(argv[loc],"-Spec") == 0)) { - spec = argv[loc+1]; - loc += 2; - } else if ((strcmp(argv[loc],"-currency") == 0) || - (strcmp(argv[loc],"-Currency") == 0)) { - currency = argv[loc+1]; - loc += 2; - } else if ((strcmp(argv[loc],"-length") == 0) || - (strcmp(argv[loc],"-Length") == 0)) { - length = argv[loc+1]; - loc += 2; - } else if ((strcmp(argv[loc],"-force") == 0) || - (strcmp(argv[loc],"-Force") == 0)) { - force = argv[loc+1]; - loc += 2; - } else if ((strcmp(argv[loc],"-temp") == 0) || - (strcmp(argv[loc],"-Temp") == 0)) { - temp = argv[loc+1]; - loc += 2; - } - else if (strcmp(argv[loc],"-dT") == 0) { - if (Tcl_GetDouble(interp, argv[loc+1], &dT) != TCL_OK) - return TCL_ERROR; - loc += 2; - } - else - loc++; - } - - GSA_Recorder *theR = new GSA_Recorder(theDomain, filename, title1, title2, - title3, jobno, initials, spec, currency, length, force, temp, dT); - (*theRecorder) = theR; - } -#endif - else { // try existing loaded packages @@ -1413,7 +1341,7 @@ TclCreateRecorder(ClientData clientData, Tcl_Interp *interp, int argc, } if (*theRecorder == nullptr) { - opserr << G3_ERROR_PROMPT << "No recorder exists " + opserr << OpenSees::PromptValueError << "No recorder exists " << "with type '" << argv[1] << "'\n"; return TCL_ERROR; @@ -1430,6 +1358,11 @@ TclAddRecorder(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** Recorder *theRecorder = nullptr; + if (argc > 1 && strcasecmp(argv[1], "flush") == 0) { + domain->flushRecorders(); + return TCL_OK; + } + if (TclCreateRecorder(clientData, interp, argc, argv, *domain, &theRecorder) != TCL_OK) return TCL_ERROR; @@ -1439,7 +1372,7 @@ TclAddRecorder(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** } else if ((domain->addRecorder(*theRecorder)) < 0) { - opserr << G3_ERROR_PROMPT << "Failed to add recorder to domain" << endln; + opserr << OpenSees::PromptValueError << "Failed to add recorder to domain" << "\n"; delete theRecorder; Tcl_SetObjResult(interp, Tcl_NewIntObj(-1)); return TCL_ERROR; @@ -1552,7 +1485,7 @@ createNodeRecorder(ClientData clientData, Tcl_Interp *interp, int argc, OutputOptions options; if (argc < 7) { - opserr << G3_ERROR_PROMPT << "recorder Node "; + opserr << OpenSees::PromptValueError << "recorder Node "; opserr << "-node -dof -file -dT
" ""; return TCL_ERROR; @@ -1578,12 +1511,20 @@ createNodeRecorder(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(argv[pos], "-dT") == 0) { // allow user to specify time step size for recording pos++; + if (pos == argc) { + opserr << OpenSees::PromptValueError << "flag -dT is missing required argument\n"; + return TCL_ERROR; + } if (Tcl_GetDouble(interp, argv[pos], &dT) != TCL_OK) return TCL_ERROR; pos++; } else if (strcmp(argv[pos], "-rTolDt") == 0) { pos++; + if (pos == argc) { + opserr << OpenSees::PromptValueError << "flag -rTolDt is missing required argument\n"; + return TCL_ERROR; + } if (Tcl_GetDouble(interp, argv[pos], &rTolDt) != TCL_OK) return TCL_ERROR; pos++; @@ -1638,7 +1579,7 @@ createNodeRecorder(ClientData clientData, Tcl_Interp *interp, int argc, } else if (domain->getNode(node) == nullptr) { delete theNodes; theNodes = nullptr; - opserr << G3_ERROR_PROMPT << "cannot find node with tag " << node << "\n"; + opserr << OpenSees::PromptValueError << "cannot find node with tag " << node << "\n"; return TCL_ERROR; } else { @@ -1653,7 +1594,7 @@ createNodeRecorder(ClientData clientData, Tcl_Interp *interp, int argc, (strcmp(argv[pos], "-range")==0)) { // ensure no segmentation fault if user messes up if (argc < pos + 3) { - opserr << G3_ERROR_PROMPT << "recorder " << argv[1] + opserr << OpenSees::PromptValueError << "recorder " << argv[1] << " .. -range start? end? .. - missing start/end tags\n"; return TCL_ERROR; } @@ -1661,16 +1602,16 @@ createNodeRecorder(ClientData clientData, Tcl_Interp *interp, int argc, // read in start and end tags of two elements & add set [start,end] int start, end; if (Tcl_GetInt(interp, argv[pos + 1], &start) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "recorder " << argv[1] + opserr << OpenSees::PromptValueError << "recorder " << argv[1] << " -range start? end? - invalid start " - << argv[pos + 1] << endln; + << argv[pos + 1] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[pos + 2], &end) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "recorder " << argv[1] + opserr << OpenSees::PromptValueError << "recorder " << argv[1] << " -range start? end? - invalid end " - << argv[pos + 2] << endln; + << argv[pos + 2] << "\n"; return TCL_ERROR; } @@ -1697,13 +1638,13 @@ createNodeRecorder(ClientData clientData, Tcl_Interp *interp, int argc, int tag; if (Tcl_GetInt(interp, argv[pos + 1], &tag) != TCL_OK) { opserr << "WARNING recorder Node -region tag? - invalid tag " - << argv[pos + 1] << endln; + << argv[pos + 1] << "\n"; return TCL_ERROR; } MeshRegion *theRegion = domain->getRegion(tag); if (theRegion == nullptr) { opserr << "WARNING recorder Node -region " << tag - << " - region does not exist" << endln; + << " - region does not exist" << "\n"; return TCL_OK; } @@ -1727,12 +1668,12 @@ createNodeRecorder(ClientData clientData, Tcl_Interp *interp, int argc, pos++; } } - // AddingSensitivity:BEGIN ////////////////////////////////////// + else if (strcmp(argv[pos], "-sensitivity") == 0) { pos++; int paramTag; if (Tcl_GetInt(interp, argv[pos], ¶mTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid parameter tag to node recorder." << endln; + opserr << OpenSees::PromptValueError << "invalid parameter tag to node recorder." << "\n"; return TCL_ERROR; } pos++; @@ -1740,19 +1681,21 @@ createNodeRecorder(ClientData clientData, Tcl_Interp *interp, int argc, // Now get gradIndex from parameter tag Parameter *theParameter = domain->getParameter(paramTag); if (theParameter == nullptr) { - opserr << G3_ERROR_PROMPT << "parameter " << paramTag << " not found" - << endln; + opserr << OpenSees::PromptValueError << "parameter " << paramTag << " not found" + << "\n"; return TCL_ERROR; } gradIndex = theParameter->getGradIndex(); } - // AddingSensitivity:END //////////////////////////////////////// + else if (responseID == nullptr && pos < argc) { responseID = argv[pos]; pos++; } + else if (pos < argc) { - opserr << "WARNING Unknown argument " << argv[pos] << "\n"; + opserr << "WARNING Unknown argument " << argv[pos] << " at index " << pos << "\n"; + return TCL_ERROR; } } // while (pos < argc) @@ -1764,7 +1707,7 @@ createNodeRecorder(ClientData clientData, Tcl_Interp *interp, int argc, theOutputStream = createOutputStream(options); if (theTimeSeries != nullptr && theTimeSeriesID.Size() < theDofs.Size()) { - opserr << G3_ERROR_PROMPT << "recorder Node/EnvelopNode # TimeSeries must equal # " + opserr << OpenSees::PromptValueError << "recorder Node/EnvelopNode # TimeSeries must equal # " "dof - IGNORING TimeSeries OPTION\n"; for (int i = 0; i < theTimeSeriesID.Size(); ++i) { if (theTimeSeries[i] != nullptr) @@ -1776,7 +1719,7 @@ createNodeRecorder(ClientData clientData, Tcl_Interp *interp, int argc, if ((dataFlag = getNodeDataFlag(responseID, *domain, &dataIndex)) == NodeData::Unknown) { - opserr << G3_ERROR_PROMPT << "invalid response ID '" << responseID << "'\n"; + opserr << OpenSees::PromptValueError << "invalid response ID '" << responseID << "'\n"; return TCL_ERROR; } diff --git a/SRC/runtime/commands/domain/region.cpp b/SRC/runtime/commands/domain/region.cpp index 776dc04f3f..67f99d638e 100644 --- a/SRC/runtime/commands/domain/region.cpp +++ b/SRC/runtime/commands/domain/region.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -10,8 +19,8 @@ // // Written: fmk, cmp // -#include -#include +#include +#include #include #include #include @@ -19,7 +28,7 @@ #include int -TclCommand_addMeshRegion(ClientData clientData, Tcl_Interp *interp, int argc, +TclCommand_addMeshRegion(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { Domain& theDomain = *static_cast(clientData); @@ -46,7 +55,7 @@ TclCommand_addMeshRegion(ClientData clientData, Tcl_Interp *interp, int argc, } if (Tcl_GetInt(interp, argv[loc], &tag) != TCL_OK) { - opserr << "WARNING region tag? .. - invalid tag " << argv[loc] << endln; + opserr << "WARNING region tag? .. - invalid tag " << argv[loc] << "\n"; return TCL_ERROR; } @@ -83,8 +92,9 @@ TclCommand_addMeshRegion(ClientData clientData, Tcl_Interp *interp, int argc, if (loc < argc) loc--; - } else if (strcmp(argv[loc], "-eleRange") == 0 || - strcmp(argv[loc], "-eleOnlyRange") == 0) { + } + else if (strcmp(argv[loc], "-eleRange") == 0 || + strcmp(argv[loc], "-eleOnlyRange") == 0) { if (strcmp(argv[loc], "-eleOnlyRange") == 0) eleOnly = true; @@ -103,12 +113,12 @@ TclCommand_addMeshRegion(ClientData clientData, Tcl_Interp *interp, int argc, int start, end; if (Tcl_GetInt(interp, argv[loc + 1], &start) != TCL_OK) { opserr << "WARNING region tag? -eleRange start? end? - invalid start " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[loc + 2], &end) != TCL_OK) { opserr << "WARNING region tag? -eleRange start? end? - invalid end " - << argv[loc + 2] << endln; + << argv[loc + 2] << "\n"; return TCL_ERROR; } if (start > end) { @@ -143,7 +153,7 @@ TclCommand_addMeshRegion(ClientData clientData, Tcl_Interp *interp, int argc, // read in list of nodes - if (theNodes == 0) + if (theNodes == nullptr) theNodes = new ID(0, 64); int nodTag; while (loc < argc && Tcl_GetInt(interp, argv[loc++], &nodTag) == TCL_OK) { @@ -170,12 +180,12 @@ TclCommand_addMeshRegion(ClientData clientData, Tcl_Interp *interp, int argc, int start, end; if (Tcl_GetInt(interp, argv[loc + 1], &start) != TCL_OK) { opserr << "WARNING region tag? -eleRange start? end? - invalid start " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[loc + 2], &end) != TCL_OK) { opserr << "WARNING region tag? -eleRange start? end? - invalid end " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } if (start > end) { @@ -204,22 +214,22 @@ TclCommand_addMeshRegion(ClientData clientData, Tcl_Interp *interp, int argc, // read in rayleigh damping factors if (Tcl_GetDouble(interp, argv[loc + 1], &alphaM) != TCL_OK) { opserr << "WARNING region tag? .. -rayleigh aM bK bK0 - invalid aM " - << argv[loc + 1] << endln; + << argv[loc + 1] << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[loc + 2], &betaK) != TCL_OK) { opserr << "WARNING region tag? .. -rayleigh aM bK bK0 - invalid bK " - << argv[loc + 2] << endln; + << argv[loc + 2] << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[loc + 3], &betaK0) != TCL_OK) { opserr << "WARNING region tag? .. -rayleigh aM bK bK0 - invalid bK0 " - << argv[loc + 3] << endln; + << argv[loc + 3] << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[loc + 4], &betaKc) != TCL_OK) { opserr << "WARNING region tag? .. -rayleigh aM bK bK0 - invalid bKc " - << argv[loc + 4] << endln; + << argv[loc + 4] << "\n"; return TCL_ERROR; } loc += 5; @@ -284,7 +294,7 @@ TclCommand_addMeshRegion(ClientData clientData, Tcl_Interp *interp, int argc, MeshRegion *theRegion = new MeshRegion(tag); if (theDomain.addRegion(*theRegion) < 0) { - opserr << "WARNING could not add to domain - region " << tag << endln; + opserr << "WARNING could not add to domain - region " << tag << "\n"; delete theRegion; return TCL_ERROR; } diff --git a/SRC/runtime/commands/domain/response.cpp b/SRC/runtime/commands/domain/response.cpp index 21b92a72f7..a309498b5c 100644 --- a/SRC/runtime/commands/domain/response.cpp +++ b/SRC/runtime/commands/domain/response.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -21,26 +30,26 @@ basicDeformation(ClientData clientData, Tcl_Interp *interp, int argc, Domain *the_domain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - basicDeformation eleTag? \n"; + opserr << OpenSees::PromptValueError << "want - basicDeformation eleTag? \n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "basicDeformation eleTag? dofNum? - could not read " + opserr << OpenSees::PromptValueError << "basicDeformation eleTag? dofNum? - could not read " "eleTag? \n"; return TCL_ERROR; } /* if (Tcl_GetInt(interp, argv[2], &secNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "basicDeformation eleTag? dofNum? - could not read dofNum? + opserr << OpenSees::PromptValueError << "basicDeformation eleTag? dofNum? - could not read dofNum? \n"; return TCL_ERROR; } */ Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "basicDeformation element with tag " << tag + opserr << OpenSees::PromptValueError << "basicDeformation element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -82,26 +91,26 @@ basicForce(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** cons Domain *the_domain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - basicForce eleTag? \n"; + opserr << OpenSees::PromptValueError << "want - basicForce eleTag? \n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "basicForce eleTag? dofNum? - could not read eleTag? \n"; + opserr << OpenSees::PromptValueError << "basicForce eleTag? dofNum? - could not read eleTag? \n"; return TCL_ERROR; } /* if (Tcl_GetInt(interp, argv[2], &secNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "basicDeformation eleTag? dofNum? - could not read dofNum \n"; + opserr << OpenSees::PromptValueError << "basicDeformation eleTag? dofNum? - could not read dofNum \n"; return TCL_ERROR; } */ Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "basicDeformation element with tag " << tag + opserr << OpenSees::PromptValueError << "basicDeformation element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -144,26 +153,26 @@ basicStiffness(ClientData clientData, Tcl_Interp *interp, int argc, Domain *the_domain = (Domain*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "want - basicStiffness eleTag? \n"; + opserr << OpenSees::PromptValueError << "want - basicStiffness eleTag? \n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "basicStiffness eleTag? - could not read eleTag? \n"; + opserr << OpenSees::PromptValueError << "basicStiffness eleTag? - could not read eleTag? \n"; return TCL_ERROR; } /* if (Tcl_GetInt(interp, argv[2], &secNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "basicDeformation eleTag? dofNum? - could not read dofNum?\n"; + opserr << OpenSees::PromptValueError << "basicDeformation eleTag? dofNum? - could not read dofNum?\n"; return TCL_ERROR; } */ Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "basicStiffness element with tag " << tag + opserr << OpenSees::PromptValueError << "basicStiffness element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -208,7 +217,7 @@ sectionForce(ClientData clientData, Tcl_Interp *interp, int argc, Domain *the_domain = (Domain*)clientData; if (argc < 3) { - opserr << G3_ERROR_PROMPT << "want - sectionForce eleTag? dof? \n"; + opserr << OpenSees::PromptValueError << "want - sectionForce eleTag? dof? \n"; return TCL_ERROR; } @@ -216,7 +225,7 @@ sectionForce(ClientData clientData, Tcl_Interp *interp, int argc, int secNum = 0; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionForce eleTag? secNum? dof? - could not read " + opserr << OpenSees::PromptValueError << "sectionForce eleTag? secNum? dof? - could not read " "eleTag? \n"; return TCL_ERROR; } @@ -225,20 +234,20 @@ sectionForce(ClientData clientData, Tcl_Interp *interp, int argc, int currentArg = 2; if (argc > 3) { if (Tcl_GetInt(interp, argv[currentArg++], &secNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionForce eleTag? secNum? dof? - could not read " + opserr << OpenSees::PromptValueError << "sectionForce eleTag? secNum? dof? - could not read " "secNum? \n"; return TCL_ERROR; } } if (Tcl_GetInt(interp, argv[currentArg++], &dof) != TCL_OK) { opserr - << G3_ERROR_PROMPT << "sectionForce eleTag? secNum? dof? - could not read dof? \n"; + << OpenSees::PromptValueError << "sectionForce eleTag? secNum? dof? - could not read dof? \n"; return TCL_ERROR; } Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "sectionForce element with tag " << tag + opserr << OpenSees::PromptValueError << "sectionForce element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -283,30 +292,30 @@ sectionDeformation(ClientData clientData, Tcl_Interp *interp, int argc, Domain *the_domain = (Domain*)clientData; if (argc < 4) { - opserr << G3_ERROR_PROMPT << "want - sectionDeformation eleTag? secNum? dof? \n"; + opserr << OpenSees::PromptValueError << "want - sectionDeformation eleTag? secNum? dof? \n"; return TCL_ERROR; } int tag, secNum, dof; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionDeformation eleTag? secNum? dof? - could not " + opserr << OpenSees::PromptValueError << "sectionDeformation eleTag? secNum? dof? - could not " "read eleTag? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &secNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionDeformation eleTag? secNum? dof? - could not " + opserr << OpenSees::PromptValueError << "sectionDeformation eleTag? secNum? dof? - could not " "read secNum? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &dof) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionDeformation eleTag? secNum? dof? - could not " + opserr << OpenSees::PromptValueError << "sectionDeformation eleTag? secNum? dof? - could not " "read dof? \n"; return TCL_ERROR; } Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "sectionDeformation element with tag " << tag + opserr << OpenSees::PromptValueError << "sectionDeformation element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -348,25 +357,25 @@ sectionLocation(ClientData clientData, Tcl_Interp *interp, int argc, Domain *the_domain = (Domain*)clientData; if (argc < 3) { - opserr << G3_ERROR_PROMPT << "want - sectionLocation eleTag? secNum? \n"; + opserr << OpenSees::PromptValueError << "want - sectionLocation eleTag? secNum? \n"; return TCL_ERROR; } int tag, secNum; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionLocation eleTag? secNum? - could not read " + opserr << OpenSees::PromptValueError << "sectionLocation eleTag? secNum? - could not read " "eleTag? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &secNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionLocation eleTag? secNum? - could not read " + opserr << OpenSees::PromptValueError << "sectionLocation eleTag? secNum? - could not read " "secNum? \n"; return TCL_ERROR; } Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "sectionLocation element with tag " << tag + opserr << OpenSees::PromptValueError << "sectionLocation element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -404,7 +413,7 @@ sectionWeight(ClientData clientData, Tcl_Interp *interp, int argc, Domain *the_domain = (Domain*)clientData; if (argc < 3) { - opserr << G3_ERROR_PROMPT << "want - sectionWeight eleTag? secNum? \n"; + opserr << OpenSees::PromptValueError << "want - sectionWeight eleTag? secNum? \n"; return TCL_ERROR; } @@ -412,18 +421,18 @@ sectionWeight(ClientData clientData, Tcl_Interp *interp, int argc, if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { opserr - << G3_ERROR_PROMPT << "sectionWeight eleTag? secNum? - could not read eleTag? \n"; + << OpenSees::PromptValueError << "sectionWeight eleTag? secNum? - could not read eleTag? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &secNum) != TCL_OK) { opserr - << G3_ERROR_PROMPT << "sectionWeight eleTag? secNum? - could not read secNum? \n"; + << OpenSees::PromptValueError << "sectionWeight eleTag? secNum? - could not read secNum? \n"; return TCL_ERROR; } Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "sectionWeight element with tag " << tag + opserr << OpenSees::PromptValueError << "sectionWeight element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -460,26 +469,26 @@ sectionStiffness(ClientData clientData, Tcl_Interp *interp, int argc, Domain *the_domain = (Domain*)clientData; if (argc < 3) { - opserr << G3_ERROR_PROMPT << "want - sectionStiffness eleTag? secNum? \n"; + opserr << OpenSees::PromptValueError << "want - sectionStiffness eleTag? secNum? \n"; return TCL_ERROR; } int tag, secNum; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionStiffness eleTag? secNum? - could not read " + opserr << OpenSees::PromptValueError << "sectionStiffness eleTag? secNum? - could not read " "eleTag? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &secNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionStiffness eleTag? secNum? - could not read " + opserr << OpenSees::PromptValueError << "sectionStiffness eleTag? secNum? - could not read " "secNum? \n"; return TCL_ERROR; } Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "sectionStiffness element with tag " << tag + opserr << OpenSees::PromptValueError << "sectionStiffness element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -529,26 +538,26 @@ sectionFlexibility(ClientData clientData, Tcl_Interp *interp, int argc, Domain *the_domain = (Domain*)clientData; if (argc < 3) { - opserr << G3_ERROR_PROMPT << "want - sectionFlexibility eleTag? secNum? \n"; + opserr << OpenSees::PromptValueError << "want - sectionFlexibility eleTag? secNum? \n"; return TCL_ERROR; } int tag, secNum; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionFlexibility eleTag? secNum? - could not read " + opserr << OpenSees::PromptValueError << "sectionFlexibility eleTag? secNum? - could not read " "eleTag? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &secNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionFlexibility eleTag? secNum? - could not read " + opserr << OpenSees::PromptValueError << "sectionFlexibility eleTag? secNum? - could not read " "secNum? \n"; return TCL_ERROR; } Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "sectionFlexibility element with tag " << tag + opserr << OpenSees::PromptValueError << "sectionFlexibility element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -598,25 +607,25 @@ sectionTag(ClientData clientData, Tcl_Interp *interp, int argc, Domain *the_domain = (Domain*)clientData; if (argc < 3) { - opserr << G3_ERROR_PROMPT << "want - sectionTag eleTag? secNum? \n"; + opserr << OpenSees::PromptValueError << "want - sectionTag eleTag? secNum? \n"; return TCL_ERROR; } int tag, secNum; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionTag eleTag? secNum? - could not read " + opserr << OpenSees::PromptValueError << "sectionTag eleTag? secNum? - could not read " "eleTag? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &secNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionTag eleTag? secNum? - could not read " + opserr << OpenSees::PromptValueError << "sectionTag eleTag? secNum? - could not read " "secNum? \n"; return TCL_ERROR; } Element *theElement = the_domain->getElement(tag); if (theElement == nullptr) { - opserr << G3_ERROR_PROMPT << "sectionFlexibility element with tag " << tag + opserr << OpenSees::PromptValueError << "sectionFlexibility element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -667,19 +676,19 @@ sectionDisplacement(ClientData clientData, Tcl_Interp *interp, int argc, Domain *theDomain = (Domain*)clientData; if (argc < 3) { - opserr << G3_ERROR_PROMPT << "want - sectionLocation eleTag? secNum? \n"; + opserr << OpenSees::PromptValueError << "want - sectionLocation eleTag? secNum? \n"; return TCL_ERROR; } int tag, secNum; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionLocation eleTag? secNum? - could not read " + opserr << OpenSees::PromptValueError << "sectionLocation eleTag? secNum? - could not read " "eleTag? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &secNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "sectionLocation eleTag? secNum? - could not read " + opserr << OpenSees::PromptValueError << "sectionLocation eleTag? secNum? - could not read " "secNum? \n"; return TCL_ERROR; } diff --git a/SRC/runtime/commands/domain/rigid_links.cpp b/SRC/runtime/commands/domain/rigid_links.cpp index d6b7662fdf..2f4a153a8f 100644 --- a/SRC/runtime/commands/domain/rigid_links.cpp +++ b/SRC/runtime/commands/domain/rigid_links.cpp @@ -1,9 +1,17 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// // // Author: fmk, cmp // @@ -34,109 +42,110 @@ static int createLinearRigidDiaphragm(Domain &theDomain, int ret_tag, ID &nC, in static int createLinearRigidBeam(Domain &theDomain, int ret_tag, int con_tag) { - - // get a pointer to the retained and constrained nodes - make sure they exist - Node *nodeR = theDomain.getNode(ret_tag); - if (nodeR == nullptr) { - opserr << G3_ERROR_PROMPT - << "retained Node" << ret_tag << " not in domain\n"; - return CONSTRAINT_ERROR; - } - Node *nodeC = theDomain.getNode(con_tag); - if (nodeR == nullptr) { - opserr << G3_ERROR_PROMPT - << "constrained node " << con_tag << " not in domain\n"; - return CONSTRAINT_ERROR; - } + // get a pointer to the retained and constrained nodes - make sure they exist + Node *nodeR = theDomain.getNode(ret_tag); - // get the coordinates of the two nodes - check dimensions are the same - const Vector &crdR = nodeR->getCrds(); - const Vector &crdC = nodeC->getCrds(); - int dimR = crdR.Size(); - int dimC = crdC.Size(); - if (dimR != dimC) { - opserr << G3_ERROR_PROMPT - << "mismatch in dimension between constrained node " - << con_tag << " and retained node " << ret_tag << "\n"; - return CONSTRAINT_ERROR; - } - - // check the number of dof at each node is the same - int numDOF = nodeR->getNumberDOF(); - if (numDOF != nodeC->getNumberDOF()){ - opserr << G3_ERROR_PROMPT - << "mismatch in numDOF between constrained node " - << con_tag << " and retained node " << ret_tag << "\n"; - return CONSTRAINT_ERROR; - } + if (nodeR == nullptr) { + opserr << OpenSees::PromptValueError + << "retained node " << ret_tag << " not in domain\n"; + return CONSTRAINT_ERROR; + } - // check the number of dof at the nodes >= dimension of problem - if(numDOF < dimR){ - opserr << G3_ERROR_PROMPT - << "numDOF at nodes " << ret_tag << " and " - << con_tag << " must be >= dimension of problem\n"; - return CONSTRAINT_ERROR; - } - - // create the ID to identify the constrained dof - ID id(numDOF); + Node *nodeC = theDomain.getNode(con_tag); + if (nodeR == nullptr) { + opserr << OpenSees::PromptValueError + << "constrained node " << con_tag << " not in domain\n"; + return CONSTRAINT_ERROR; + } - // construct the transformation matrix Ccr, where Uc = Ccr Ur & set the diag, Ccr = I - Matrix mat(numDOF,numDOF); - mat.Zero(); + // get the coordinates of the two nodes - check dimensions are the same + const Vector &crdR = nodeR->getCrds(); + const Vector &crdC = nodeC->getCrds(); + int dimR = crdR.Size(); + int dimC = crdC.Size(); + if (dimR != dimC) { + opserr << OpenSees::PromptValueError + << "mismatch in dimension between constrained node " + << con_tag << " and retained node " << ret_tag << "\n"; + return CONSTRAINT_ERROR; + } + + // check the number of dof at each node is the same + int numDOF = nodeR->getNumberDOF(); + if (numDOF != nodeC->getNumberDOF()){ + opserr << OpenSees::PromptValueError + << "mismatch in numDOF between constrained node " + << con_tag << " and retained node " << ret_tag << "\n"; + return CONSTRAINT_ERROR; + } - // set the values - for (int i=0; i= dimension of problem + if(numDOF < dimR){ + opserr << OpenSees::PromptValueError + << "numDOF at nodes " << ret_tag << " and " + << con_tag << " must be >= dimension of problem\n"; + return CONSTRAINT_ERROR; + } - // if there are rotational dof - we must modify Ccr DONE ASSUMING SMALL ROTATIONS - if (dimR != numDOF) { - if (dimR == 2 && numDOF == 3) { - double deltaX = crdC(0) - crdR(0); - double deltaY = crdC(1) - crdR(1); - mat(0,2) = -deltaY; - mat(1,2) = deltaX; - - } else if (dimR == 3 && numDOF == 6) { - double deltaX = crdC(0) - crdR(0); - double deltaY = crdC(1) - crdR(1); - double deltaZ = crdC(2) - crdR(2); - - // rotation about z/3 axis - mat(0,5) = -deltaY; - mat(1,5) = deltaX; - - // rotation about y/2 axis - mat(0,4) = deltaZ; - mat(2,4) = -deltaX; - - // rotation about x/1 axis - mat(1,3) = -deltaZ; - mat(2,3) = deltaY; - - } else { // not valid - opserr << G3_ERROR_PROMPT - << " for nodes " << ret_tag << " and " << con_tag - << " nodes do not have valid numDOF for their dimension\n"; - return CONSTRAINT_ERROR; - } - } - - // create the MP_Constraint - MP_Constraint *newC = new MP_Constraint(ret_tag, con_tag, mat, id, id); - - // add the constraint to the domain - if (theDomain.addMP_Constraint(newC) == false) { - delete newC; - opserr << G3_ERROR_PROMPT - << "nodes " << con_tag << " and " << ret_tag << ", could not add to domain\n"; + // create the ID to identify the constrained dof + ID id(numDOF); + + // construct the transformation matrix Ccr, where Uc = Ccr Ur & set the diag, Ccr = I + Matrix mat(numDOF,numDOF); + mat.Zero(); + + // set the values + for (int i=0; igetCrds(); - const Vector &crdC = nodeC->getCrds(); - int dimR = crdR.Size(); - int dimC = crdC.Size(); - if (dimR != dimC) { - opserr << G3_ERROR_PROMPT - << "mismatch in dimension between constrained node " - << con_tag << " and retained node " << ret_tag << "\n"; - return CONSTRAINT_ERROR; - } - - // check the number of dof at each node is the same - int numDOF = nodeR->getNumberDOF(); - if (numDOF != nodeC->getNumberDOF()){ - opserr << G3_ERROR_PROMPT - << "mismatch in numDOF " << "between constrained node " - << con_tag << " and retained node " << ret_tag << "\n"; - return CONSTRAINT_ERROR; - } + // get the coordinates of the two nodes - check dimensions are the same + const Vector &crdR = nodeR->getCrds(); + const Vector &crdC = nodeC->getCrds(); + int dimR = crdR.Size(); + int dimC = crdC.Size(); + if (dimR != dimC) { + opserr << OpenSees::PromptValueError + << "mismatch in dimension between constrained node " + << con_tag << " and retained node " << ret_tag << "\n"; + return CONSTRAINT_ERROR; + } + + // check the number of dof at each node is the same + int numDOF = nodeR->getNumberDOF(); + if (numDOF != nodeC->getNumberDOF()){ + opserr << OpenSees::PromptValueError + << "mismatch in numDOF " << "between constrained node " + << con_tag << " and retained node " << ret_tag << "\n"; + return CONSTRAINT_ERROR; + } - // check the number of dof at the nodes >= dimension of problem - if(numDOF < dimR){ - opserr << G3_ERROR_PROMPT - << "numDOF at nodes " << ret_tag << " and " << con_tag - << " must be >= dimension of problem\n"; - return CONSTRAINT_ERROR; - } - - // create the ID to identify the constrained dof - ID id(dimR); + // check the number of dof at the nodes >= dimension of problem + if(numDOF < dimR){ + opserr << OpenSees::PromptValueError + << "numDOF at nodes " << ret_tag << " and " << con_tag + << " must be >= dimension of problem\n"; + return CONSTRAINT_ERROR; + } - // construct the transformation matrix Ccr, where Uc = Ccr Ur & set the diag - Matrix mat(dimR,dimR); - mat.Zero(); + // create the ID to identify the constrained dof + ID id(dimR); - // set the values - for (int i=0; i 2) { - opserr << G3_ERROR_PROMPT << + opserr << OpenSees::PromptValueError << "the dirn of perpendicular to constrained plane " << perpPlaneConstrained << " not valid\n"; return CONSTRAINT_ERROR; } // check constrainedNodes ID does not contain the retained node if (nC.getLocation(ret_tag) >= 0) { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "retained node " << ret_tag << " is in constrained node list\n"; return CONSTRAINT_ERROR; } @@ -240,15 +249,15 @@ createLinearRigidDiaphragm(Domain &theDomain, int ret_tag, ID &nC, // get a pointer to the retained node and check node in 3d with 6 DOFs Node *nodeR = theDomain.getNode(ret_tag); if (nodeR == nullptr) { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "retained Node " << ret_tag << " not in domain\n"; return CONSTRAINT_ERROR; } const Vector &crdR = nodeR->getCrds(); if ((nodeR->getNumberDOF() != 6) || (crdR.Size() != 3)){ - opserr << G3_ERROR_PROMPT - << "retained Node " << ret_tag << " not in 3d space with 6 DOFs\n"; + opserr << OpenSees::PromptValueError + << "retained node " << ret_tag << " not in 3d space with 6 DOFs\n"; return CONSTRAINT_ERROR; } @@ -281,7 +290,7 @@ createLinearRigidDiaphragm(Domain &theDomain, int ret_tag, ID &nC, // ensure node exists if (nodeC == nullptr) { // TODO: Document change; this used to be accepted without error. - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "cannot constrain node " << ndC << " as no node in domain\n"; return CONSTRAINT_ERROR; } @@ -311,7 +320,7 @@ createLinearRigidDiaphragm(Domain &theDomain, int ret_tag, ID &nC, mat(1,2) = deltaX; } else { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "ignoring constrained node " << ndC << ", not in xy plane\n"; return CONSTRAINT_ERROR; } @@ -330,7 +339,7 @@ createLinearRigidDiaphragm(Domain &theDomain, int ret_tag, ID &nC, mat(1,2) = -deltaX; } else { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "ignoring constrained node " << ndC << ", not in xz plane\n"; return CONSTRAINT_ERROR; } @@ -349,7 +358,7 @@ createLinearRigidDiaphragm(Domain &theDomain, int ret_tag, ID &nC, mat(1,2) = deltaY; } else { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "ignoring constrained node " << ndC << ", not in xz plane\n"; return CONSTRAINT_ERROR; } @@ -360,19 +369,20 @@ createLinearRigidDiaphragm(Domain &theDomain, int ret_tag, ID &nC, // add the constraint to the domain if (theDomain.addMP_Constraint(newC) == false) { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "ignoring constrained node " << ndC << ", failed to add\n"; delete newC; return CONSTRAINT_ERROR; } + } - } else { + else { opserr << G3_WARN_PROMPT << "ignoring constrained node " << ndC << ", not 3D node\n"; return CONSTRAINT_OK; - } - + } } // for each node in constrained nodes + return CONSTRAINT_OK; } @@ -384,18 +394,18 @@ TclCommand_RigidDiaphragm(ClientData clientData, Tcl_Interp *interp, int argc, T Domain *theTclDomain = ((BasicModelBuilder*)clientData)->getDomain(); if (argc < 3) { - opserr << G3_ERROR_PROMPT << "rigidLink perpDirn? rNode? \n"; + opserr << OpenSees::PromptValueError << "rigidLink perpDirn? rNode? \n"; return TCL_ERROR; } int rNode, perpDirn; if (Tcl_GetInt(interp, argv[1], &perpDirn) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rigidLink perpDirn rNode cNodes - could not read perpDirn? \n"; + opserr << OpenSees::PromptValueError << "rigidLink perpDirn rNode cNodes - could not read perpDirn? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &rNode) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rigidLink perpDirn rNode cNodes - could not read rNode \n"; + opserr << OpenSees::PromptValueError << "rigidLink perpDirn rNode cNodes - could not read rNode \n"; return TCL_ERROR; } @@ -405,7 +415,7 @@ TclCommand_RigidDiaphragm(ClientData clientData, Tcl_Interp *interp, int argc, T for (int i=0; igetDomain(); if (argc < 4) { - opserr << G3_ERROR_PROMPT << "rigidLink linkType? rNode? cNode?\n"; + opserr << OpenSees::PromptValueError << "rigidLink linkType? rNode? cNode?\n"; return TCL_ERROR; } int rNode, cNode; if (Tcl_GetInt(interp, argv[2], &rNode) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rigidLink linkType? rNode? cNode? - could not read rNode \n"; + opserr << OpenSees::PromptValueError + << "invalid rNode" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } + if (Tcl_GetInt(interp, argv[3], &cNode) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "rigidLink linkType? rNode? cNode? - could not read CNode \n"; + opserr << OpenSees::PromptValueError + << "invalid CNode" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } // construct a rigid rod or beam depending on 1st arg if ((strcmp(argv[1],"-bar") == 0) || (strcmp(argv[1],"bar") == 0)) { - // RigidRod theLink(*theTclDomain, rNode, cNode); - createLinearRigidRod(*theTclDomain, rNode, cNode); + return createLinearRigidRod(*theTclDomain, rNode, cNode); } else if ((strcmp(argv[1],"-beam") == 0) || (strcmp(argv[1],"beam") == 0)) { - createLinearRigidBeam(*theTclDomain, rNode, cNode); - //RigidBeam theLink(*theTclDomain, rNode, cNode); + return createLinearRigidBeam(*theTclDomain, rNode, cNode); } else { - opserr << G3_ERROR_PROMPT << "rigidLink linkType? rNode? cNode? - unrecognised link type (-bar, -beam) \n"; + opserr << OpenSees::PromptValueError + << "unrecognised link type (-bar, -beam) \n"; return TCL_ERROR; } return TCL_OK; diff --git a/SRC/runtime/commands/domain/runtime.cpp b/SRC/runtime/commands/domain/runtime.cpp index a08f0324cc..63479af404 100644 --- a/SRC/runtime/commands/domain/runtime.cpp +++ b/SRC/runtime/commands/domain/runtime.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -11,7 +20,7 @@ #include #include #include -#include // Tcl_Char +#include #include int @@ -81,20 +90,9 @@ int TclCommand_getTime(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { assert(clientData != nullptr); - Domain* domain = (Domain*)clientData; - - double time = domain->getCurrentTime(); - - // get the display format - char format[80]; - if (argc == 1) { - sprintf(format, "%f", time); - } else if (argc == 2) { - sprintf(format, argv[1], time); - } + Domain* domain = static_cast(clientData); - // now we copy the value to the tcl string that is returned - Tcl_SetResult(interp, format, TCL_VOLATILE); + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(domain->getCurrentTime())); return TCL_OK; } diff --git a/SRC/runtime/commands/domain/sensitivity.cpp b/SRC/runtime/commands/domain/sensitivity.cpp index e4fdbb977b..029644f523 100644 --- a/SRC/runtime/commands/domain/sensitivity.cpp +++ b/SRC/runtime/commands/domain/sensitivity.cpp @@ -1,14 +1,29 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// -// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// #include #include + +#include #include #include -#include +#include +#include +#include +#include +#include #include #include #include @@ -16,7 +31,6 @@ #include - int sensNodeDisp(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) @@ -26,7 +40,7 @@ sensNodeDisp(ClientData clientData, Tcl_Interp *interp, int argc, // make sure at least one other argument to contain type of system if (argc < 4) { - opserr << "WARNING want - sensNodeDisp nodeTag? dof? paramTag?\n"; + opserr << OpenSees::PromptValueError << "want - sensNodeDisp nodeTag? dof? paramTag?\n"; return TCL_ERROR; } @@ -34,28 +48,30 @@ sensNodeDisp(ClientData clientData, Tcl_Interp *interp, int argc, if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { opserr - << "WARNING nodeDisp nodeTag? dof? paramTag?- could not read nodeTag? "; + << OpenSees::PromptValueError << "nodeDisp nodeTag? dof? paramTag?- could not read nodeTag? "; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << "WARNING nodeDisp nodeTag? dof? paramTag?- could not read dof? "; + opserr << OpenSees::PromptValueError << "nodeDisp nodeTag? dof? paramTag?- could not read dof? "; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], ¶mTag) != TCL_OK) { - opserr << "WARNING nodeDisp paramTag? dof? paramTag?- could not read " + opserr << OpenSees::PromptValueError << "nodeDisp paramTag? dof? paramTag?- could not read " "paramTag? "; return TCL_ERROR; } + // + // Node *theNode = theDomain->getNode(tag); - if (theNode == 0) { - opserr << "sensNodeDisp: node " << tag << " not found" << endln; + if (theNode == nullptr) { + opserr << "sensNodeDisp: node " << tag << " not found" << "\n"; return TCL_ERROR; } Parameter *theParam = theDomain->getParameter(paramTag); - if (theParam == 0) { - opserr << "sensNodeDisp: parameter " << paramTag << " not found" << endln; + if (theParam == nullptr) { + opserr << "sensNodeDisp: parameter " << paramTag << " not found" << "\n"; return TCL_ERROR; } @@ -63,9 +79,7 @@ sensNodeDisp(ClientData clientData, Tcl_Interp *interp, int argc, double value = theNode->getDispSensitivity(dof, gradIndex); - char buffer[40]; - sprintf(buffer, "%35.20f", value); - Tcl_SetResult(interp, buffer, TCL_VOLATILE); + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(value)); return TCL_OK; } @@ -79,37 +93,37 @@ sensNodeVel(ClientData clientData, Tcl_Interp *interp, int argc, // make sure at least one other argument to contain type of system if (argc < 4) { - opserr << "WARNING want - sensNodeVel nodeTag? dof? paramTag?\n"; + opserr << OpenSees::PromptValueError << "want - sensNodeVel nodeTag? dof? paramTag?\n"; return TCL_ERROR; } int tag, dof, paramTag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING sensNodeVel nodeTag? dof? paramTag? - could not read " + opserr << OpenSees::PromptValueError << "sensNodeVel nodeTag? dof? paramTag? - could not read " "nodeTag? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << "WARNING sensNodeVel nodeTag? dof? paramTag? - could not read " + opserr << OpenSees::PromptValueError << "sensNodeVel nodeTag? dof? paramTag? - could not read " "dof? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], ¶mTag) != TCL_OK) { - opserr << "WARNING sensNodeVel nodeTag? dof? paramTag? - could not read " + opserr << OpenSees::PromptValueError << "sensNodeVel nodeTag? dof? paramTag? - could not read " "paramTag? \n"; return TCL_ERROR; } Node *theNode = theDomain->getNode(tag); - if (theNode == 0) { - opserr << "sensNodeVel: node " << tag << " not found" << endln; + if (theNode == nullptr) { + opserr << "sensNodeVel: node " << tag << " not found" << "\n"; return TCL_ERROR; } Parameter *theParam = theDomain->getParameter(paramTag); - if (theParam == 0) { - opserr << "sensNodeVel: parameter " << paramTag << " not found" << endln; + if (theParam == nullptr) { + opserr << "sensNodeVel: parameter " << paramTag << " not found" << "\n"; return TCL_ERROR; } @@ -117,10 +131,7 @@ sensNodeVel(ClientData clientData, Tcl_Interp *interp, int argc, double value = theNode->getVelSensitivity(dof, gradIndex); - char buffer[40]; - sprintf(buffer, "%35.20f", value); - - Tcl_SetResult(interp, buffer, TCL_VOLATILE); + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(value)); return TCL_OK; } @@ -134,37 +145,39 @@ sensNodeAccel(ClientData clientData, Tcl_Interp *interp, int argc, // make sure at least one other argument to contain type of system if (argc < 4) { - opserr << "WARNING want - sensNodeAccel nodeTag? dof? paramTag?\n"; + opserr << OpenSees::PromptValueError << "want - sensNodeAccel nodeTag? dof? paramTag?\n"; return TCL_ERROR; } int tag, dof, paramTag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING sensNodeAccel nodeTag? dof? paramTag? - could not read " + opserr << OpenSees::PromptValueError << "sensNodeAccel nodeTag? dof? paramTag? - could not read " "nodeTag? \n"; return TCL_ERROR; } + if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << "WARNING sensNodeAccel nodeTag? dof? paramTag? - could not read " + opserr << OpenSees::PromptValueError << "sensNodeAccel nodeTag? dof? paramTag? - could not read " "dof? \n"; return TCL_ERROR; } + if (Tcl_GetInt(interp, argv[3], ¶mTag) != TCL_OK) { - opserr << "WARNING sendNodeAccel nodeTag? dof? paramTag? - could not read " + opserr << OpenSees::PromptValueError << "sendNodeAccel nodeTag? dof? paramTag? - could not read " "paramTag? \n"; return TCL_ERROR; } Node *theNode = theDomain->getNode(tag); - if (theNode == 0) { - opserr << "sensNodeAccel: node " << tag << " not found" << endln; + if (theNode == nullptr) { + opserr << "sensNodeAccel: node " << tag << " not found" << "\n"; return TCL_ERROR; } Parameter *theParam = theDomain->getParameter(paramTag); - if (theParam == 0) { - opserr << "sensNodeAccel: parameter " << paramTag << " not found" << endln; + if (theParam == nullptr) { + opserr << "sensNodeAccel: parameter " << paramTag << " not found" << "\n"; return TCL_ERROR; } @@ -172,10 +185,7 @@ sensNodeAccel(ClientData clientData, Tcl_Interp *interp, int argc, double value = theNode->getAccSensitivity(dof, gradIndex); - char buffer[40]; - sprintf(buffer, "%35.20f", value); - - Tcl_SetResult(interp, buffer, TCL_VOLATILE); + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(value)); return TCL_OK; } @@ -189,35 +199,35 @@ sensNodePressure(ClientData clientData, Tcl_Interp *interp, int argc, // make sure at least one other argument to contain type of system if (argc < 3) { - opserr << "WARNING want - sensNodePressure nodeTag? paramTag?\n"; + opserr << OpenSees::PromptValueError << "want - sensNodePressure nodeTag? paramTag?\n"; return TCL_ERROR; } int tag, paramTag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING sensNodePressure nodeTag? paramTag?- could not read " + opserr << OpenSees::PromptValueError << "sensNodePressure nodeTag? paramTag?- could not read " "nodeTag? "; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], ¶mTag) != TCL_OK) { - opserr << "WARNING sensNodePressure paramTag? paramTag?- could not read " + opserr << OpenSees::PromptValueError << "sensNodePressure paramTag? paramTag?- could not read " "paramTag? "; return TCL_ERROR; } double dp = 0.0; Pressure_Constraint *thePC = theDomain->getPressure_Constraint(tag); - if (thePC != 0) { + if (thePC != nullptr) { // int ptag = thePC->getPressureNode(); // Node* pNode = theDomain->getNode(ptag); Node *pNode = thePC->getPressureNode(); - if (pNode != 0) { + if (pNode != nullptr) { Parameter *theParam = theDomain->getParameter(paramTag); - if (theParam == 0) { + if (theParam == nullptr) { opserr << "sensNodePressure: parameter " << paramTag << " not found" - << endln; + << "\n"; return TCL_ERROR; } @@ -226,10 +236,7 @@ sensNodePressure(ClientData clientData, Tcl_Interp *interp, int argc, } } - char buffer[40]; - sprintf(buffer, "%35.20f", dp); - - Tcl_SetResult(interp, buffer, TCL_VOLATILE); + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(dp)); return TCL_OK; } @@ -238,14 +245,13 @@ int sensSectionForce(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { -#ifdef _RELIABILITY assert(clientData != nullptr); Domain *theDomain = (Domain *)clientData; // make sure at least one other argument to contain type of system if (argc < 4) { opserr - << "WARNING want - sensSectionForce eleTag? dof? paramTag?\n"; + << OpenSees::PromptValueError << "want - sensSectionForce eleTag? dof? paramTag?\n"; return TCL_ERROR; } @@ -253,7 +259,7 @@ sensSectionForce(ClientData clientData, Tcl_Interp *interp, int argc, int secNum = 0; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING sensSectionForce eleTag? secNum? dof? paramTag?- could " + opserr << OpenSees::PromptValueError << "sensSectionForce eleTag? secNum? dof? paramTag?- could " "not read eleTag? \n"; return TCL_ERROR; } @@ -262,18 +268,18 @@ sensSectionForce(ClientData clientData, Tcl_Interp *interp, int argc, int currentArg = 2; if (argc > 4) { if (Tcl_GetInt(interp, argv[currentArg++], &secNum) != TCL_OK) { - opserr << "WARNING sensSectionForce eleTag? secNum? dof? paramTag?- " + opserr << OpenSees::PromptValueError << "sensSectionForce eleTag? secNum? dof? paramTag?- " "could not read secNum? \n"; return TCL_ERROR; } } if (Tcl_GetInt(interp, argv[currentArg++], &dof) != TCL_OK) { - opserr << "WARNING sensSectionForce eleTag? secNum? dof? paramTag?- could " + opserr << OpenSees::PromptValueError << "sensSectionForce eleTag? secNum? dof? paramTag?- could " "not read dof? \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[currentArg++], ¶mTag) != TCL_OK) { - opserr << "WARNING sensSectionForce eleTag? secNum? dof? paramTag?- could " + opserr << OpenSees::PromptValueError << "sensSectionForce eleTag? secNum? dof? paramTag?- could " "not read paramTag? \n"; return TCL_ERROR; } @@ -289,7 +295,7 @@ sensSectionForce(ClientData clientData, Tcl_Interp *interp, int argc, Element *theElement = theDomain->getElement(tag); if (theElement == 0) { - opserr << "WARNING sensSectionForce element with tag " << tag + opserr << OpenSees::PromptValueError << "sensSectionForce element with tag " << tag << " not found in domain \n"; return TCL_ERROR; } @@ -311,8 +317,8 @@ sensSectionForce(ClientData clientData, Tcl_Interp *interp, int argc, DummyStream dummy; Response *theResponse = theElement->setResponse(argvv, argcc, dummy); - if (theResponse == 0) { - Tcl_SetResult(interp, "0.0", TCL_VOLATILE); + if (theResponse == nullptr) { + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(0.0)); return TCL_OK; } @@ -321,75 +327,14 @@ sensSectionForce(ClientData clientData, Tcl_Interp *interp, int argc, const Vector &theVec = *(info.theVector); - char buffer[40]; - sprintf(buffer, "%12.8g", theVec(dof - 1)); - - Tcl_SetResult(interp, buffer, TCL_VOLATILE); + Tcl_SetObjResult(interp, Tcl_NewDoubleObj(theVec(dof - 1))); theParam->activate(false); delete theResponse; -#endif - return TCL_OK; -} - -///////////////////////Abbas////////////////////////////// - -int -sensLambda(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - BasicAnalysisBuilder* builder = (BasicAnalysisBuilder*)clientData; - - - if (argc < 3) { - opserr << "WARNING no load pattern supplied -- getLoadFactor\n"; - return TCL_ERROR; - } - - int pattern, paramTag; - if (Tcl_GetInt(interp, argv[1], &pattern) != TCL_OK) { - opserr << "ERROR reading load pattern tag -- getLoadFactor\n"; - return TCL_ERROR; - } - - LoadPattern *thePattern = builder->getDomain()->getLoadPattern(pattern); - if (thePattern == 0) { - opserr << "ERROR load pattern with tag " << pattern - << " not found in domain -- getLoadFactor\n"; - return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[2], ¶mTag) != TCL_OK) { - opserr << "WARNING sensLambda patternTag? paramTag?- could not read " - "paramTag? "; - return TCL_ERROR; - } - Parameter *theParam = builder->getDomain()->getParameter(paramTag); - if (theParam == 0) { - opserr << "sensLambda: parameter " << paramTag << " not found" << endln; - return TCL_ERROR; - } - -#if 0 - IncrementalIntegrator *theIntegrator = nullptr; - - if (the_static_integrator != nullptr) { - theIntegrator = the_static_integrator; - - } else if (theTransientIntegrator != nullptr) { - theIntegrator = theTransientIntegrator; - } -#endif - - int gradIndex = theParam->getGradIndex(); - double factor = thePattern->getLoadFactorSensitivity(gradIndex); - - char buffer[40]; - sprintf(buffer, "%35.20f", factor); - Tcl_SetResult(interp, buffer, TCL_VOLATILE); return TCL_OK; } - diff --git a/SRC/runtime/commands/domain/staging.cpp b/SRC/runtime/commands/domain/staging.cpp deleted file mode 100644 index c305c163ca..0000000000 --- a/SRC/runtime/commands/domain/staging.cpp +++ /dev/null @@ -1,48 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// OpenSees - Open System for Earthquake Engineering Simulation -// -//===----------------------------------------------------------------------===// -// -int -elementActivate(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - assert(clientData != nullptr); - Domain* the_domain = (Domain*)clientData; - - int eleTag; - int argLoc = 1; - int Nelements = argc; - ID activate_us(0, Nelements); - - while (argLoc < argc && Tcl_GetInt(interp, argv[argLoc], &eleTag) == TCL_OK) { - activate_us.insert(eleTag); - ++argLoc; - } - - the_domain->activateElements(activate_us); - - return TCL_OK; -} - -int -elementDeactivate(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - assert(clientData != nullptr); - Domain* the_domain = (Domain*)clientData; - - int eleTag; - int argLoc = 1; - int Nelements = argc; - ID deactivate_us(0, Nelements); - - while (argLoc < argc && Tcl_GetInt(interp, argv[argLoc], &eleTag) == TCL_OK) { - deactivate_us.insert(eleTag); - ++argLoc; - } - - the_domain->deactivateElements(deactivate_us); - return TCL_OK; -} diff --git a/SRC/runtime/commands/interpreter.cpp b/SRC/runtime/commands/interpreter.cpp index 21cc660d7d..1f68be72cf 100644 --- a/SRC/runtime/commands/interpreter.cpp +++ b/SRC/runtime/commands/interpreter.cpp @@ -1,9 +1,18 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// + // Description: This file contains basic commands that enhance the // experience of the interpreter. This file should not reference // any analysis or modeling classes. @@ -12,16 +21,14 @@ #include #include #include -#include +#include +#include #include +#include "interpreter.h" static Tcl_ObjCmdProc *Tcl_putsCommand = nullptr; static Timer *theTimer = nullptr; -Tcl_CmdProc TclCommand_wipeModel; -Tcl_CmdProc TclCommand_clearAnalysis; -Tcl_CmdProc TclCommand_specifyModel; - class ProgressBar; Tcl_ObjCmdProc TclObjCommand_progress; extern ProgressBar* progress_bar_ptr; @@ -30,19 +37,15 @@ extern ProgressBar* progress_bar_ptr; const char *getInterpPWD(Tcl_Interp *interp); int TclObjCommand_pragma([[maybe_unused]] ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); + Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]); -// formats.cpp -Tcl_CmdProc convertBinaryToText; -Tcl_CmdProc convertTextToBinary; -Tcl_CmdProc stripOpenSeesXML; // // Consider reimplmenting to use Tcl built-ins; see // https://wiki.tcl-lang.org/page/timers // static int -startTimer(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +startTimer(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { if (theTimer == nullptr) theTimer = new Timer(); @@ -52,7 +55,7 @@ startTimer(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** cons } static int -stopTimer(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +stopTimer(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { if (theTimer == nullptr) return TCL_OK; @@ -63,7 +66,7 @@ stopTimer(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const } static int -timer(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char** const argv) +timer(ClientData clientData, Tcl_Interp* interp, Tcl_Size argc, TCL_Char** const argv) { if ((argc == 1) || (strcmp(argv[1], "start")==0)) { stopTimer(clientData, interp, argc, argv); @@ -79,7 +82,7 @@ timer(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char** const argv // revised puts command to send to stderr // static int -OpenSees_putsCommand(ClientData dummy, Tcl_Interp *interp, int objc, +OpenSees_putsCommand(ClientData dummy, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]) { // Tcl_Channel chan; // The channel to puts on. @@ -153,7 +156,7 @@ OpenSees_putsCommand(ClientData dummy, Tcl_Interp *interp, int objc, static int -OPS_SetObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, +OPS_SetObjCmd(ClientData clientData, Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]) { @@ -184,11 +187,10 @@ OPS_SetObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, static int -logFile(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +logFile(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { - if (argc < 2) { - opserr << "WARNING logFile fileName? - no filename supplied\n"; + opserr << "WARNING no filename supplied\n"; return TCL_ERROR; } bool echo = true; @@ -204,15 +206,21 @@ logFile(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const a cArg++; } - if (opserr.setFile(argv[1], mode, echo) < 0) - opserr << "WARNING logFile " << argv[1] << " failed to set the file\n"; + if (opserr.setFile(argv[1], mode, echo) < 0) { + opserr << "WARNING logFile " << argv[1] << " failed to set the file" + << "\n"; + } + std::string cmd = std::string{"namespace eval opensees::internal {set log_file \""} + + std::string{argv[1]} + + std::string{"\"}\n"}; + Tcl_Eval(interp, cmd.c_str()); return TCL_OK; } static int -setPrecision(ClientData clientData, Tcl_Interp *interp, int argc, +setPrecision(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { @@ -291,7 +299,7 @@ OPS_SourceCmd(ClientData dummy, /* Not used. */ } static int -OpenSeesExit(ClientData clientData, Tcl_Interp *interp, int argc, +OpenSeesExit(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { // theDomain.clearAll(); @@ -325,7 +333,7 @@ OpenSeesExit(ClientData clientData, Tcl_Interp *interp, int argc, } static int -maxOpenFiles(ClientData clientData, Tcl_Interp *interp, int argc, +maxOpenFiles(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { int maxOpenFiles; @@ -352,7 +360,7 @@ maxOpenFiles(ClientData clientData, Tcl_Interp *interp, int argc, } int -OpenSeesAppInit(Tcl_Interp *interp) +Init_OpenSees(Tcl_Interp *interp) { // redo puts command so we can capture puts into std:cerr @@ -388,9 +396,6 @@ OpenSeesAppInit(Tcl_Interp *interp) Tcl_CreateCommand(interp, "timer", timer, nullptr, nullptr); // File utilities - Tcl_CreateCommand(interp, "stripXML", stripOpenSeesXML, nullptr, NULL); - Tcl_CreateCommand(interp, "convertBinaryToText", convertBinaryToText, nullptr, NULL); - Tcl_CreateCommand(interp, "convertTextToBinary", convertTextToBinary, nullptr, NULL); Tcl_CreateCommand(interp, "setMaxOpenFiles", maxOpenFiles, nullptr, nullptr); // Some entry points @@ -399,13 +404,21 @@ OpenSeesAppInit(Tcl_Interp *interp) Tcl_CreateCommand(interp, "wipe", TclCommand_wipeModel, nullptr, nullptr); Tcl_CreateCommand(interp, "_clearAnalysis", TclCommand_clearAnalysis, nullptr, nullptr); + + Tcl_CreateObjCommand(interp, "pset", OPS_SetObjCmd, nullptr, nullptr); Tcl_CreateObjCommand(interp, "source", OPS_SourceCmd, nullptr, nullptr); Tcl_CreateObjCommand(interp, "pragma", TclObjCommand_pragma, nullptr, nullptr); Tcl_CreateObjCommand(interp, "progress", TclObjCommand_progress, (ClientData)&progress_bar_ptr, nullptr); - // Tcl_CreateCommand(interp, "searchPeerNGA", &peerNGA, nullptr, nullptr); - // Tcl_CreateCommand(interp, "defaultUnits", &defaultUnits, nullptr, NULL); + // + static int ncmd = sizeof(InterpreterCommands)/sizeof(char_cmd); + + for (int i = 0; i < ncmd; i++) + Tcl_CreateCommand(interp, + InterpreterCommands[i].name, + InterpreterCommands[i].func, + (ClientData) nullptr, nullptr); return TCL_OK; } diff --git a/SRC/runtime/commands/interpreter.h b/SRC/runtime/commands/interpreter.h new file mode 100644 index 0000000000..e3ddd2c8ef --- /dev/null +++ b/SRC/runtime/commands/interpreter.h @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +#include + +Tcl_CmdProc TclCommand_wipeModel; +Tcl_CmdProc TclCommand_clearAnalysis; +Tcl_CmdProc TclCommand_specifyModel; + + +// formats.cpp +Tcl_CmdProc convertBinaryToText; +Tcl_CmdProc convertTextToBinary; +Tcl_CmdProc stripOpenSeesXML; + +// domain/peri/commands.cpp +Tcl_CmdProc Tcl_Peri; + +struct char_cmd { + const char* name; Tcl_CmdProc* func; +} +const InterpreterCommands[] = { + + {"peri", Tcl_Peri}, + + {"stripXML", stripOpenSeesXML }, + {"convertBinaryToText", convertBinaryToText }, + {"convertTextToBinary", convertTextToBinary }, +}; diff --git a/SRC/runtime/commands/modeling/CMakeLists.txt b/SRC/runtime/commands/modeling/CMakeLists.txt new file mode 100644 index 0000000000..108c484f0c --- /dev/null +++ b/SRC/runtime/commands/modeling/CMakeLists.txt @@ -0,0 +1,2 @@ + +add_subdirectory(material) \ No newline at end of file diff --git a/SRC/runtime/commands/modeling/commands.h b/SRC/runtime/commands/modeling/commands.h index 9a12605603..ae18d44861 100644 --- a/SRC/runtime/commands/modeling/commands.h +++ b/SRC/runtime/commands/modeling/commands.h @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -41,6 +50,10 @@ extern Tcl_CmdProc TclCommand_addReinfLayer; // extern Tcl_CmdProc TclCommand_addRemoFiber; extern Tcl_CmdProc TclCommand_addFiber; extern Tcl_CmdProc TclCommand_addHFiber; +// +extern Tcl_CmdProc TclCommand_addYS_PlasticMaterial; +extern Tcl_CmdProc TclCommand_addYS_EvolutionModel; +extern Tcl_CmdProc TclCommand_addYieldSurface_BC; // Constraints extern Tcl_CmdProc TclCommand_addMP; @@ -66,6 +79,7 @@ extern Tcl_CmdProc TclCommand_updateMaterialStage; // UpdatedLagrange Tcl_CmdProc TclCommand_addCyclicModel; +Tcl_CmdProc TclCommand_addDamageModel; Tcl_CmdProc TclCommand_addParameter; Tcl_CmdProc TclCommand_mesh; @@ -85,10 +99,14 @@ Tcl_CmdProc TclCommand_invoke; Tcl_CmdProc TclCommand_print; Tcl_CmdProc TclCommand_classType; -struct char_cmd { +Tcl_CmdProc TclCommand_addMaterial; + +namespace OpenSees { +struct CommandTableEntry { const char* name; Tcl_CmdProc* func; -} const tcl_char_cmds[] = { +} +constexpr ModelBuilderCommands[] = { {"build", buildModel}, {"getNDM", TclCommand_getNDM}, @@ -106,12 +124,13 @@ struct char_cmd { {"fixY", TclCommand_addHomogeneousBC_Y}, {"fixZ", TclCommand_addHomogeneousBC_Z}, -// // +// {"with", TclCommand_invoke}, {"invoke", TclCommand_invoke}, // Materials & sections {"uniaxialMaterial", TclCommand_addUniaxialMaterial}, {"nDMaterial", TclCommand_addNDMaterial}, + {"material", TclCommand_addMaterial}, {"beamIntegration", TclCommand_addBeamIntegration}, {"section", TclCommand_addSection}, @@ -156,33 +175,16 @@ struct char_cmd { { "backbone", TclCommand_addHystereticBackbone}, {"frictionModel", TclCommand_addFrictionModel}, - {"cyclicModel", TclCommand_addCyclicModel}, -#if 0 - {"yieldSurface_BC", TclCommand_addYieldSurface_BC}, + {"damageModel", TclCommand_addDamageModel}, {"ysEvolutionModel", TclCommand_addYS_EvolutionModel}, + {"yieldSurface_BC", TclCommand_addYieldSurface_BC}, {"plasticMaterial", TclCommand_addYS_PlasticMaterial}, - {"limitCurve", TclCommand_addLimitCurve}, - {"damageModel", TclCommand_addDamageModel}, - {"stiffnessDegradation", TclCommand_addStiffnessDegradation}, - {"unloadingRule", TclCommand_addUnloadingRule}, - {"strengthDegradation", TclCommand_addStrengthDegradation}, - {"loadPackage", TclCommand_Package}, -#endif - -// command for elast2plast in Multi-yield plasticity, by ZHY {"updateMaterialStage", TclCommand_updateMaterialStage}, -#if 0 - {"updateMaterials", TclCommand_UpdateMaterials}, -#endif - -#if 0 -// command for updating properties of soil materials, by ZHY - {"updateParameter", TclCommand_UpdateParameter}, -#endif }; +} // namespace OpenSees Tcl_CmdProc TclCommand_Package; diff --git a/SRC/runtime/commands/modeling/constraint.cpp b/SRC/runtime/commands/modeling/constraint.cpp index 7a021110a6..a82fceac2c 100644 --- a/SRC/runtime/commands/modeling/constraint.cpp +++ b/SRC/runtime/commands/modeling/constraint.cpp @@ -1,9 +1,17 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// // #include #include @@ -15,6 +23,8 @@ #include #include +#include + #include #include #include @@ -27,64 +37,102 @@ int -TclCommand_addHomogeneousBC(ClientData clientData, Tcl_Interp *interp, int argc, +TclCommand_addHomogeneousBC(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); Domain *theTclDomain = ((BasicModelBuilder*)clientData)->getDomain(); - int ndf = argc - 2; - // check number of arguments - if (argc < (2 + ndf)) { - opserr << G3_ERROR_PROMPT << "bad command - want: fix nodeId " << ndf - << " [0,1] conditions"; + if (argc < 3) { + opserr << OpenSees::PromptValueError << "bad command - want: fix tag \n"; return TCL_ERROR; } - // get the id of the node + + // get the tag of the node int nodeId; if (Tcl_GetInt(interp, argv[1], &nodeId) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nodeId - fix nodeId " << ndf - << " [0,1] conditions\n"; + opserr << OpenSees::PromptValueError << "invalid tag\n"; return TCL_ERROR; } - char buffer[80]; - strcpy(buffer, ""); + // Alternate form: + // + // fix $node -dof $dof <-value $value> + // + if (strcmp(argv[2], "-dof") == 0) { + if (argc < 4) { + opserr << OpenSees::PromptValueError << "missing required argument for -dof $dof\n"; + return TCL_ERROR; + } + int dof; + if (Tcl_GetInt(interp, argv[3], &dof) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid dof\n"; + return TCL_ERROR; + } + // create a homogeneous constraint + SP_Constraint *theSP = new SP_Constraint(nodeId, dof-1, 0.0, true, true); + + // add it to the domain + if (theTclDomain->addSP_Constraint(theSP) == false) { + opserr << OpenSees::PromptValueError << "could not add SP_Constraint to domain using fix " + "command - node may already be constrained\n"; + delete theSP; + return TCL_ERROR; + } + + return TCL_OK; + } + + int ndf = argc - 2; + + // check number of arguments + if (argc < (2 + ndf)) { + opserr << OpenSees::PromptValueError + << "bad command - want: fix nodeId " << ndf + << " [0,1] conditions"; + return TCL_ERROR; + } // get the fixity condition and add the constraint if fixed + Tcl_Obj* list = Tcl_NewListObj(ndf, nullptr); for (int i = 0; i < ndf; ++i) { int theFixity; if (Tcl_GetInt(interp, argv[2 + i], &theFixity) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid fixity " << i + 1 << " - load " << nodeId; + opserr << OpenSees::PromptValueError << "invalid fixity " << i + 1 << " - load " << nodeId; opserr << " " << ndf << " fixities\n"; return TCL_ERROR; + } else { if (theFixity != 0) { // create a homogeneous constraint - SP_Constraint *theSP = new SP_Constraint(nodeId, i, 0.0, true); + SP_Constraint *theSP = new SP_Constraint(nodeId, i, 0.0, true, true); // add it to the domain if (theTclDomain->addSP_Constraint(theSP) == false) { - opserr << G3_ERROR_PROMPT << "could not add SP_Constraint to domain using fix " + opserr << OpenSees::PromptValueError << "could not add SP_Constraint to domain using fix " "command - node may already be constrained\n"; - sprintf(buffer, "%d ", 0); delete theSP; return TCL_ERROR; + } else { - sprintf(buffer, "%d ", theSP->getTag()); - Tcl_AppendResult(interp, buffer, NULL); +// Tcl(buffer, "%d ", theSP->getTag()); +// Tcl_AppendResult(interp, buffer, NULL); + Tcl_ListObjAppendElement(interp, list, Tcl_NewDoubleObj(theSP->getTag())); } } } } + + Tcl_SetObjResult(interp, list); + return TCL_OK; } int TclCommand_addHomogeneousBC_X(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) + Tcl_Size argc, TCL_Char ** const argv) { int ndf = argc - 2; if (strcmp(argv[argc-2],"-tol") == 0) @@ -92,7 +140,7 @@ TclCommand_addHomogeneousBC_X(ClientData clientData, Tcl_Interp *interp, // check number of arguments if (argc < (2 + ndf)) { - opserr << G3_ERROR_PROMPT << "bad command - want: fixX xLoc " << ndf + opserr << OpenSees::PromptValueError << "bad command - want: fixX xLoc " << ndf << " [0,1] conditions" << "\n"; return TCL_ERROR; } @@ -100,7 +148,7 @@ TclCommand_addHomogeneousBC_X(ClientData clientData, Tcl_Interp *interp, // get the xCrd of nodes to be constrained double xLoc; if (Tcl_GetDouble(interp, argv[1], &xLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid xCrd - fixX xLoc " << ndf + opserr << OpenSees::PromptValueError << "invalid xCrd - fixX xLoc " << ndf << " [0,1] conditions" << "\n"; return TCL_ERROR; } @@ -109,8 +157,7 @@ TclCommand_addHomogeneousBC_X(ClientData clientData, Tcl_Interp *interp, ID fixity(ndf); for (int i=0; i= (4 + ndf)) { if (strcmp(argv[2+ndf],"-tol") == 0) if (Tcl_GetDouble(interp, argv[3+ndf], &tol) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid tol specified - fixX " << xLoc << endln; + opserr << OpenSees::PromptValueError + << "invalid tol specified - fixX " << xLoc + << OpenSees::SignalMessageEnd; return TCL_ERROR; } } @@ -137,7 +186,7 @@ TclCommand_addHomogeneousBC_X(ClientData clientData, Tcl_Interp *interp, int TclCommand_addHomogeneousBC_Y(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) + Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); BasicModelBuilder *builder = static_cast(clientData); @@ -148,21 +197,22 @@ TclCommand_addHomogeneousBC_Y(ClientData clientData, Tcl_Interp *interp, // check number of arguments if (argc < (2 + ndf)) { - opserr << G3_ERROR_PROMPT << "bad command - want: fixY yLoc " << ndf << " [0,1] conditions"; + opserr << OpenSees::PromptValueError << "bad command - want: fixY yLoc " << ndf << " [0,1] conditions"; return TCL_ERROR; } // get the yCrd of nodes to be constrained double yLoc; if (Tcl_GetDouble(interp, argv[1], &yLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid yCrd - fixY yLoc " << ndf << " [0,1] conditions\n"; return TCL_ERROR; + opserr << OpenSees::PromptValueError << "invalid yCrd - fixY yLoc " << ndf << " [0,1] conditions\n"; + return TCL_ERROR; } // read in the fixities ID fixity(ndf); for (int i=0; i= (4 + ndf)) { if (strcmp(argv[2+ndf],"-tol") == 0) if (Tcl_GetDouble(interp, argv[3+ndf], &tol) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid tol specified - fixY " << yLoc << endln; + opserr << OpenSees::PromptValueError << "invalid tol specified - fixY " << yLoc << OpenSees::SignalMessageEnd; return TCL_ERROR; } } @@ -186,7 +236,7 @@ TclCommand_addHomogeneousBC_Y(ClientData clientData, Tcl_Interp *interp, int TclCommand_addHomogeneousBC_Z(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) + Tcl_Size argc, TCL_Char ** const argv) { assert(clientData != nullptr); @@ -198,21 +248,22 @@ TclCommand_addHomogeneousBC_Z(ClientData clientData, Tcl_Interp *interp, // check number of arguments if (argc < (2 + ndf)) { - opserr << G3_ERROR_PROMPT << "bad command - want: fixZ zLoc " << ndf << " [0,1] conditions"; + opserr << OpenSees::PromptValueError << "bad command - want: fixZ zLoc " << ndf << " [0,1] conditions"; return TCL_ERROR; } // get the yCrd of nodes to be constrained double zLoc; if (Tcl_GetDouble(interp, argv[1], &zLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid zCrd - fixZ zLoc " << ndf << " [0,1] conditions\n"; return TCL_ERROR; + opserr << OpenSees::PromptValueError << "invalid zCrd - fixZ zLoc " << ndf << " [0,1] conditions\n"; + return TCL_ERROR; } // read in the fixities ID fixity(ndf); for (int i=0; i= (4 + ndf)) { if (strcmp(argv[2+ndf],"-tol") == 0) if (Tcl_GetDouble(interp, argv[3+ndf], &tol) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid tol specified - fixZ " << zLoc << endln; + opserr << OpenSees::PromptValueError + << "invalid tol specified - fixZ " << zLoc + << OpenSees::SignalMessageEnd; return TCL_ERROR; } } @@ -237,25 +290,26 @@ TclCommand_addHomogeneousBC_Z(ClientData clientData, Tcl_Interp *interp, int -TclCommand_addSP(ClientData clientData, Tcl_Interp *interp, int argc, +TclCommand_addSP(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char ** const argv) { -//G3_Runtime *rt = G3_getRuntime(interp); assert(clientData != nullptr); BasicModelBuilder* builder = static_cast(clientData); Domain *theTclDomain = builder->getDomain(); if (argc > 1 && (strcmp(argv[1], "remove") == 0)) { if (argc < 3) { - opserr << G3_ERROR_PROMPT << "want - remove sp spTag? -or- remove " + opserr << OpenSees::PromptValueError + << "want - remove sp spTag? -or- remove " "sp nodeTag? dofTag? \n"; return TCL_ERROR; } int tag; if (argc == 3) { if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "remove sp tag? failed to read tag: " << argv[2] - << endln; + opserr << OpenSees::PromptValueError + << "remove sp tag? failed to read tag: " << argv[2] + << OpenSees::SignalMessageEnd; return TCL_ERROR; } SP_Constraint *theSPconstraint = theTclDomain->removeSP_Constraint(tag); @@ -267,20 +321,20 @@ TclCommand_addSP(ClientData clientData, Tcl_Interp *interp, int argc, int patternTag = -1; if (Tcl_GetInt(interp, argv[2], &nodeTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "remove sp tag? failed to read node tag: " << argv[2] - << endln; + opserr << OpenSees::PromptValueError << "remove sp tag? failed to read node tag: " << argv[2] + << OpenSees::SignalMessageEnd; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &dofTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "remove sp tag? failed to read dof tag: " << argv[3] - << endln; + opserr << OpenSees::PromptValueError << "remove sp tag? failed to read dof tag: " << argv[3] + << OpenSees::SignalMessageEnd; return TCL_ERROR; } if (argc == 5) { if (Tcl_GetInt(interp, argv[4], &patternTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "remove sp tag? failed to read pattern tag: " - << argv[4] << endln; + opserr << OpenSees::PromptValueError << "remove sp tag? failed to read pattern tag: " + << argv[4] << OpenSees::SignalMessageEnd; return TCL_ERROR; } } @@ -296,32 +350,36 @@ TclCommand_addSP(ClientData clientData, Tcl_Interp *interp, int argc, // check number of arguments if (argc < 4) { - opserr << G3_ERROR_PROMPT << "bad command - want: sp nodeId dofID value"; + opserr << OpenSees::PromptValueError + << "bad command - want: sp nodeId dofID value"; return TCL_ERROR; } // get the nodeID, dofId and value of the constraint - int nodeId, dofId; - double value; + int nodeId, dofId; if (Tcl_GetInt(interp, argv[1], &nodeId) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nodeId: " << argv[1] << " - sp nodeId dofID value\n"; + opserr << OpenSees::PromptValueError << "invalid nodeId: " << argv[1] << " - sp nodeId dofID value\n"; return TCL_ERROR; } - if (Tcl_GetInt(interp, argv[2], &dofId) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid dofId: " << argv[2] << " - sp "; + if (Tcl_GetInt(interp, argv[2], &dofId) != TCL_OK || dofId < 1) { + opserr << OpenSees::PromptValueError << "invalid dofId: " << argv[2] << " - sp "; opserr << nodeId << " dofID value\n"; return TCL_ERROR; } - dofId--; // DECREMENT THE DOF VALUE BY 1 TO GO TO OUR C++ INDEXING + // Decrement the DOF index by 1 to go to C/C++ 0-indexing + dofId--; + + double value; if (Tcl_GetDouble(interp, argv[3], &value) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid value: " << argv[3] << " - sp "; + opserr << OpenSees::PromptValueError << "invalid value: " << argv[3] << " - sp "; opserr << nodeId << " dofID value\n"; return TCL_ERROR; } bool isSpConst = false; + bool retZeroInit = true; bool userSpecifiedPattern = false; int loadPatternTag = 0; // some pattern that will never be used! @@ -330,15 +388,18 @@ TclCommand_addSP(ClientData clientData, Tcl_Interp *interp, int argc, if (strcmp(argv[endMarker],"-const") == 0) { // allow user to specify const load isSpConst = true; - - } else if (strcmp(argv[endMarker],"-pattern") == 0) { + } + else if (strcmp(argv[endMarker], "-subtractInit") == 0) { + retZeroInit = false; + } + else if (strcmp(argv[endMarker],"-pattern") == 0) { // allow user to specify load pattern other than current endMarker++; userSpecifiedPattern = true; if (endMarker == argc || Tcl_GetInt(interp, argv[endMarker], &loadPatternTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid patternTag - load " << nodeId << "\n"; + opserr << OpenSees::PromptValueError << "invalid patternTag - load " << nodeId << "\n"; return TCL_ERROR; } } @@ -348,7 +409,7 @@ TclCommand_addSP(ClientData clientData, Tcl_Interp *interp, int argc, // if load pattern tag has not changed - get the pattern tag from current one if (userSpecifiedPattern == false) { if (theTclLoadPattern == nullptr) { - opserr << G3_ERROR_PROMPT << "no current pattern - sp " + opserr << OpenSees::PromptValueError << "no current pattern - sp " << nodeId << " dofID value\n"; return TCL_ERROR; } else { @@ -359,10 +420,10 @@ TclCommand_addSP(ClientData clientData, Tcl_Interp *interp, int argc, // LoadPattern *thePattern = theTclDomain->getLoadPattern(loadPatternTag); // create a homogeneous constraint - SP_Constraint *theSP = new SP_Constraint(nodeId, dofId, value, isSpConst); + SP_Constraint *theSP = new SP_Constraint(nodeId, dofId, value, isSpConst, retZeroInit); if (theTclDomain->addSP_Constraint(theSP, loadPatternTag) == false) { - opserr << G3_ERROR_PROMPT << "could not add SP_Constraint to domain "; + opserr << OpenSees::PromptValueError << "could not add SP_Constraint to domain "; delete theSP; return TCL_ERROR; } @@ -372,7 +433,7 @@ TclCommand_addSP(ClientData clientData, Tcl_Interp *interp, int argc, int TclCommand_addEqualDOF_MP(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) + Tcl_Size argc, TCL_Char ** const argv) { BasicModelBuilder *builder = static_cast(clientData); Domain *theTclDomain = builder->getDomain(); @@ -380,7 +441,7 @@ TclCommand_addEqualDOF_MP(ClientData clientData, Tcl_Interp *interp, // Check number of arguments if (argc < 4) { - opserr << G3_ERROR_PROMPT << "bad command - want: equalDOF RnodeID? CnodeID? DOF1? DOF2? ..."; + opserr << OpenSees::PromptValueError << "bad command - want: equalDOF RnodeID? CnodeID? DOF1? DOF2? ..."; return TCL_ERROR; } @@ -388,12 +449,12 @@ TclCommand_addEqualDOF_MP(ClientData clientData, Tcl_Interp *interp, int RnodeID, CnodeID, dofID; if (Tcl_GetInt(interp, argv[1], &RnodeID) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid RnodeID: " << argv[1] + opserr << OpenSees::PromptValueError << "invalid RnodeID: " << argv[1] << " equalDOF RnodeID? CnodeID? DOF1? DOF2? ..."; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &CnodeID) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid CnodeID: " << argv[2] + opserr << OpenSees::PromptValueError << "invalid CnodeID: " << argv[2] << " equalDOF RnodeID? CnodeID? DOF1? DOF2? ..."; return TCL_ERROR; } @@ -412,14 +473,14 @@ TclCommand_addEqualDOF_MP(ClientData clientData, Tcl_Interp *interp, // Read the degrees of freedom which are to be coupled for (i = 3, j = 0; i < argc; i++, j++) { if (Tcl_GetInt(interp, argv[i], &dofID) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid dofID: " << argv[3] + opserr << OpenSees::PromptValueError << "invalid dofID: " << argv[3] << " equalDOF RnodeID? CnodeID? DOF1? DOF2? ..."; return TCL_ERROR; } dofID -= 1; // Decrement for C++ indexing if (dofID < 0) { - opserr << G3_ERROR_PROMPT << "invalid dofID: " << argv[i] + opserr << OpenSees::PromptValueError << "invalid dofID: " << argv[i] << " must be >= 1"; return TCL_ERROR; } @@ -432,7 +493,7 @@ TclCommand_addEqualDOF_MP(ClientData clientData, Tcl_Interp *interp, // Add the multi-point constraint to the domain if (theTclDomain->addMP_Constraint(theMP) == false) { - opserr << G3_ERROR_PROMPT << "could not add equalDOF MP_Constraint to domain "; + opserr << OpenSees::PromptValueError << "could not add equalDOF MP_Constraint to domain "; delete theMP; return TCL_ERROR; } @@ -440,114 +501,21 @@ TclCommand_addEqualDOF_MP(ClientData clientData, Tcl_Interp *interp, return TCL_OK; } -#if 0 -int -TclCommand_addEqualDOF_MP_Mixed(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) -{ - // Ensure the destructor has not been called - BasicModelBuilder *builder = static_cast(clientData); - - if (theTclBuilder == 0 || clientData == 0) { - opserr << G3_ERROR_PROMPT << "builder has been destroyed - equalDOF \n"; - return TCL_ERROR; - } - - // Check number of arguments - if (argc < 4) { - opserr << G3_ERROR_PROMPT << "bad command - want: equalDOFmixed RnodeID? CnodeID? numDOF? RDOF1? CDOF1? ... ..."; - return TCL_ERROR; - } - - // Read in the node IDs and the DOF - int RnodeID, CnodeID, dofIDR, dofIDC, numDOF; - - if (Tcl_GetInt(interp, argv[1], &RnodeID) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid RnodeID: " << argv[1] - << " equalDOF RnodeID? CnodeID? numDOF? RDOF1? CDOF1? ..."; - return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[2], &CnodeID) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid CnodeID: " << argv[2] - << " equalDOF RnodeID? CnodeID? numDOF? RDOF1? CDOF1? ..."; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &numDOF) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid numDOF: " << argv[2] - << " equalDOF RnodeID? CnodeID? numDOF? RDOF1? CDOF1? ..."; - return TCL_ERROR; - } - - // The number of DOF to be coupled - // int numDOF = argc - 3; - - // The constraint matrix ... U_c = C_cr * U_r - Matrix Ccr (numDOF, numDOF); - Ccr.Zero(); - - // The vector containing the retained and constrained DOFs - ID rDOF (numDOF); - ID cDOF (numDOF); - - int i, j, k; - // Read the degrees of freedom which are to be coupled - for (i = 4, j = 5, k = 0; k < numDOF; i+=2, j+=2, k++) { - if (Tcl_GetInt(interp, argv[i], &dofIDR) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid dofID: " << argv[3] - << " equalDOF RnodeID? CnodeID? DOF1? DOF2? ..."; - return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[j], &dofIDC) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid dofID: " << argv[3] - << " equalDOF RnodeID? CnodeID? DOF1? DOF2? ..."; - return TCL_ERROR; - } - - dofIDR -= 1; // Decrement for 0-based indexing - dofIDC -= 1; - if (dofIDC < 0 || dofIDR < 0) { - opserr << G3_ERROR_PROMPT << "invalid dofID: " << argv[i] - << " must be >= 1"; - return TCL_ERROR; - } - rDOF(k) = dofIDR; - cDOF(k) = dofIDC; - Ccr(k,k) = 1.0; - } - - // Create the multi-point constraint - MP_Constraint *theMP = new MP_Constraint (RnodeID, CnodeID, Ccr, cDOF, rDOF); - - // Add the multi-point constraint to the domain - if (theTclDomain->addMP_Constraint (theMP) == false) { - opserr << G3_ERROR_PROMPT << "could not add equalDOF MP_Constraint to domain "; - delete theMP; - return TCL_ERROR; - } - - Tcl_SetObjResult(interp, Tcl_NewIntObj(theMP->getTag())); - return TCL_OK; -} -#endif - - int TclCommand_addImposedMotionSP(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) + Tcl_Size argc, TCL_Char ** const argv) { // TODO: Cleanup G3_Runtime* rt = G3_getRuntime(interp); Domain *domain = G3_getDomain(rt); // BasicModelBuilder *theTclBuilder = G3_getSafeBuilder(G3_getRuntime(interp)); - // // ensure the destructor has not been called - // BasicModelBuilder *builder = static_cast(clientData); // check number of arguments if (argc < 4) { - opserr << G3_ERROR_PROMPT << "bad command - want: imposedMotion nodeId dofID gMotionID\n"; + opserr << OpenSees::PromptValueError << "bad command - want: imposedMotion nodeId dofID gMotionID\n"; return TCL_ERROR; } @@ -555,20 +523,20 @@ TclCommand_addImposedMotionSP(ClientData clientData, Tcl_Interp *interp, int nodeId, dofId, gMotionID; if (Tcl_GetInt(interp, argv[1], &nodeId) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nodeId: " << argv[1] + opserr << OpenSees::PromptValueError << "invalid nodeId: " << argv[1] << " - imposedMotion nodeId dofID gMotionID" << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &dofId) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid dofId: " << argv[2] + opserr << OpenSees::PromptValueError << "invalid dofId: " << argv[2] << " - imposedMotion " << nodeId << " dofID gMotionID\n"; return TCL_ERROR; } dofId--; // DECREMENT THE DOF VALUE BY 1 TO GO TO OUR C++ INDEXING if (Tcl_GetInt(interp, argv[3], &gMotionID) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gMotionID: " << argv[3] << " - imposedMotion "; + opserr << OpenSees::PromptValueError << "invalid gMotionID: " << argv[3] << " - imposedMotion "; opserr << nodeId << " dofID gMotionID\n"; return TCL_ERROR; } @@ -582,16 +550,15 @@ TclCommand_addImposedMotionSP(ClientData clientData, Tcl_Interp *interp, // // check valid node & dof // - Node *theNode = domain->getNode(nodeId); if (theNode == nullptr) { - opserr << G3_ERROR_PROMPT << "invalid node " << argv[2] << " node not found\n "; + opserr << OpenSees::PromptValueError << "invalid node " << argv[2] << " node not found\n "; return -1; } int nDof = theNode->getNumberDOF(); if (dofId < 0 || dofId >= nDof) { - opserr << G3_ERROR_PROMPT << "invalid dofId: " << argv[2] << " dof specified cannot be <= 0 or greater than num dof at nod\n "; + opserr << OpenSees::PromptValueError << "invalid dofId: " << argv[2] << " dof specified cannot be <= 0 or greater than num dof at nod\n "; return -2; } @@ -613,7 +580,7 @@ TclCommand_addImposedMotionSP(ClientData clientData, Tcl_Interp *interp, } if (thePattern->addSP_Constraint(theSP) == false) { - opserr << G3_ERROR_PROMPT << "could not add SP_Constraint to pattern "; + opserr << OpenSees::PromptValueError << "could not add SP_Constraint to pattern "; delete theSP; return TCL_ERROR; } diff --git a/SRC/runtime/commands/modeling/element.cpp b/SRC/runtime/commands/modeling/element.cpp index d15c5f7ba2..4be3402ba3 100644 --- a/SRC/runtime/commands/modeling/element.cpp +++ b/SRC/runtime/commands/modeling/element.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -11,7 +20,7 @@ #include #include -#ifdef _MSC_VER +#ifdef _MSC_VER # include # define strcasecmp _stricmp #else @@ -22,8 +31,7 @@ #include #include -#include -#include +#include #include #include #include @@ -53,20 +61,9 @@ extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, Tcl_Interp *interp // // THE PROTOTYPES OF THE FUNCTIONS INVOKED BY THE INTERPRETER // - -#if 0 // cmp - commented out to eliminate use of TclBasicBuilder -extern int TclBasicBuilder_addFeapTruss(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv, Domain *, TclBasicBuilder *, int argStart); -extern int Tcl_addWrapperElement(eleObj *, ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv, Domain *, TclBuilder *); -// Added by Quan Gu and Yongdou Liu, et al. on 2018/10/31 (Xiamen University) -#endif static Tcl_CmdProc TclBasicBuilder_addWheelRail; - -extern OPS_Routine OPS_ElasticBeam3d; -extern void *OPS_ElasticBeam2d(G3_Runtime *, const ID &); - - // Frame Tcl_CmdProc TclBasicBuilder_addElasticBeam; Tcl_CmdProc TclBasicBuilder_addGradientInelasticBeamColumn; @@ -109,20 +106,8 @@ G3_TclElementCommand TclBasicBuilder_addMasonPan12; G3_TclElementCommand TclBasicBuilder_addMasonPan3D; G3_TclElementCommand TclBasicBuilder_addBeamGT; - - - // Shells -Element* TclDispatch_newASDShellQ4(ClientData, Tcl_Interp*, int, TCL_Char** const); Element* TclDispatch_newShellANDeS(ClientData, Tcl_Interp*, int, TCL_Char** const); -Element* TclDispatch_newShellDKGQ(ClientData, Tcl_Interp*, int, TCL_Char** const); -Element* TclDispatch_newShellDKGT(ClientData, Tcl_Interp*, int, TCL_Char** const); -Element* TclDispatch_newShellMITC4(ClientData, Tcl_Interp*, int, TCL_Char** const); -Element* TclDispatch_newShellMITC4Thermal(ClientData, Tcl_Interp*, int, TCL_Char** const); -Element* TclDispatch_newShellMITC9(ClientData, Tcl_Interp*, int, TCL_Char** const); -Element* TclDispatch_newShellNLDKGQ(ClientData, Tcl_Interp*, int, TCL_Char** const); -Element* TclDispatch_newShellNLDKGQThermal(ClientData, Tcl_Interp*, int, TCL_Char** const); -Element* TclDispatch_newShellNLDKGT(ClientData, Tcl_Interp*, int, TCL_Char** const); @@ -138,10 +123,10 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C OPS_ResetInputNoBuilder(clientData, interp, 2, argc, argv, theTclDomain); - // check at least two arguments so don't segemnt fault on strcmp if (argc < 2) { - opserr << G3_ERROR_PROMPT << "insufficient arguments, expected:\n"; - opserr << " element eleType .. \n"; + opserr << OpenSees::PromptValueError + << "Missing element type" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -160,14 +145,6 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C return (*tcl_cmd->second)(clientData, interp, argc, &argv[0]); } - if (strcasecmp(argv[1], "truss") == 0) { - theEle = OPS_TrussElement(rt, argc, argv); - - // for backward compatibility - if (theEle == nullptr) - theEle = OPS_TrussSectionElement(rt, argc, argv); - } - else if ((strcasecmp(argv[1], "elasticBeamColumn") == 0) || (strcasecmp(argv[1], "elasticBeam") == 0) || (strcasecmp(argv[1], "PrismFrame") == 0)) { @@ -180,26 +157,10 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C theEle = OPS_PML2D(rt, argc, argv); else theEle = OPS_PML3D(rt, argc, argv); - -#if 0 - } else if (strcmp(argv[1], "gradientInelasticBeamColumn") == 0) { - - Element *theEle = 0; - if (ndm == 2) - theEle = OPS_GradientInelasticBeamColumn2d(rt, argc, argv); - else - theEle = OPS_GradientInelasticBeamColumn3d(rt, argc, argv); - - if (theEle != 0) - theElement = theEle; - else { - return TCL_ERROR; - } - } -#endif + } #if defined(_HAVE_LHNMYS) || defined(OPSDEF_ELEMENT_LHNMYS) - } else if (strcmp(argv[1], "beamColumn2DwLHNMYS") == 0) { + else if (strcmp(argv[1], "beamColumn2DwLHNMYS") == 0) { theEle = OPS_BeamColumn2DwLHNMYS(rt, argc, argv); } else if (strcmp(argv[1], "beamColumn2dDamage") == 0) { @@ -210,9 +171,10 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C } else if (strcmp(argv[1], "beamColumn3DwLHNMYS") == 0) { theEle = OPS_BeamColumn3DwLHNMYS(rt, argc, argv); + } #endif - } else if (strcmp(argv[1], "ElasticTimoshenkoBeam") == 0) { + else if (strcmp(argv[1], "ElasticTimoshenkoBeam") == 0) { if (ndm == 2) theEle = OPS_ElasticTimoshenkoBeam2d(rt, argc, argv); else @@ -233,14 +195,6 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C theEle = OPS_TFP_Bearing(rt, argc, argv); } - else if (strcasecmp(argv[1], "CorotTruss") == 0) { - theEle = OPS_CorotTrussElement(rt, argc, argv); - - // for backward compatibility - if (theEle == nullptr) - theEle = OPS_CorotTrussSectionElement(rt, argc, argv); - } - else if ((strcmp(argv[1], "MultiFP2d") == 0) || (strcmp(argv[1], "MultiFPB2d") == 0)) { @@ -282,10 +236,6 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C interp, argc, argv); -// if (ndm == 2) -// theEle = OPS_FlatSliderSimple2d(rt, argc, argv); -// else -// theEle = OPS_FlatSliderSimple3d(rt, argc, argv); } else if (strcmp(argv[1], "SingleFPBearing") == 0 || @@ -296,80 +246,25 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C interp, argc, argv); -// if (ndm == 2) -// theEle = OPS_SingleFPSimple2d(rt, argc, argv); -// else -// theEle = OPS_SingleFPSimple3d(rt, argc, argv); - } - - // Xinlong Du - else if ((strcmp(argv[1], "DispBeamColumnAsym") == 0) || - (strcmp(argv[1], "DispBeamAsym")) == 0) { - if (ndm == 3) - theEle = OPS_DispBeamColumnAsym3dTcl(rt, argc, argv); } - else if ((strcmp(argv[1], "MixedBeamColumnAsym") == 0) || - (strcmp(argv[1], "MixedBeamAsym") == 0)) { - - if (ndm == 3) - theEle = OPS_MixedBeamColumnAsym3dTcl(rt, argc, argv); - } - // Xinlong Du // // Shells // - else if ((strcmp(argv[1], "Shell") == 0) || - (strcmp(argv[1], "ShellMITC4") == 0)) { - theEle = TclDispatch_newShellMITC4(clientData, interp, argc, argv); - } - - else if (strcmp(argv[1], "ShellMITC4Thermal") == 0) { - theEle = TclDispatch_newShellMITC4Thermal(clientData, interp, argc, argv); - } - - else if (strcmp(argv[1], "ShellNLDKGQThermal") == 0) { - theEle = TclDispatch_newShellNLDKGQThermal(clientData, interp, argc, argv); - } - - else if ((strcmp(argv[1], "ShellNL") == 0) || - (strcmp(argv[1], "ShellMITC9") == 0)) { - theEle = TclDispatch_newShellMITC9(clientData, interp, argc, argv); - } - - else if ((strcmp(argv[1], "shellDKGQ") == 0) || - (strcmp(argv[1], "ShellDKGQ") == 0)) { - theEle = TclDispatch_newShellDKGQ(clientData, interp, argc, argv); - } - - else if (strcmp(argv[1], "ShellNLDKGQ") == 0) { - theEle = TclDispatch_newShellNLDKGQ(clientData, interp, argc, argv); - } - - else if (strcmp(argv[1], "ShellDKGT") == 0) { - theEle = TclDispatch_newShellDKGT(clientData, interp, argc, argv); - } - - else if (strcmp(argv[1], "ShellNLDKGT") == 0) { - theEle = TclDispatch_newShellNLDKGT(clientData, interp, argc, argv); - } - - else if (strcmp(argv[1], "ASDShellQ4") == 0) { - theEle = TclDispatch_newASDShellQ4(clientData, interp, argc, argv); - } else if (strcmp(argv[1], "ShellANDeS") == 0) { theEle = TclDispatch_newShellANDeS(clientData, interp, argc, argv); } + // if one of the above worked theElement = (Element*)theEle; if (theElement != nullptr) { if (theTclDomain->addElement(theElement) == false) { - opserr << "WARNING could not add element of with tag: " + opserr << OpenSees::PromptValueError << "could not add element of with tag: " << theElement->getTag() << " and of type: " << theElement->getClassType() << " to the Domain\n"; @@ -379,7 +274,7 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C return TCL_OK; } -#if 0 && defined(OPSDEF_ELEMENT_FEAP) +#if defined(OPSDEF_ELEMENT_FEAP) if (strcmp(argv[1], "fTruss") == 0) { int eleArgStart = 1; int result = TclBasicBuilder_addFeapTruss( @@ -400,26 +295,28 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C return TclBasicBuilder_addWheelRail(clientData, interp, argc, argv); } - else if (strcmp(argv[1], "DisplFrame") == 0 || - strcmp(argv[1], "CubicFrame") == 0 || - strcmp(argv[1], "ForceFrame") == 0 || - strcmp(argv[1], "ExactFrame") == 0 || - strcmp(argv[1], "ForceDeltaFrame") == 0 || - - strcmp(argv[1], "ForceBeamColumn") == 0 || - strcmp(argv[1], "DispBeamColumn") == 0 || - strcmp(argv[1], "DispBeamColumn") == 0 || - strcmp(argv[1], "TimoshenkoBeamColumn") == 0 || - strcmp(argv[1], "ForceBeamColumnCBDI") == 0 || - strcmp(argv[1], "ForceBeamColumnCSBDI") == 0 || - strcmp(argv[1], "ForceBeamColumnWarping") == 0 || - strcmp(argv[1], "ForceBeamColumnThermal") == 0 || - strcmp(argv[1], "ElasticForceBeamColumnWarping") == 0 || - strcmp(argv[1], "DispBeamColumnNL") == 0 || - strcmp(argv[1], "DispBeamColumnThermal") == 0 || - strcmp(argv[1], "ElasticForceBeamColumn") == 0 || - strcmp(argv[1], "NonlinearBeamColumn") == 0 || - strcmp(argv[1], "DispBeamColumnWithSensitivity") == 0) { + else if (strcasecmp(argv[1], "DisplFrame") == 0 || + strcasecmp(argv[1], "CubicFrame") == 0 || + strcasecmp(argv[1], "EulerFrame") == 0 || + strcasecmp(argv[1], "ForceFrame") == 0 || + strcasecmp(argv[1], "MixedFrame") == 0 || + strcasecmp(argv[1], "ExactFrame") == 0 || + strcasecmp(argv[1], "ForceDeltaFrame") == 0 || + + strcasecmp(argv[1], "ForceBeamColumn") == 0 || + strcasecmp(argv[1], "DispBeamColumn") == 0 || + strcasecmp(argv[1], "DispBeamColumn") == 0 || + strcasecmp(argv[1], "TimoshenkoBeamColumn") == 0 || + strcasecmp(argv[1], "ForceBeamColumnCBDI") == 0 || + strcasecmp(argv[1], "ForceBeamColumnCSBDI") == 0 || + strcasecmp(argv[1], "ForceBeamColumnWarping") == 0 || + strcasecmp(argv[1], "ForceBeamColumnThermal") == 0 || + strcasecmp(argv[1], "ElasticForceBeamColumnWarping") == 0 || + strcasecmp(argv[1], "DispBeamColumnNL") == 0 || + strcasecmp(argv[1], "DispBeamColumnThermal") == 0 || + strcasecmp(argv[1], "ElasticForceBeamColumn") == 0 || + strcasecmp(argv[1], "nonlinearBeamColumn") == 0 || + strcasecmp(argv[1], "DispBeamColumnWithSensitivity") == 0) { return TclBasicBuilder_addForceBeamColumn(clientData, interp, argc, argv); @@ -427,11 +324,7 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C (strcmp(argv[1], "BeamWithHinges") == 0)) { return TclBasicBuilder_addBeamWithHinges(clientData, interp, argc, argv); - // - // -// -// Brick -// + // // Zero-Length // @@ -442,11 +335,11 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C return TclCommand_addZeroLengthSection(clientData, interp, argc, argv); } else if (strcmp(argv[1], "zeroLengthRocking") == 0) { - int result = TclCommand_addZeroLengthRocking(clientData, interp, argc, argv); - return result; + return TclCommand_addZeroLengthRocking(clientData, interp, argc, argv); + } else if (strcmp(argv[1], "zeroLengthContact2D") == 0) { - int result = TclCommand_addZeroLengthContact2D(clientData, interp, argc, argv); - return result; + return TclCommand_addZeroLengthContact2D(clientData, interp, argc, argv); + } else if (strcmp(argv[1], "zeroLengthContact3D") == 0) { return TclCommand_addZeroLengthContact3D(clientData, interp, argc, argv); @@ -500,9 +393,7 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C else if ((strcmp(argv[1], "multipleNormalSpring") == 0) || (strcmp(argv[1], "MNS") == 0)) { - int result = TclBasicBuilder_addMultipleNormalSpring( - clientData, interp, argc, argv, theTclDomain, theTclBuilder); - return result; + return TclBasicBuilder_addMultipleNormalSpring(clientData, interp, argc, argv, theTclDomain, theTclBuilder); } else if (strcmp(argv[1], "KikuchiBearing") == 0) { @@ -510,15 +401,12 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C } else if (strcmp(argv[1], "YamamotoBiaxialHDR") == 0) { - int result = TclBasicBuilder_addYamamotoBiaxialHDR( - clientData, interp, argc, argv, theTclDomain, theTclBuilder); - return result; + return TclBasicBuilder_addYamamotoBiaxialHDR(clientData, interp, argc, argv, theTclDomain, theTclBuilder); } // MSN else if (strcmp(argv[1], "gradientInelasticBeamColumn") == 0) { - int result = TclBasicBuilder_addGradientInelasticBeamColumn(clientData, interp, argc, argv); - return result; + return TclBasicBuilder_addGradientInelasticBeamColumn(clientData, interp, argc, argv); } else { @@ -551,28 +439,7 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C } else eleCommands = eleCommands->next; } -#if 0 - // - // maybe element in a routine, check existing ones or try loading new ones - // - - char *eleType = new char[strlen(argv[1]) + 1]; - strcpy(eleType, argv[1]); - eleObj *eleObject = OPS_GetElementType(eleType, (int)strlen(eleType)); - - delete[] eleType; - - if (eleObject != 0) { - - int result = Tcl_addWrapperElement(eleObject, clientData, interp, argc, argv, - theTclDomain, theTclBuilder); - if (result != 0) - delete eleObject; - else - return result; - } -#endif // // try loading new dynamic library containing a C++ class // @@ -585,7 +452,7 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C strcpy(&tclFuncName[4], argv[1]); - opserr << "checking library: " << tclFuncName << endln; + opserr << "checking library: " << tclFuncName << OpenSees::SignalMessageEnd; int res = getLibraryFunction(argv[1], tclFuncName, &libHandle, (void **)&funcPtr); @@ -621,7 +488,7 @@ TclCommand_addElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_C } // If we get here, the element type is unknown - opserr << "ERROR -- element of type " << argv[1] << " not known" << endln; + opserr << "ERROR -- element of type " << argv[1] << " not known" << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -634,7 +501,7 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp BasicModelBuilder *builder = static_cast(clientData); if (builder == 0 || clientData == 0) { - opserr << "WARNING builder has been destroyed - multipleShearSpring\n"; + opserr << OpenSees::PromptValueError << "builder has been destroyed - multipleShearSpring\n"; return TCL_ERROR; } @@ -643,10 +510,10 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp int ndf = builder->getNDF(); if (ndm != 3 || ndf != 6) { - opserr << "ndm=" << ndm << ", ndf=" << ndf << endln; - opserr << "WARNING multipleShearSpring command only works when ndm is 3 " + opserr << "ndm=" << ndm << ", ndf=" << ndf << OpenSees::SignalMessageEnd; + opserr << OpenSees::PromptValueError << "multipleShearSpring command only works when ndm is 3 " "and ndf is 6" - << endln; + << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -680,29 +547,29 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp if (argc < 8) { // element multipleShearSpring eleTag? iNode? jNode? nSpring? // -mat matTag? - opserr << "WARNING insufficient arguments\n"; + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; ifNoError = false; } else { // argv[2~5] if (Tcl_GetInt(interp, argv[2], &eleTag) != TCL_OK) { - opserr << "WARNING invalid multipleShearSpring eleTag\n"; + opserr << OpenSees::PromptValueError << "invalid multipleShearSpring eleTag\n"; ifNoError = false; } if (Tcl_GetInt(interp, argv[3], &iNode) != TCL_OK) { - opserr << "WARNING invalid iNode\n"; + opserr << OpenSees::PromptValueError << "invalid iNode\n"; ifNoError = false; } if (Tcl_GetInt(interp, argv[4], &jNode) != TCL_OK) { - opserr << "WARNING invalid jNode\n"; + opserr << OpenSees::PromptValueError << "invalid jNode\n"; ifNoError = false; } if (Tcl_GetInt(interp, argv[5], &nSpring) != TCL_OK || nSpring <= 0) { - opserr << "WARNING invalid nSpring\n"; + opserr << OpenSees::PromptValueError << "invalid nSpring\n"; ifNoError = false; } @@ -715,15 +582,12 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp (i + 1) <= (argc - 1)) { // -mat matTag? if (Tcl_GetInt(interp, argv[i + 1], &matTag) != TCL_OK) { - opserr << "WARNING invalid matTag\n"; + opserr << OpenSees::PromptValueError << "invalid matTag\n"; ifNoError = false; } material = builder->getTypedObject(matTag); - if (material == 0) { - opserr << "WARNING material model not found\n"; - opserr << "uniaxialMaterial: " << matTag << endln; - opserr << "multipleShearSpring element: " << eleTag << endln; + if (material == nullptr) { return TCL_ERROR; } @@ -736,15 +600,15 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp theMaterials = new UniaxialMaterial *[nSpring]; for (int j = 0; j < nSpring; j++) { if (Tcl_GetInt(interp, argv[j + i + 1], &matTag) != TCL_OK) { - opserr << "WARNING invalid matTag\n"; + opserr << OpenSees::PromptValueError << "invalid matTag\n"; ifNoError = false; } theMaterials[j] = builder->getTypedObject(matTag); if (theMaterials[j] == 0) { - opserr << "WARNING material model not found\n"; - opserr << "uniaxialMaterial: " << matTag << endln; - opserr << "multipleShearSpring element: " << eleTag << endln; + opserr << OpenSees::PromptValueError << "material model not found\n"; + opserr << "uniaxialMaterial: " << matTag << OpenSees::SignalMessageEnd; + opserr << "multipleShearSpring element: " << eleTag << OpenSees::SignalMessageEnd; return TCL_ERROR; } } @@ -759,7 +623,7 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp for (int j = 1; j <= 3; j++) { if (Tcl_GetDouble(interp, argv[i + j], &value) != TCL_OK) { - opserr << "WARNING invalid -orient value\n"; + opserr << OpenSees::PromptValueError << "invalid -orient value\n"; ifNoError = false; } else { oriX(j - 1) = value; @@ -770,7 +634,7 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp for (int j = 1; j <= 3; j++) { if (Tcl_GetDouble(interp, argv[i + j], &value) != TCL_OK) { - opserr << "WARNING invalid -orient value\n"; + opserr << OpenSees::PromptValueError << "invalid -orient value\n"; ifNoError = false; } else { oriYp(j - 1) = value; @@ -784,7 +648,7 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp for (int j = 1; j <= 3; j++) { if (Tcl_GetDouble(interp, argv[i + j], &value) != TCL_OK) { - opserr << "WARNING invalid -orient value\n"; + opserr << OpenSees::PromptValueError << "invalid -orient value\n"; ifNoError = false; } else { oriYp(j - 1) = value; @@ -797,7 +661,7 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp // <-mass m?> if (Tcl_GetDouble(interp, argv[i + 1], &mass) != TCL_OK || mass <= 0) { - opserr << "WARNING invalid mass\n"; + opserr << OpenSees::PromptValueError << "invalid mass\n"; ifNoError = false; } @@ -807,7 +671,7 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp // <-lim limDisp?> if (Tcl_GetDouble(interp, argv[i + 1], &limDisp) != TCL_OK || limDisp < 0) { - opserr << "WARNING invalid limDisp\n"; + opserr << OpenSees::PromptValueError << "invalid limDisp\n"; ifNoError = false; } @@ -815,7 +679,7 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp } else { // invalid option - opserr << "WARNING invalid optional arguments \n"; + opserr << OpenSees::PromptValueError << "invalid optional arguments \n"; ifNoError = false; break; } @@ -825,7 +689,7 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp // confirm material if (recvMat != 1) { - opserr << "WARNING wrong number of -mat inputs\n"; + opserr << OpenSees::PromptValueError << "wrong number of -mat inputs\n"; opserr << "got " << recvMat << " inputs, but want 1 input\n"; ifNoError = false; } @@ -850,8 +714,8 @@ TclBasicBuilder_addMultipleShearSpring(ClientData clientData, Tcl_Interp *interp // then add the multipleShearSpring to the domain if (theTclDomain->addElement(theElement) == false) { - opserr << "WARNING could not add element to the domain\n"; - opserr << "multipleShearSpring element: " << eleTag << endln; + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + opserr << "multipleShearSpring element: " << eleTag << OpenSees::SignalMessageEnd; delete theElement; return TCL_ERROR; } @@ -866,15 +730,16 @@ errDetected(bool ifNoError, const char *msg) { if (ifNoError) { - opserr << "" << endln; - opserr << "========================================" << endln; - opserr << " element : input error detected" << endln; - opserr << "------------------------------" << endln; + opserr << "" << OpenSees::SignalMessageEnd; + opserr << "========================================" << OpenSees::SignalMessageEnd; + opserr << " element : input error detected" << OpenSees::SignalMessageEnd; + opserr << "------------------------------" << OpenSees::SignalMessageEnd; } - opserr << " " << msg << endln; + opserr << " " << msg << OpenSees::SignalMessageEnd; return false; }; + int TclBasicBuilder_addMultipleNormalSpring(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv, @@ -889,10 +754,9 @@ TclBasicBuilder_addMultipleNormalSpring(ClientData clientData, Tcl_Interp *inter int ndf = builder->getNDF(); if (ndm != 3 || ndf != 6) { - opserr << "ndm=" << ndm << ", ndf=" << ndf << endln; - opserr << "WARNING multipleNormalSpring command only works when ndm is 3 " + opserr << OpenSees::PromptValueError << "multipleNormalSpring command only works when ndm is 3 " "and ndf is 6" - << endln; + << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -1131,7 +995,7 @@ TclBasicBuilder_addMultipleNormalSpring(ClientData clientData, Tcl_Interp *inter opserr << "Want: element multipleNormalSpring eleTag? iNode? jNode? " "\n nDivide? -mat matTag? -shape shape? -size size? <-lambda " "\n lambda?> <-orient yp1? yp2? yp3?> <-mass m?>\n"; - opserr << "" << endln; + opserr << "" << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -1141,8 +1005,8 @@ TclBasicBuilder_addMultipleNormalSpring(ClientData clientData, Tcl_Interp *inter // then add the multipleNormalSpring to the domain if (theTclDomain->addElement(theElement) == false) { - opserr << "WARNING could not add element to the domain\n"; - opserr << "multipleNormalSpring element: " << eleTag << endln; + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + opserr << "multipleNormalSpring element: " << eleTag << OpenSees::SignalMessageEnd; delete theElement; return TCL_ERROR; } @@ -1164,10 +1028,10 @@ TclBasicBuilder_addKikuchiBearing(ClientData clientData, Tcl_Interp *interp, int ndf = builder->getNDF(); if (ndm != 3 || ndf != 6) { - opserr << "ndm=" << ndm << ", ndf=" << ndf << endln; - opserr << "WARNING KikuchiBearing command only works when ndm is 3 and ndf " + opserr << "ndm=" << ndm << ", ndf=" << ndf << OpenSees::SignalMessageEnd; + opserr << OpenSees::PromptValueError << "KikuchiBearing command only works when ndm is 3 and ndf " "is 6" - << endln; + << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -1618,7 +1482,7 @@ TclBasicBuilder_addKikuchiBearing(ClientData clientData, Tcl_Interp *interp, "yp3?> <-mass m?>\n"; opserr << " <-noPDInput> <-noTilt> " "<-adjustPDOutput ci? cj?> <-doBalance limFo? limFi? nIter?>\n"; - opserr << "" << endln; + opserr << "" << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -1630,8 +1494,8 @@ TclBasicBuilder_addKikuchiBearing(ClientData clientData, Tcl_Interp *interp, // then add the KikuchiBearing to the domain if (builder->getDomain()->addElement(theElement) == false) { - opserr << "WARNING could not add element to the domain\n"; - opserr << "KikuchiBearing element: " << eleTag << endln; + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + opserr << "KikuchiBearing element: " << eleTag << OpenSees::SignalMessageEnd; delete theElement; return TCL_ERROR; } @@ -1655,9 +1519,9 @@ TclBasicBuilder_addYamamotoBiaxialHDR(ClientData clientData, Tcl_Interp *interp, int ndf = builder->getNDF(); if (ndm != 3 || ndf != 6) { - opserr << "ndm=" << ndm << ", ndf=" << ndf << endln; - opserr << "WARNING YamamotoBiaxialHDR command only works when ndm is 3 and " - "ndf is 6" << endln; + opserr << "ndm=" << ndm << ", ndf=" << ndf << OpenSees::SignalMessageEnd; + opserr << OpenSees::PromptValueError << "YamamotoBiaxialHDR command only works when ndm is 3 and " + "ndf is 6" << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -1688,25 +1552,25 @@ TclBasicBuilder_addYamamotoBiaxialHDR(ClientData clientData, Tcl_Interp *interp, if (argc < 9) { // element YamamotoBiaxialHDR eleTag? iNode? jNode? Tp? DDo? DDi? Hr? - opserr << "WARNING insufficient arguments\n"; + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; ifNoError = false; } else { // argv[2~8] if (Tcl_GetInt(interp, argv[2], &eleTag) != TCL_OK) { - opserr << "WARNING invalid YamamotoBiaxialHDR eleTag\n"; + opserr << OpenSees::PromptValueError << "invalid YamamotoBiaxialHDR eleTag\n"; ifNoError = false; } // iNode if (Tcl_GetInt(interp, argv[3], &iNode) != TCL_OK) { - opserr << "WARNING invalid iNode\n"; + opserr << OpenSees::PromptValueError << "invalid iNode\n"; ifNoError = false; } // jNode if (Tcl_GetInt(interp, argv[4], &jNode) != TCL_OK) { - opserr << "WARNING invalid jNode\n"; + opserr << OpenSees::PromptValueError << "invalid jNode\n"; ifNoError = false; } @@ -1714,25 +1578,25 @@ TclBasicBuilder_addYamamotoBiaxialHDR(ClientData clientData, Tcl_Interp *interp, if (strcmp(argv[5], "1") == 0) { Tp = 1; // Bridgestone X0.6R (EESD version) } else { - opserr << "WARNING invalid YamamotoBiaxialHDR Tp" << endln; + opserr << OpenSees::PromptValueError << "invalid YamamotoBiaxialHDR Tp" << OpenSees::SignalMessageEnd; ifNoError = false; } // DDo if (Tcl_GetDouble(interp, argv[6], &DDo) != TCL_OK || DDo <= 0.0) { - opserr << "WARNING invalid YamamotoBiaxialHDR DDo" << endln; + opserr << OpenSees::PromptValueError << "invalid YamamotoBiaxialHDR DDo" << OpenSees::SignalMessageEnd; ifNoError = false; } // DDi if (Tcl_GetDouble(interp, argv[7], &DDi) != TCL_OK || DDi < 0.0) { - opserr << "WARNING invalid YamamotoBiaxialHDR DDi" << endln; + opserr << OpenSees::PromptValueError << "invalid YamamotoBiaxialHDR DDi" << OpenSees::SignalMessageEnd; ifNoError = false; } // Hr if (Tcl_GetDouble(interp, argv[8], &Hr) != TCL_OK || Hr <= 0.0) { - opserr << "WARNING invalid YamamotoBiaxialHDR Hr" << endln; + opserr << OpenSees::PromptValueError << "invalid YamamotoBiaxialHDR Hr" << OpenSees::SignalMessageEnd; ifNoError = false; } @@ -1749,7 +1613,7 @@ TclBasicBuilder_addYamamotoBiaxialHDR(ClientData clientData, Tcl_Interp *interp, // x1, x2, x3 for (int j = 1; j <= 3; j++) { if (Tcl_GetDouble(interp, argv[i + j], &value) != TCL_OK) { - opserr << "WARNING invalid -orient value\n"; + opserr << OpenSees::PromptValueError << "invalid -orient value\n"; ifNoError = false; } else { oriX(j - 1) = value; @@ -1761,7 +1625,7 @@ TclBasicBuilder_addYamamotoBiaxialHDR(ClientData clientData, Tcl_Interp *interp, // yp1, yp2, yp3 for (int j = 1; j <= 3; j++) { if (Tcl_GetDouble(interp, argv[i + j], &value) != TCL_OK) { - opserr << "WARNING invalid -orient value\n"; + opserr << OpenSees::PromptValueError << "invalid -orient value\n"; ifNoError = false; } else { oriYp(j - 1) = value; @@ -1775,7 +1639,7 @@ TclBasicBuilder_addYamamotoBiaxialHDR(ClientData clientData, Tcl_Interp *interp, for (int j = 1; j <= 3; j++) { if (Tcl_GetDouble(interp, argv[i + j], &value) != TCL_OK) { - opserr << "WARNING invalid -orient value\n"; + opserr << OpenSees::PromptValueError << "invalid -orient value\n"; ifNoError = false; } else { oriYp(j - 1) = value; @@ -1788,7 +1652,7 @@ TclBasicBuilder_addYamamotoBiaxialHDR(ClientData clientData, Tcl_Interp *interp, // <-mass m?> if (Tcl_GetDouble(interp, argv[i + 1], &mass) != TCL_OK || mass <= 0) { - opserr << "WARNING invalid mass\n"; + opserr << OpenSees::PromptValueError << "invalid mass\n"; ifNoError = false; } @@ -1798,11 +1662,11 @@ TclBasicBuilder_addYamamotoBiaxialHDR(ClientData clientData, Tcl_Interp *interp, // <-coRS cr? cs?> if (Tcl_GetDouble(interp, argv[i + 1], &Cr) != TCL_OK || Cr <= 0) { - opserr << "WARNING invalid cr\n"; + opserr << OpenSees::PromptValueError << "invalid cr\n"; ifNoError = false; } if (Tcl_GetDouble(interp, argv[i + 2], &Cs) != TCL_OK || Cs <= 0) { - opserr << "WARNING invalid cs\n"; + opserr << OpenSees::PromptValueError << "invalid cs\n"; ifNoError = false; } @@ -1810,7 +1674,7 @@ TclBasicBuilder_addYamamotoBiaxialHDR(ClientData clientData, Tcl_Interp *interp, } else { - opserr << "WARNING invalid optional arguments \n"; + opserr << OpenSees::PromptValueError << "invalid optional arguments \n"; ifNoError = false; break; } @@ -1832,8 +1696,8 @@ TclBasicBuilder_addYamamotoBiaxialHDR(ClientData clientData, Tcl_Interp *interp, // then add the YamamotoBiaxialHDR to the domain if (theTclDomain->addElement(theElement) == false) { - opserr << "WARNING could not add element to the domain\n"; - opserr << "YamamotoBiaxialHDR element: " << eleTag << endln; + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + opserr << "YamamotoBiaxialHDR element: " << eleTag << OpenSees::SignalMessageEnd; delete theElement; return TCL_ERROR; } @@ -1863,14 +1727,14 @@ TclBasicBuilder_addWheelRail(ClientData clientData, Tcl_Interp *interp, int argc // check plane frame problem has 3 dof per node if (ndf != 3) { - opserr << "WARNING invalid ndf: " << ndf; + opserr << OpenSees::PromptValueError << "invalid ndf: " << ndf; opserr << ", for plane problem need 3 - elasticBeamColumn \n"; return TCL_ERROR; } // check the number of arguments if ((argc - eleArgStart) < 8) { - opserr << "WARNING bad command - want: elasticBeamColumn beamId iNode " + opserr << OpenSees::PromptValueError << "bad command - want: elasticBeamColumn beamId iNode " "jNode A E I transTag <-mass m> <-cMass>\n"; return TCL_ERROR; } @@ -1881,75 +1745,75 @@ TclBasicBuilder_addWheelRail(ClientData clientData, Tcl_Interp *interp, int argc double pDeltT, pVel, pInitLocation, pRWheel, pI, pE, pA; if (Tcl_GetInt(interp, argv[1 + eleArgStart], &pTag) != TCL_OK) { - opserr << "WARNING invalid pTag: " << argv[1 + eleArgStart]; + opserr << OpenSees::PromptValueError << "invalid pTag: " << argv[1 + eleArgStart]; opserr << " - WheelRail pTag iNode jNode"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[2 + eleArgStart], &pDeltT) != TCL_OK) { - opserr << "WARNING invalid pDeltT - WheelRail " << pTag + opserr << OpenSees::PromptValueError << "invalid pDeltT - WheelRail " << pTag << " iNode jNode A E I\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[3 + eleArgStart], &pVel) != TCL_OK) { - opserr << "WARNING invalid pVel - WheelRail " << pTag + opserr << OpenSees::PromptValueError << "invalid pVel - WheelRail " << pTag << " iNode jNode A E I\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4 + eleArgStart], &pInitLocation) != TCL_OK) { - opserr << "WARNING invalid pInitLocation - WheelRail " << pTag + opserr << OpenSees::PromptValueError << "invalid pInitLocation - WheelRail " << pTag << " iNode jNode A E I\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[5 + eleArgStart], &pNd1) != TCL_OK) { - opserr << "WARNING invalid pNd1 - WheelRail " << pTag + opserr << OpenSees::PromptValueError << "invalid pNd1 - WheelRail " << pTag << " iNode jNode A E I\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6 + eleArgStart], &pRWheel) != TCL_OK) { - opserr << "WARNING invalid pRWheel - WheelRail " << pTag + opserr << OpenSees::PromptValueError << "invalid pRWheel - WheelRail " << pTag << " iNode jNode A E I\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[7 + eleArgStart], &pI) != TCL_OK) { - opserr << "WARNING invalid pI - WheelRail " << pTag + opserr << OpenSees::PromptValueError << "invalid pI - WheelRail " << pTag << " iNode jNode A E I\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8 + eleArgStart], &pE) != TCL_OK) { - opserr << "WARNING invalid pE - WheelRail " << pTag + opserr << OpenSees::PromptValueError << "invalid pE - WheelRail " << pTag << " iNode jNode A E I\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9 + eleArgStart], &pA) != TCL_OK) { - opserr << "WARNING invalid pA - WheelRail " << pTag + opserr << OpenSees::PromptValueError << "invalid pA - WheelRail " << pTag << " iNode jNode A E I\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[10 + eleArgStart], &transTag) != TCL_OK) { - opserr << "WARNING invalid transTag - WheelRail " << pTag + opserr << OpenSees::PromptValueError << "invalid transTag - WheelRail " << pTag << " iNode jNode A E I\n"; return TCL_ERROR; } CrdTransf *theTransRWheel = builder->getTypedObject(transTag); if (Tcl_GetInt(interp, argv[11 + eleArgStart], &pnLoad) != TCL_OK) { - opserr << "WARNING invalid I - WheelRail " << pTag + opserr << OpenSees::PromptValueError << "invalid I - WheelRail " << pTag << " iNode jNode A E I\n"; return TCL_ERROR; } //---------------------------------- - Vector *pNodeList = 0; - Vector *pDeltaYList = 0; - Vector *pDeltaYLocationList = 0; + Vector *pNodeList = nullptr; + Vector *pDeltaYList = nullptr; + Vector *pDeltaYLocationList = nullptr; if (strcmp(argv[12 + eleArgStart], "-NodeList") == 0) { int pathSize; @@ -1960,7 +1824,7 @@ TclBasicBuilder_addWheelRail(ClientData clientData, Tcl_Interp *interp, int argc if (Tcl_SplitList(interp, argv[13 + eleArgStart], &pathSize, &pathStrings) != TCL_OK) { - opserr << "WARNING problem splitting path list " + opserr << OpenSees::PromptValueError << "problem splitting path list " << argv[13 + eleArgStart] << " - "; opserr << " NodeList -values {path} ... \n"; return TCL_OK; @@ -1970,7 +1834,7 @@ TclBasicBuilder_addWheelRail(ClientData clientData, Tcl_Interp *interp, int argc double value; // int debug = Tcl_GetDouble(interp, pathStrings[i], &value); if (Tcl_GetDouble(interp, pathStrings[i], &value) != TCL_OK) { - opserr << "WARNING problem reading path data value " << pathStrings[i] + opserr << OpenSees::PromptValueError << "problem reading path data value " << pathStrings[i] << " - "; opserr << " -strain {path} ... \n"; return 0; @@ -1983,7 +1847,7 @@ TclBasicBuilder_addWheelRail(ClientData clientData, Tcl_Interp *interp, int argc TCL_Char **pathStrings; if (Tcl_SplitList(interp, argv[15 + eleArgStart], &pathSize, &pathStrings) != TCL_OK) { - opserr << "WARNING problem splitting path list " + opserr << OpenSees::PromptValueError << "problem splitting path list " << argv[15 + eleArgStart] << " - "; opserr << " NodeList -values {path} ... \n"; return TCL_OK; @@ -1992,7 +1856,7 @@ TclBasicBuilder_addWheelRail(ClientData clientData, Tcl_Interp *interp, int argc for (int i = 0; i < pathSize; ++i) { double value; if (Tcl_GetDouble(interp, pathStrings[i], &value) != TCL_OK) { - opserr << "WARNING problem reading path data value " << pathStrings[i] + opserr << OpenSees::PromptValueError << "problem reading path data value " << pathStrings[i] << " - "; opserr << " -strain {path} ... \n"; return 0; @@ -2005,7 +1869,7 @@ TclBasicBuilder_addWheelRail(ClientData clientData, Tcl_Interp *interp, int argc TCL_Char **pathStrings; if (Tcl_SplitList(interp, argv[17 + eleArgStart], &pathSize, &pathStrings) != TCL_OK) { - opserr << "WARNING problem splitting path list " + opserr << OpenSees::PromptValueError << "problem splitting path list " << argv[17 + eleArgStart] << " - "; opserr << " NodeList -values {path} ... \n"; return TCL_OK; @@ -2014,7 +1878,7 @@ TclBasicBuilder_addWheelRail(ClientData clientData, Tcl_Interp *interp, int argc for (int i = 0; i < pathSize; ++i) { double value; if (Tcl_GetDouble(interp, pathStrings[i], &value) != TCL_OK) { - opserr << "WARNING problem reading path data value " << pathStrings[i] + opserr << OpenSees::PromptValueError << "problem reading path data value " << pathStrings[i] << " - "; opserr << " -strain {path} ... \n"; return 0; @@ -2030,14 +1894,14 @@ TclBasicBuilder_addWheelRail(ClientData clientData, Tcl_Interp *interp, int argc // -- End of a 2D wheel-rail element(By Quan Gu, Yongdou Liu, et al.) on 2018/10/29 else if (ndm == 3) { - opserr << G3_ERROR_PROMPT << "Unimplemented." << endln; + opserr << OpenSees::PromptValueError << "Unimplemented." << OpenSees::SignalMessageEnd; return TCL_ERROR; } // add the WheelRail element to the Domain if (builder->getDomain()->addElement(theElement) == false) { - opserr << "WARNING could not add element to the domain\n"; - opserr << "YamamotoBiaxialHDR element: " << pTag << endln; + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + opserr << "YamamotoBiaxialHDR element: " << pTag << OpenSees::SignalMessageEnd; delete theElement; return TCL_ERROR; } diff --git a/SRC/runtime/commands/modeling/element.hpp b/SRC/runtime/commands/modeling/element.hpp index 73f0ecd9a7..8a66c8c174 100644 --- a/SRC/runtime/commands/modeling/element.hpp +++ b/SRC/runtime/commands/modeling/element.hpp @@ -1,3 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// #include #include @@ -6,11 +21,6 @@ typedef void *OPS_Routine(G3_Runtime* , int, const char** const); extern OPS_Routine OPS_ComponentElement2d; extern OPS_Routine OPS_ComponentElement3d; -// extern void *OPS_ComponentElementDamp2d(G3_Runtime*); -extern OPS_Routine OPS_TrussElement; -extern OPS_Routine OPS_TrussSectionElement; -extern OPS_Routine OPS_CorotTrussElement; -extern OPS_Routine OPS_CorotTrussSectionElement; extern OPS_Routine OPS_ElasticTubularJoint; extern OPS_Routine OPS_ZeroLength; extern OPS_Routine OPS_ZeroLengthContactNTS2D; @@ -31,10 +41,6 @@ extern OPS_Routine OPS_ElasticTimoshenkoBeam2d; extern OPS_Routine OPS_ElasticTimoshenkoBeam3d; extern OPS_Routine OPS_AxEqDispBeamColumn2d; extern OPS_Routine OPS_BeamGT; -// extern void* OPS_GradientInelasticBeamColumn2d(); -// extern void* OPS_GradientInelasticBeamColumn3d(); -extern OPS_Routine OPS_DispBeamColumnAsym3dTcl; // Xinlong Du -extern OPS_Routine OPS_MixedBeamColumnAsym3dTcl; // Xinlong Du #if defined(_HAVE_LHNMYS) || defined(OPSDEF_ELEMENT_LHNMYS) extern void *OPS_BeamColumn2DwLHNMYS(G3_Runtime*); extern void *OPS_Beam2dDamage(G3_Runtime*); @@ -43,6 +49,8 @@ extern OPS_Routine OPS_MixedBeamColumnAsym3dTcl; // Xinlong Du #endif extern OPS_Routine OPS_FourNodeTetrahedron; +extern OPS_Routine OPS_TenNodeTetrahedron; + extern OPS_Routine OPS_TPB1D; extern OPS_Routine OPS_TFP_Bearing; extern OPS_Routine OPS_FPBearingPTV; @@ -63,10 +71,11 @@ extern OPS_Routine OPS_PML2D; extern OPS_Routine OPS_CorotTruss2; extern OPS_Routine OPS_HDR; extern OPS_Routine OPS_LeadRubberX; +extern OPS_Routine OPS_LeadRubberY; extern OPS_Routine OPS_ElastomericX; extern OPS_Routine OPS_N4BiaxialTruss; extern OPS_Routine OPS_AC3D8HexWithSensitivity; -extern OPS_Routine OPS_VS3D4WuadWithSensitivity; +extern OPS_Routine OPS_VS3D4QuadWithSensitivity; extern OPS_Routine OPS_MVLEM; // Kristijan Kolozvari extern OPS_Routine OPS_SFI_MVLEM; // Kristijan Kolozvari extern OPS_Routine OPS_MVLEM_3D; // Kristijan Kolozvari @@ -86,6 +95,7 @@ extern OPS_Routine OPS_FSIFluidBoundaryElement2D; // Massimo Petracca (ASDEA) extern OPS_Routine OPS_FSIFluidElement2D; // Massimo Petracca (ASDEA) extern OPS_Routine OPS_ASDShellT3; extern OPS_Routine OPS_TwoNodeLink; +extern OPS_Routine OPS_TwoNodeLinkSection; extern OPS_Routine OPS_LinearElasticSpring; extern OPS_Routine OPS_Inerter; extern OPS_Routine OPS_Inno3DPnPJoint; @@ -105,6 +115,7 @@ extern OPS_Routine OPS_LehighJoint2d; extern OPS_Routine OPS_MasonPan12; extern OPS_Routine OPS_MasonPan3D; + #include #include static @@ -137,42 +148,20 @@ class CaseInsensitive } }; -#if 0 -// template static int -class BasicModelBuilder; -struct Tcl_Interp; -class Domain; -template static int -dispatch(BasicModelBuilder* builder, Tcl_Interp* interp, int argc, const char** const argv) -{ - int ndm = builder->getNDM(); - Domain* domain = builder->getDomain(); - G3_Runtime *rt = G3_getRuntime(interp); - - Element* theElement = (Element*)fn( rt, argc, argv ); - - if (domain->addElement(*theElement) == false) { - opserr << G3_ERROR_PROMPT << "Could not add element to the domain.\n"; - delete theElement; - return TCL_ERROR; - } - return TCL_OK; -} -#endif +Tcl_CmdProc TclCommand_addTruss; Tcl_CmdProc TclCommand_addTwoNodeLink; +Tcl_CmdProc TclCommand_addTwoNodeLinkSection; // Plane Tcl_CmdProc TclBasicBuilder_addFourNodeQuad; Tcl_CmdProc TclBasicBuilder_addFourNodeQuadWithSensitivity; -Tcl_CmdProc TclBasicBuilder_addEnhancedQuad; Tcl_CmdProc TclBasicBuilder_addConstantPressureVolumeQuad; Tcl_CmdProc TclBasicBuilder_addNineNodeMixedQuad; -Tcl_CmdProc TclBasicBuilder_addNineNodeQuad; Tcl_CmdProc TclBasicBuilder_addSixNodeTri; -Tcl_CmdProc TclBasicBuilder_addEightNodeQuad; Tcl_CmdProc TclBasicBuilder_addFourNodeQuadUP; Tcl_CmdProc TclBasicBuilder_addNineFourNodeQuadUP; Tcl_CmdProc TclBasicBuilder_addBBarFourNodeQuadUP; -Tcl_CmdProc TclDispatch_newTri31; +// Shell +Tcl_CmdProc TclBasicBuilder_addShell; // Brick Tcl_CmdProc TclBasicBuilder_addBrickUP; Tcl_CmdProc TclBasicBuilder_addBBarBrickUP; @@ -186,37 +175,56 @@ Tcl_CmdProc TclCommand_addActuatorCorot; Tcl_CmdProc TclCommand_addAdapter; Tcl_CmdProc TclBasicBuilder_addRJWatsonEqsBearing; -static +const static std::unordered_map element_dispatch_tcl = { {"twoNodeLink", TclCommand_addTwoNodeLink}, + {"twoNodeLinkSection", TclCommand_addTwoNodeLinkSection}, + {"Truss", TclCommand_addTruss}, + {"TrussSection", TclCommand_addTruss}, + {"CorotTruss", TclCommand_addTruss}, + {"CorotTrussSection", TclCommand_addTruss}, // // Plane // - {"Quad", TclBasicBuilder_addFourNodeQuad}, {"stdQuad", TclBasicBuilder_addFourNodeQuad}, + {"LagrangeQuad", TclBasicBuilder_addFourNodeQuad}, + {"enhancedQuad", TclBasicBuilder_addFourNodeQuad}, + {"quad", TclBasicBuilder_addFourNodeQuad}, + {"quad9n", TclBasicBuilder_addFourNodeQuad}, + {"quad8n", TclBasicBuilder_addFourNodeQuad}, {"quadWithSensitivity", TclBasicBuilder_addFourNodeQuadWithSensitivity}, - {"enhancedQuad", TclBasicBuilder_addEnhancedQuad}, - {"bbarQuad", TclBasicBuilder_addConstantPressureVolumeQuad}, {"mixedQuad", TclBasicBuilder_addConstantPressureVolumeQuad}, {"nineNodeMixedQuad", TclBasicBuilder_addNineNodeMixedQuad}, - {"nineNodeQuad", TclBasicBuilder_addNineNodeMixedQuad}, + {"nineNodeQuad", TclBasicBuilder_addNineNodeMixedQuad}, // ?? - {"quad9n", TclBasicBuilder_addNineNodeQuad}, + {"tri6n", TclBasicBuilder_addSixNodeTri}, + {"tri31", TclBasicBuilder_addFourNodeQuad}, - {"quad8n", TclBasicBuilder_addEightNodeQuad}, +// Shell + {"ASDShellQ4", TclBasicBuilder_addShell}, + {"ShellMITC4", TclBasicBuilder_addShell}, + {"ShellMITC9", TclBasicBuilder_addShell}, + {"ShellDKGQ", TclBasicBuilder_addShell}, + {"ShellDKGT", TclBasicBuilder_addShell}, + {"ShellNLDKGQ", TclBasicBuilder_addShell}, + {"ShellNLDKGT", TclBasicBuilder_addShell}, +// {"ShellANDeS", TclBasicBuilder_addShell}, + {"ShellMITC4Thermal", TclBasicBuilder_addShell}, + {"ShellNLDKGQThermal", TclBasicBuilder_addShell}, + +// U-P - {"tri6n", TclBasicBuilder_addSixNodeTri}, - {"tri31", TclDispatch_newTri31}, {"quadUP", TclBasicBuilder_addFourNodeQuadUP}, {"9_4_QuadUP", TclBasicBuilder_addNineFourNodeQuadUP}, {"bbarQuadUP", TclBasicBuilder_addBBarFourNodeQuadUP}, + // // Brick // @@ -252,8 +260,6 @@ static std::unordered_map element_dispatch = { // Truss - {"TrussSection", OPS_TrussSectionElement}, - {"CorotTrussSection", OPS_CorotTrussSectionElement}, {"N4BiaxialTruss", OPS_N4BiaxialTruss}, {"Truss2", OPS_Truss2}, {"CorotTruss2", OPS_CorotTruss2}, @@ -271,9 +277,6 @@ element_dispatch = { {"componentElement2d", OPS_ComponentElement2d}, {"componentElement3d", OPS_ComponentElement3d}, -#if 0 - {"componentElementDamp2d", OPS_ComponentElementDamp2d}, -#endif {"ModElasticBeam2d", OPS_ModElasticBeam2d}, {"ModElasticBeam3d", OPS_ModElasticBeam3d}, @@ -284,7 +287,8 @@ element_dispatch = { {"TripleFrictionPendulum", OPS_TripleFrictionPendulum}, {"TripleFrictionPendulumX", OPS_TripleFrictionPendulumX}, {"HDR", OPS_HDR}, - {"LeadRubberX", OPS_LeadRubberX}, +//{"LeadRubberX", OPS_LeadRubberX}, + {"LeadRubberX", OPS_LeadRubberY}, {"ElastomericX", OPS_ElastomericX}, {"AxEqDispBeamColumn2d", OPS_AxEqDispBeamColumn2d}, @@ -322,13 +326,16 @@ element_dispatch = { {"ASI3D8", OPS_ASID8QuadWithSensitivity}, {"AV3D4", OPS_AV3D4QuadWithSensitivity}, {"ElastomericBearingBoucWenMod", OPS_ElastomericBearingBoucWenMod3d}, - {"VS3D4", OPS_VS3D4WuadWithSensitivity}, + {"VS3D4", OPS_VS3D4QuadWithSensitivity}, {"CatenaryCable", OPS_CatenaryCableElement}, {"ASDEmbeddedNodeElement", OPS_ASDEmbeddedNodeElement}, {"LysmerTriangle", OPS_LysmerTriangle}, {"ASDAbsorbingBoundary2D", OPS_ASDAbsorbingBoundary2D}, {"ASDAbsorbingBoundary3D", OPS_ASDAbsorbingBoundary3D}, + {"FourNodeTetrahedron", OPS_FourNodeTetrahedron}, + {"TenNodeTetrahedron", OPS_TenNodeTetrahedron}, + {"LinearElasticSpring", OPS_LinearElasticSpring}, {"Inerter", OPS_Inerter}, {"Adapter", OPS_Adapter}, diff --git a/SRC/runtime/commands/modeling/element/brick.cpp b/SRC/runtime/commands/modeling/element/brick.cpp new file mode 100644 index 0000000000..f21b69379d --- /dev/null +++ b/SRC/runtime/commands/modeling/element/brick.cpp @@ -0,0 +1,676 @@ +//===----------------------------------------------------------------------===// +// +// OpenSees - Open System for Earthquake Engineering Simulation +// +//===----------------------------------------------------------------------===// +// +// Written: fmk +// Created: 03/01 +// +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef _FLBrick +# include +#endif + +int +TclBasicBuilder_addBrick(ClientData clientData, Tcl_Interp *interp, int argc, + TCL_Char **const argv) +{ + const int eleArgStart = 1; + + BasicModelBuilder* builder = (BasicModelBuilder*)clientData; + Domain* theTclDomain = builder->getDomain(); + + // check the number of arguments is correct + if ((argc - eleArgStart) < 11) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: element Brick eleTag? Node1? Node2? Node3? Node4? Node5? " + "Node6? Node7? Node 8? matTag?\n"; + return TCL_ERROR; + } + + // get the id and end nodes + int BrickId; + int matID; + int Node1, Node2, Node3, Node4, + Node5, Node6, Node7, Node8; + + if (Tcl_GetInt(interp, argv[1 + eleArgStart], &BrickId) != TCL_OK) { + opserr << "WARNING invalid Brick eleTag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[2 + eleArgStart], &Node1) != TCL_OK) { + opserr << "WARNING invalid Node1\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[3 + eleArgStart], &Node2) != TCL_OK) { + opserr << "WARNING invalid Node2\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[4 + eleArgStart], &Node3) != TCL_OK) { + opserr << "WARNING invalid Node3\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[5 + eleArgStart], &Node4) != TCL_OK) { + opserr << "WARNING invalid Node4\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[6 + eleArgStart], &Node5) != TCL_OK) { + opserr << "WARNING invalid Node5\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[7 + eleArgStart], &Node6) != TCL_OK) { + opserr << "WARNING invalid Node6\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[8 + eleArgStart], &Node7) != TCL_OK) { + opserr << "WARNING invalid Node7\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[9 + eleArgStart], &Node8) != TCL_OK) { + opserr << "WARNING invalid Node8\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[10 + eleArgStart], &matID) != TCL_OK) { + opserr << "WARNING invalid matTag\n"; + return TCL_ERROR; + } + + + NDMaterial *theMaterial = builder->getTypedObject(matID); + if (theMaterial == nullptr) + return TCL_ERROR; + + + double b1 = 0.0; + double b2 = 0.0; + double b3 = 0.0; + if ((argc - eleArgStart) > 11) { + if (Tcl_GetDouble(interp, argv[11 + eleArgStart], &b1) != TCL_OK) { + opserr << "WARNING invalid b1\n"; + opserr << "Brick element: " << BrickId << "\n"; + return TCL_ERROR; + } + } + + if ((argc - eleArgStart) > 12) { + if (Tcl_GetDouble(interp, argv[12 + eleArgStart], &b2) != TCL_OK) { + opserr << "WARNING invalid b2\n"; + opserr << "Brick element: " << BrickId << "\n"; + return TCL_ERROR; + } + } + + if ((argc - eleArgStart) > 13) { + if (Tcl_GetDouble(interp, argv[13 + eleArgStart], &b3) != TCL_OK) { + opserr << "WARNING invalid b3\n"; + opserr << "Brick element: " << BrickId << "\n"; + return TCL_ERROR; + } + } + + // now create the Brick and add it to the Domain + Element *theBrick = nullptr; + if (strcmp(argv[1], "stdBrick") == 0) { + theBrick = new Brick(BrickId, Node1, Node2, Node3, Node4, Node5, Node6, + Node7, Node8, *theMaterial, b1, b2, b3); + + } else if (strcmp(argv[1], "bbarBrickWithSensitivity") == 0) { + theBrick = new BbarBrickWithSensitivity(BrickId, Node1, Node2, Node3, Node4, + Node5, Node6, Node7, Node8, + *theMaterial, b1, b2, b3); + } else if (strcmp(argv[1], "bbarBrick") == 0) { + theBrick = new BbarBrick(BrickId, Node1, Node2, Node3, Node4, Node5, Node6, + Node7, Node8, *theMaterial, b1, b2, b3); + } + +#ifdef _FLBrick + else if (strcmp(argv[1], "flBrick") == 0) { + theBrick = new FLBrick(BrickId, Node1, Node2, Node3, Node4, Node5, Node6, + Node7, Node8, *theMaterial, b1, b2, b3); + } +#endif + + else { + opserr << "WARNING element " << argv[1] << " type not recognized\n"; + return TCL_ERROR; + } + + if (theBrick == 0) { + opserr << "WARNING ran out of memory creating element\n"; + return TCL_ERROR; + } + + if (theTclDomain->addElement(theBrick) == false) { + opserr << "WARNING could not add element to the domain\n"; + delete theBrick; + return TCL_ERROR; + } + + // if get here we have successfully created the node and added it to the domain + return TCL_OK; +} + +// +// Description: This file contains the implementation of +// TclBasicBuilder_addBrickUP() , +// TclBasicBuilder_addTwentyEightNodeBrickUP(), +// TclBasicBuilder_addBBarBrickUP() +// +// +// Jinchi Lu and Zhaohui Yang (May 2004) +// +#include +#include +#include +#include +#include +#include +#include + +int +TclBasicBuilder_addTwentyNodeBrick(ClientData clientData, Tcl_Interp *interp, + int argc, + TCL_Char ** const argv) +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + Domain* theTclDomain = builder->getDomain(); + + if (builder == 0 || clientData == 0) { + opserr << "WARNING builder has been destroyed\n"; + return TCL_ERROR; + } + if (builder->getNDM() != 3) { + opserr << "WARNING -- model dimensions and/or nodal DOF not compatible " + "with 20NodeBrick element\n"; + return TCL_ERROR; + } + // check the number of arguments is correct + int argStart = 2; + if ((argc - argStart) < 22) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: element 20NodeBrick eleTag? N1? N2? N3? N4? N5? N6? N7? " + "N8? N9? N10? N11? N12? N13? N14? N15? N16? N17? N18? N19? N20? " + "matTag? \n"; + return TCL_ERROR; + } + // get the id and end nodes + int brickId, Nod[20], matID; + double b1 = 0.0; + double b2 = 0.0; + double b3 = 0.0; + if (Tcl_GetInt(interp, argv[argStart], &brickId) != TCL_OK) { + opserr << "WARNING invalid 20NodeBrick eleTag" << "\n"; + return TCL_ERROR; + } + for (int i = 0; i < 20; i++) + if (Tcl_GetInt(interp, argv[1 + argStart + i], &(Nod[i])) != TCL_OK) { + opserr << "WARNING invalid Node number\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[21 + argStart], &matID) != TCL_OK) { + opserr << "WARNING invalid matID\n"; + return TCL_ERROR; + } + if ((argc - argStart) >= 23) { + if (Tcl_GetDouble(interp, argv[22 + argStart], &b1) != TCL_OK) { + opserr << "WARNING invalid b1\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 24) { + if (Tcl_GetDouble(interp, argv[23 + argStart], &b2) != TCL_OK) { + opserr << "WARNING invalid b2\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 25) { + if (Tcl_GetDouble(interp, argv[24 + argStart], &b3) != TCL_OK) { + opserr << "WARNING invalid b3\n"; + return TCL_ERROR; + } + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + if (theMaterial == nullptr) { + return TCL_ERROR; + } + + // now create the brick and add it to the Domain + Twenty_Node_Brick *theTwentyNodeBrick = + new Twenty_Node_Brick(brickId, Nod[0], Nod[1], Nod[2], Nod[3], Nod[4], + Nod[5], Nod[6], Nod[7], + Nod[8], Nod[9], Nod[10], Nod[11], Nod[12], Nod[13], + Nod[14], + Nod[15], Nod[16], Nod[17], Nod[18], Nod[19], + *theMaterial, b1, b2, b3); + + if (theTclDomain->addElement(theTwentyNodeBrick) == false) { + opserr << "WARNING could not add element to the domain\n"; + delete theTwentyNodeBrick; + return TCL_ERROR; + } + // if get here we have successfully created the element and added it to the + // domain + return TCL_OK; +} + +int +TclBasicBuilder_addBrickUP(ClientData clientData, Tcl_Interp *interp, int argc, + TCL_Char ** const argv) +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + Domain* theTclDomain = builder->getDomain(); + + if (builder == 0 || clientData == 0) { + opserr << "WARNING builder has been destroyed\n"; + return TCL_ERROR; + } + + if (builder->getNDM() != 3 || builder->getNDF() != 4) { + opserr << "WARNING -- model dimensions and/or nodal DOF not compatible " + "with QuadUP element\n"; + return TCL_ERROR; + } + + // check the number of arguments is correct + int argStart = 2; + + if ((argc - argStart) < 15) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: element brickUP eleTag? N1? N2? N3? N4? N5? N6? N7? N8? " + "matTag? bulk? rhof? perm_x? perm_y? perm_z? \n"; + return TCL_ERROR; + } + + // get the id and end nodes + int brickUPId, Nod[8], matID; + double bk, r, perm1, perm2, perm3; + double b1 = 0.0; + double b2 = 0.0; + double b3 = 0.0; + + if (Tcl_GetInt(interp, argv[argStart], &brickUPId) != TCL_OK) { + opserr << "WARNING invalid brickUP eleTag" << "\n"; + return TCL_ERROR; + } + + for (int i = 0; i < 8; i++) + if (Tcl_GetInt(interp, argv[1 + argStart + i], &(Nod[i])) != TCL_OK) { + opserr << "WARNING invalid Node number\n"; + opserr << "brickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[9 + argStart], &matID) != TCL_OK) { + opserr << "WARNING invalid matID\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[10 + argStart], &bk) != TCL_OK) { + opserr << "WARNING invalid fluid bulk modulus\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[11 + argStart], &r) != TCL_OK) { + opserr << "WARNING invalid fluid mass density\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[12 + argStart], &perm1) != TCL_OK) { + opserr << "WARNING invalid permeability_x\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[13 + argStart], &perm2) != TCL_OK) { + opserr << "WARNING invalid permeability_y\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[14 + argStart], &perm3) != TCL_OK) { + opserr << "WARNING invalid permeability_z\n"; + return TCL_ERROR; + } + + if ((argc - argStart) >= 16) { + if (Tcl_GetDouble(interp, argv[15 + argStart], &b1) != TCL_OK) { + opserr << "WARNING invalid b1\n"; + opserr << "brickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 17) { + if (Tcl_GetDouble(interp, argv[16 + argStart], &b2) != TCL_OK) { + opserr << "WARNING invalid b2\n"; + opserr << "brickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 18) { + if (Tcl_GetDouble(interp, argv[17 + argStart], &b3) != TCL_OK) { + opserr << "WARNING invalid b3\n"; + opserr << "brickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + + if (theMaterial == 0) { + opserr << "WARNING material not found\n"; + opserr << "Material: " << matID; + opserr << "\nbrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + // now create the brickUP and add it to the Domain + BrickUP *theBrickUP = new BrickUP( + brickUPId, Nod[0], Nod[1], Nod[2], Nod[3], Nod[4], Nod[5], Nod[6], Nod[7], + *theMaterial, bk, r, perm1, perm2, perm3, b1, b2, b3); + if (theBrickUP == 0) { + opserr << "WARNING ran out of memory creating element\n"; + return TCL_ERROR; + } + + if (theTclDomain->addElement(theBrickUP) == false) { + opserr << "WARNING could not add element to the domain\n"; + delete theBrickUP; + return TCL_ERROR; + } + + // if get here we have successfully created the element and added it to the + // domain + return TCL_OK; +} + +int +TclBasicBuilder_addTwentyEightNodeBrickUP(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) + +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + Domain* theTclDomain = builder->getDomain(); + + + if (builder->getNDM() != 3) { + opserr << "WARNING -- model dimensions and/or nodal DOF not compatible " + "with 20_8_BrickUP element\n"; + return TCL_ERROR; + } + + // check the number of arguments is correct + int argStart = 2; + + if ((argc - argStart) < 27) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: element 20_8_BrickUP eleTag? N1? N2? N3? N4? N5? N6? N7? " + "N8? N9? N10? N11? N12? N13? N14? N15? N16? N17? N18? N19? N20? " + "matTag? bulk? rhof? perm_x? perm_y? perm_z? \n"; + return TCL_ERROR; + } + + // get the id and end nodes + int brickUPId, Nod[20], matID; + double bk, r, perm1, perm2, perm3; + double b1 = 0.0; + double b2 = 0.0; + double b3 = 0.0; + + if (Tcl_GetInt(interp, argv[argStart], &brickUPId) != TCL_OK) { + opserr << "WARNING invalid 20_8_BrickUP eleTag" << "\n"; + return TCL_ERROR; + } + + for (int i = 0; i < 20; i++) + if (Tcl_GetInt(interp, argv[1 + argStart + i], &(Nod[i])) != TCL_OK) { + opserr << "WARNING invalid Node number\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[21 + argStart], &matID) != TCL_OK) { + opserr << "WARNING invalid matID\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[22 + argStart], &bk) != TCL_OK) { + opserr << "WARNING invalid fluid bulk modulus\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[23 + argStart], &r) != TCL_OK) { + opserr << "WARNING invalid fluid mass density\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[24 + argStart], &perm1) != TCL_OK) { + opserr << "WARNING invalid permeability_x\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[25 + argStart], &perm2) != TCL_OK) { + opserr << "WARNING invalid permeability_y\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[26 + argStart], &perm3) != TCL_OK) { + opserr << "WARNING invalid permeability_z\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + if ((argc - argStart) >= 28) { + if (Tcl_GetDouble(interp, argv[27 + argStart], &b1) != TCL_OK) { + opserr << "WARNING invalid b1\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 29) { + if (Tcl_GetDouble(interp, argv[28 + argStart], &b2) != TCL_OK) { + opserr << "WARNING invalid b2\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 30) { + if (Tcl_GetDouble(interp, argv[29 + argStart], &b3) != TCL_OK) { + opserr << "WARNING invalid b3\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + + if (theMaterial == 0) { + opserr << "WARNING material not found\n"; + opserr << "Material: " << matID; + opserr << "\n20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + // now create the brickUP and add it to the Domain + TwentyEightNodeBrickUP *theTwentyEightNodeBrickUP = + new TwentyEightNodeBrickUP( + brickUPId, Nod[0], Nod[1], Nod[2], Nod[3], Nod[4], Nod[5], Nod[6], + Nod[7], Nod[8], Nod[9], Nod[10], Nod[11], Nod[12], Nod[13], Nod[14], + Nod[15], Nod[16], Nod[17], Nod[18], Nod[19], *theMaterial, bk, r, + perm1, perm2, perm3, b1, b2, b3); + if (theTwentyEightNodeBrickUP == 0) { + opserr << "WARNING ran out of memory creating element\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + return TCL_ERROR; + } + + if (theTclDomain->addElement(theTwentyEightNodeBrickUP) == false) { + opserr << "WARNING could not add element to the domain\n"; + opserr << "20_8_BrickUP element: " << brickUPId << "\n"; + delete theTwentyEightNodeBrickUP; + return TCL_ERROR; + } + + // if get here we have successfully created the element and added it to the + // domain + return TCL_OK; +} + +/* ***************************************************************************** + + BBAR BRICK U_P + + ***************************************************************************** + */ + +int +TclBasicBuilder_addBBarBrickUP(ClientData clientData, Tcl_Interp *interp, int argc, + TCL_Char ** const argv) +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + Domain* theTclDomain = builder->getDomain(); + + if (builder == 0 || clientData == 0) { + opserr << "WARNING builder has been destroyed\n"; + return TCL_ERROR; + } + + if (builder->getNDM() != 3 || builder->getNDF() != 4) { + opserr << "WARNING -- model dimensions and/or nodal DOF not compatible " + "with QuadUP element\n"; + return TCL_ERROR; + } + + // check the number of arguments is correct + int argStart = 2; + + if ((argc - argStart) < 15) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: element BBarBrickUP eleTag? N1? N2? N3? N4? N5? N6? N7? " + "N8? matTag? bulk? rhof? perm_x? perm_y? perm_z? \n"; + return TCL_ERROR; + } + + // get the id and end nodes + int BBarBrickUPId, Nod[8], matID; + double bk, r, perm1, perm2, perm3; + double b1 = 0.0; + double b2 = 0.0; + double b3 = 0.0; + + if (Tcl_GetInt(interp, argv[argStart], &BBarBrickUPId) != TCL_OK) { + opserr << "WARNING invalid BBarBrickUP eleTag" << "\n"; + return TCL_ERROR; + } + + for (int i = 0; i < 8; i++) + if (Tcl_GetInt(interp, argv[1 + argStart + i], &(Nod[i])) != TCL_OK) { + opserr << "WARNING invalid Node number\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[9 + argStart], &matID) != TCL_OK) { + opserr << "WARNING invalid matID\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[10 + argStart], &bk) != TCL_OK) { + opserr << "WARNING invalid fluid bulk modulus\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[11 + argStart], &r) != TCL_OK) { + opserr << "WARNING invalid fluid mass density\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[12 + argStart], &perm1) != TCL_OK) { + opserr << "WARNING invalid permeability_x\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[13 + argStart], &perm2) != TCL_OK) { + opserr << "WARNING invalid permeability_y\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[14 + argStart], &perm3) != TCL_OK) { + opserr << "WARNING invalid permeability_z\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + + if ((argc - argStart) >= 16) { + if (Tcl_GetDouble(interp, argv[15 + argStart], &b1) != TCL_OK) { + opserr << "WARNING invalid b1\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 17) { + if (Tcl_GetDouble(interp, argv[16 + argStart], &b2) != TCL_OK) { + opserr << "WARNING invalid b2\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 18) { + if (Tcl_GetDouble(interp, argv[17 + argStart], &b3) != TCL_OK) { + opserr << "WARNING invalid b3\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + + if (theMaterial == 0) { + opserr << "WARNING material not found\n"; + opserr << "Material: " << matID; + opserr << "\nBBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + + // now create the BBarBrickUP and add it to the Domain + BBarBrickUP *theBBarBrickUP = new BBarBrickUP( + BBarBrickUPId, Nod[0], Nod[1], Nod[2], Nod[3], Nod[4], Nod[5], Nod[6], + Nod[7], *theMaterial, bk, r, perm1, perm2, perm3, b1, b2, b3); + if (theBBarBrickUP == 0) { + opserr << "WARNING ran out of memory creating element\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + return TCL_ERROR; + } + + if (theTclDomain->addElement(theBBarBrickUP) == false) { + opserr << "WARNING could not add element to the domain\n"; + opserr << "BBarBrickUP element: " << BBarBrickUPId << "\n"; + delete theBBarBrickUP; + return TCL_ERROR; + } + + // if get here we have successfully created the element and added it to the + // domain + return TCL_OK; +} diff --git a/SRC/runtime/commands/modeling/element/frames.cpp b/SRC/runtime/commands/modeling/element/frames.cpp new file mode 100644 index 0000000000..55af8186ab --- /dev/null +++ b/SRC/runtime/commands/modeling/element/frames.cpp @@ -0,0 +1,1458 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Written: cmp, mhs, rms, fmk +// +// Created: Feb 2023 +// +// Standard library + #include + #include + #include + #include + #include + #include + #include + #include + #include + #ifdef _MSC_VER + # include + # define strcasecmp _stricmp + #else + # include + #endif + #define strcmp strcasecmp + + // Parsing + #include + #include + #include + #include + + // Model + #include + #include + #include + + // Sections + #include + #include + #include + + // Elements + #include "ElasticBeam2d.h" + #include "ElasticBeam2d.h" + #include "ElasticBeam3d.h" + #include "ElasticBeam3d.h" + #include "PrismFrame2d.h" + #include "PrismFrame2d.h" + #include "PrismFrame3d.h" + #include "PrismFrame3d.h" + + #include + #include + #include + #include + #include + #include + + #include + #include + #include + #include + #include + + #include + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + + // Quadrature + #include + #include + #include + #include + #include + #include + #include + + #include + +using namespace OpenSees; + +struct Options { + int mass_flag; + int use_mass; + int shear_flag; + int geom_flag; +}; + + +extern BeamIntegration* GetBeamIntegration(TCL_Char* type, int); +extern BeamIntegrationRule* GetHingeStencil(int argc, TCL_Char ** const argv); + +static inline int +CheckTransformation(Domain& domain, int iNode, int jNode, CrdTransf& transform) +{ + Node* ni = domain.getNode(iNode); + Node* nj = domain.getNode(jNode); + if (ni == nullptr || nj == nullptr) { + opserr << OpenSees::PromptValueError << "nodes not found with tags " + << iNode << " and " << jNode + << OpenSees::SignalMessageEnd; + } + + if (transform.initialize(ni, nj) != 0) { + if (transform.getInitialLength() <= 0.0) { + opserr << OpenSees::PromptValueError + << "element has zero or negative initial length " + << transform.getInitialLength() + << "; check for duplicate nodes" + << OpenSees::SignalMessageEnd; + } + else { + opserr << OpenSees::PromptValueError + << "transformation with tag " << transform.getTag() + << " could not be initialized with nodes " + << iNode << " and " << jNode + << "; check orientation" + << OpenSees::SignalMessageEnd; + } + return TCL_ERROR; + } + return TCL_OK; +} + + + +template +static Element* +CreateFrame(BasicModelBuilder& builder, + const char* name, + int tag, + std::vector& nodev, + int transfTag, + const std::vector& section_tags, + BeamIntegration& beamIntegr, + double mass, int max_iter, double tol, + Options& options) +{ + + std::vector sections; + + // Finalize sections + assert(section_tags.size() != 0); + for (int tag : section_tags) { + Section *section = builder.getTypedObject
(tag); + if (section == nullptr) + return nullptr; + sections.push_back(section); + } + int nIP = sections.size(); + + SectionForceDeformation** secptrs = (SectionForceDeformation**)(sections.data()); + + if (options.shear_flag == -1) { + options.shear_flag = 0; + const ID& resultants = sections[0]->getType(); + for (int i=0; i< sections[0]->getOrder(); i++) + if (resultants(i) == FrameStress::Vy) + options.shear_flag = 1; + } + + // Finalize the coordinate transform + CrdTransf* theTransf = builder.getTypedObject(transfTag); + if (theTransf == nullptr) { + opserr << OpenSees::PromptValueError << "transformation not found with tag " << transfTag << "\n"; + return nullptr; + } + + // + // Create the element + // + Element *theElement = nullptr; + + int iNode = nodev[0], + jNode = nodev[1]; + bool use_mass = options.use_mass; + + if constexpr (ndm == 2) { + + if (strcmp(name, "elasticForceBeamColumn") == 0) + theElement = new ElasticForceBeamColumn2d(tag, iNode, jNode, nIP, secptrs, beamIntegr, *theTransf, mass); + else if (strcmp(name, "timoshenkoBeamColumn") == 0) + theElement = + new TimoshenkoBeamColumn2d(tag, iNode, jNode, nIP, secptrs, beamIntegr, *theTransf, mass); + else if (strcmp(name, "dispBeamColumn") == 0) + theElement = + new DispBeamColumn2d(tag, iNode, jNode, nIP, secptrs, beamIntegr, *theTransf, mass, options.mass_flag); + else if (strcmp(name, "dispBeamColumnNL") == 0) + theElement = + new DispBeamColumnNL2d(tag, iNode, jNode, nIP, secptrs, + beamIntegr, *theTransf, mass); + + else if (strcmp(name, "dispBeamColumnThermal") == 0) + theElement = new DispBeamColumn2dThermal(tag, iNode, jNode, nIP, secptrs, beamIntegr, *theTransf, mass); + + + else if (strcmp(name, "dispBeamColumnWithSensitivity") == 0) + theElement = new DispBeamColumn2d(tag, iNode, jNode, nIP, secptrs, beamIntegr, *theTransf, mass); + + + // Force formulations + else if (strcmp(name, "forceBeamColumnCBDI") == 0) + theElement = new ForceBeamColumnCBDI2d(tag, iNode, jNode, nIP, secptrs, + beamIntegr, *theTransf, mass, false); + + else if (strcmp(name, "forceBeamColumnCSBDI") == 0) + return new ForceBeamColumnCBDI2d(tag, iNode, jNode, nIP, secptrs, + beamIntegr, *theTransf, mass, true); + + else if (strcmp(name, "forceBeamColumnWarping") == 0) + return + new ForceBeamColumnWarping2d(tag, iNode, jNode, nIP, + secptrs, beamIntegr, *theTransf); + + else if (strcmp(name, "forceBeamColumnThermal") == 0) + return new ForceBeamColumn2dThermal(tag, iNode, jNode, nIP, secptrs, beamIntegr, *theTransf, mass); + + else if (strcmp(name, "elasticForceBeamColumnWarping") == 0) + return new ElasticForceBeamColumnWarping2d( + tag, iNode, jNode, nIP, secptrs, beamIntegr, *theTransf); + else + theElement = + new ForceBeamColumn2d(tag, iNode, jNode, nIP, secptrs, + beamIntegr, *theTransf, mass, max_iter, tol); + + + } else { + // + // ndm == 3 + // + + if (CheckTransformation(*builder.getDomain(), nodev[0], nodev[nodev.size()-1], *theTransf) != TCL_OK) + return nullptr; + if (strstr(name, "Frame") != nullptr) { + if (strstr(name, "Exact") == nullptr) { + + std::array nodes {nodev[0], nodev[1]}; + + FrameTransformBuilder* tb = builder.getTypedObject(transfTag); + + if (!tb) { + opserr << OpenSees::PromptValueError << "invalid transform\n"; + return nullptr; + } + + + if (strcmp(name, "EulerFrame") == 0) { + theElement = new EulerFrame3d(tag, nodes, nIP, + sections.data(), + beamIntegr, + *tb, + mass, options.mass_flag); + } + + if (strcmp(name, "CubicFrame") == 0) { + if (options.shear_flag) + theElement = new CubicFrame3d(tag, nodes, + sections, + beamIntegr, + *theTransf, // TODO: Use FrameTransformBuilder + mass); + else + theElement = new CubicFrame3d(tag, nodes, + sections, + beamIntegr, + *theTransf, // TODO: Use FrameTransformBuilder + mass); + } + + else if (strcmp(name, "DisplFrame") == 0) { + theElement = new EulerDeltaFrame3d(tag, nodes, sections, + beamIntegr, *theTransf, + mass, + options.mass_flag, + use_mass); + } + + else if ((strstr(name, "Force") != 0) || + (strcmp(name, "MixedFrame") == 0)) { + if (strcmp(name, "ForceDeltaFrame") == 0 || options.geom_flag) { + if (!options.shear_flag) + static_loop<2,6>([&](auto nip) constexpr { + if (nip.value == sections.size()) + theElement = new ForceDeltaFrame3d(tag, nodes, sections, + beamIntegr, *tb, + mass, + options.mass_flag, + use_mass, + max_iter, tol, + options.shear_flag + ); + }); + else + static_loop<2,6>([&](auto nip) constexpr { + if (nip.value == sections.size()) + theElement = new ForceDeltaFrame3d(tag, nodes, sections, + beamIntegr, *tb, + mass, + options.mass_flag, + use_mass, + max_iter, tol, + options.shear_flag + ); + }); + } else { + int ndf = builder.getNDF(); + + static_loop<0, 3>([&](auto nwm) constexpr { + if (nwm.value + 6 == ndf) { + // Create the transform + if (!options.shear_flag) { + static_loop<2,30>([&](auto nip) constexpr { + if (nip.value == sections.size()) + theElement = new ForceFrame3d(tag, + nodes, sections, + beamIntegr, *tb, + mass, options.mass_flag, use_mass, + max_iter, tol + ); + }); + } + else + theElement = new ForceFrame3d<20, 6+nwm.value*2, nwm.value>(tag, + nodes, sections, + beamIntegr, *tb, + mass, options.mass_flag, use_mass, + max_iter, tol + ); + } + }); + } + } + } + + else if (strcmp(name, "ExactFrame") == 0) { + if (!options.shear_flag) { + opserr << OpenSees::PromptValueError + << "ExactFrame3d requires shear formulation" + << OpenSees::SignalMessageEnd; + return nullptr; + } + int ndf = builder.getNDF(); + if (sections.size() < nodev.size()-1) + for (unsigned i = 0; i < nodev.size()-1; ++i) + sections.push_back(sections[0]); + + unsigned nen = nodev.size(); + static_loop<2,6>([&](auto nn) constexpr { + if (nn.value == nen) { + std::array nodes; + std::copy_n(nodev.begin(), nn.value, nodes.begin()); + static_loop<0,4>([&](auto nwm) constexpr { + if (nwm.value+6 == ndf) + theElement = new ExactFrame3d(tag, nodes, sections.data(), *theTransf); + }); + } + }); + if (theElement == nullptr) { + opserr << OpenSees::PromptValueError + << "invalid number of dofs for ExactFrame; got " << ndf + << OpenSees::SignalMessageEnd; + return nullptr; + } + } + } + + else if (strcmp(name, "elasticForceBeamColumn") == 0) + theElement = new ElasticForceBeamColumn3d(tag, iNode, jNode, nIP, secptrs, + beamIntegr, *theTransf, mass); + + else if (strcasecmp(name, "dispBeamColumn") == 0) + theElement = new DispBeamColumn3d(tag, iNode, jNode, nIP, secptrs, + beamIntegr, *theTransf, + mass, options.mass_flag); + + else if (strcmp(name, "dispBeamColumnWithSensitivity") == 0) + theElement = new DispBeamColumn3d( + tag, iNode, jNode, nIP, secptrs, beamIntegr, *theTransf, mass); + + else if (strcmp(name, "dispBeamColumnThermal") == 0) + theElement = new DispBeamColumn3dThermal( + tag, iNode, jNode, nIP, secptrs, beamIntegr, *theTransf, mass); + + else if (strcmp(name, "forceBeamColumnCBDI") == 0) + theElement = new ForceBeamColumnCBDI3d(tag, iNode, jNode, nIP, secptrs, + beamIntegr, *theTransf, + mass, false, max_iter, tol); + else + theElement = new ForceBeamColumn3d(tag, iNode, jNode, nIP, secptrs, + beamIntegr, *theTransf, mass, max_iter, tol); + } + return theElement; +} + + +// 0 1 2 3 4 +// element beam 1 $i $j 0 1 2 +// +// a) +// 0 1 2 3 4 5 6 +// 0 1 +// element $type $tag $ndi $ndj $trn "Gauss arg1 arg2 ..." +// <-mass $mass> <-iter $iter $tol> +// +// b) +// 0 1 +// element(type, tag, ndi, ndj, trn, itag, +// iter=(10, 1e-12), mass=0.0) +// +// c) "Original/Obsolete" +// 0 1 2 +// element $type $tag $ndi $ndj $nip $sec $trn +// <-mass $mass> <-iter $iter $tol> <-integration $ityp> +// +// d) +// 0 1 ... (2 + nIP) +// element $type $tag $ndi $ndj $nip -sections ... $trn +// <-mass $massDens> <-cMass> <-integration $ityp> +// +// e) +// 0 +// element $type $tag $ndi $ndj $trn +// -sections {...} +// <-mass $massDens> <-cMass> <-integration $ityp> +// +// +// Integration may be specitied as either +// i ) a single name, +// ii ) a pattern spec, or +// iii) a tag for a pattern +// +// if a list of sections is given with -sections, or nIP is provided, then +// we must have an integration with the form (i) +// +// 1) Parse common keyword args: +// "-mass" $mass, +// "-cMass"/"-lMass" +// "-mass-form" $form +// +// "-iter" $iter $tol, +// +// "-integration" $Integration +// - first try parsing $Integration as integer ($itag, form (iii)) +// if successfull, populate section_tags and continue +// - next try parsing $Integration as basic quadrature ($ityp, form (i)) +// - finally, try parsing as full pattern spec +// +// "-section" $Tag +// +// "-transform" $Tag +// "-vertical" {} +// "-horizontal" {} +// +// "-sections" $SectionTags +// - if cannot split $SectionTags as list, then +// mark "-sections" as positional and continue +// with keyword loop +// - Check if "-integration" was provided already; if so, it must have been in form (i); +// otherwise throw an error. +// - Parse $SectionTags +// -sections {...} may occur anywhere +// -sections ... must occur after nIP is obtained +// +// +// 2) +// If pos[1] == "-sections" then command is Form (d): +// nIP = pos[0] +// trn = pos[2+nIP] +// +// else +// +// switch (pos.size()) +// case 1: // Form (e) +// trn = pos[0] +// if (section_tags.size() == 0) +// ERROR +// +// case 2: +// // Form (a) or (b) +// trn = pos[0] +// if GetInt(interp, pos[1]): +// itag = pos[1] +// else +// ParseHingeScheme(pos[1]) +// +// case 3: +// // Form (c) +// nip = int(pos[0]) +// sec = int(pos[1]) +// trn = int(pos[2]) +// +int +TclBasicBuilder_addForceBeamColumn(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char **const argv) +{ + assert(clientData != nullptr); + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + Domain *domain = builder->getDomain(); + assert(domain != nullptr); + + int status = TCL_OK; + +//enum class GaussMethod { +// None, +// Rule, // Quadrature name + section locations; Hinge methods +// Quad, // Quadrature name +//} gauss_method = GaussMethod::None; + + // collect positional arguments + std::vector positions; + + + // + // Preliminary checks + // + int ndm = builder->getNDM(); + int ndf = builder->getNDF(); + + { // Check dimension and DOFs of problem + int ok = 0; + if ((ndm == 2 && ndf == 3) || (ndm == 2 && ndf == 4)) + ok = 1; + if (ndm == 3 && ndf >= 6) + ok = 1; + + if (ok == 0) { + opserr << OpenSees::PromptValueError << "ndm = " << ndm << " and ndf = " << ndf + << " not compatible with Frame element" << "\n"; + return TCL_ERROR; + } + } + + if (argc < 6) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + return TCL_ERROR; + } + + // + // Required positional arguments + // + int tag; + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid " << " tag " << tag << "\n"; + return TCL_ERROR; + } + + int argi = 5; + // int iNode=0, jNode=0; + // bool multi_node = false; + std::vector multi_nodes; + { + int list_argc; + TCL_Char **list_argv; + if (Tcl_SplitList(interp, argv[3], &list_argc, &list_argv) == TCL_OK && list_argc >= 2) { + argi -= 1; + + for (int i = 0; i < list_argc; ++i) { + int node; + if (Tcl_GetInt(interp, list_argv[i], &node) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid node\n"; + return TCL_ERROR; + } + multi_nodes.push_back(node); + } + Tcl_Free((char *)list_argv); + } + else { + int iNode, jNode; + if (Tcl_GetInt(interp, argv[3], &iNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid iNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[4], &jNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid jNode\n"; + return TCL_ERROR; + } + multi_nodes.push_back(iNode); + multi_nodes.push_back(jNode); + } + } + + int max_iter = 10; + double tol = 1.0e-12; + double mass = 0.0; + bool use_mass = false; + int transfTag; + std::vector section_tags; + const char* integration_type = nullptr; + BeamIntegration *beamIntegr = nullptr; + BeamIntegrationRule *theRule = nullptr; + int itg_tag; + + // If we get a BeamIntegration from a BeamIntegrationRule + // then we dont own it and can't delete it + bool deleteBeamIntegr = true; + bool removeHingeIntegr = false; + + // + // Defaults + // + struct Options options; + options.mass_flag = 0; + options.shear_flag = -1; + options.geom_flag = 0; + if (strcasecmp(argv[1], "elasticBeamColumn") == 0) { + options.shear_flag = 0; + } + if (strcasecmp(argv[1], "dispBeamColumn") == 0 || + strcasecmp(argv[1], "nonlinearBeamColumn") == 0) { + options.shear_flag = 0; + } + else if (strcasecmp(argv[1], "timoshenkoBeamColumn") == 0) { + options.shear_flag = 1; + } + + + // + // Parse positions + // + { + while (argi < argc) { + // Shear + if (strcmp(argv[argi], "-shear") == 0) { + if (argc < argi + 2) { + opserr << OpenSees::PromptValueError << "not enough arguments, expected -shear $flag\n"; + status = TCL_ERROR; + goto clean_up; + } + if (Tcl_GetInt(interp, argv[argi + 1], &options.shear_flag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid shear_flag, expected integer\n"; + status = TCL_ERROR; + goto clean_up; + } + argi += 2; + } + + // Geometry + else if (strcmp(argv[argi], "-order") == 0) { + if (argc < argi + 2) { + opserr << OpenSees::PromptValueError << "not enough arguments, expected -order $flag\n"; + status = TCL_ERROR; + goto clean_up; + } + if (Tcl_GetInt(interp, argv[argi + 1], &options.geom_flag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid geom_flag, expected integer\n"; + status = TCL_ERROR; + goto clean_up; + } + argi += 2; + } + + // -iter $max_iter $tol + else if (strcmp(argv[argi], "-iter") == 0) { + if (argc < argi + 3) { + opserr << OpenSees::PromptValueError << "not enough -iter args need -iter max_iter? tol?\n"; + status = TCL_ERROR; + goto clean_up; + } + if (Tcl_GetInt(interp, argv[argi + 1], &max_iter) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid max_iter\n"; + status = TCL_ERROR; + goto clean_up; + } + if (Tcl_GetDouble(interp, argv[argi + 2], &tol) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid tol\n"; + status = TCL_ERROR; + goto clean_up; + } + argi += 3; + } + // mass + else if (strcmp(argv[argi], "-mass") == 0) { + if (argc < argi + 2) { + opserr << OpenSees::PromptValueError << "not enough arguments, expected -mass $mass\n"; + status = TCL_ERROR; + goto clean_up; + } + if (Tcl_GetDouble(interp, argv[argi + 1], &mass) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid mass\n"; + status = TCL_ERROR; + goto clean_up; + } + argi += 2; + use_mass = true; + + // mass type + } else if ((strcmp(argv[argi], "-lMass") == 0) || + (strcmp(argv[argi], "lMass") == 0)) { + options.mass_flag = 0; + argi++; + } + else if ((strcmp(argv[argi], "-cMass") == 0) || + (strcmp(argv[argi], "cMass") == 0)) { + options.mass_flag = 1; + argi++; + } + + // Quadrature + else if (strcmp(argv[argi], "-integration") == 0) { + if (argc < argi + 2) { + opserr << OpenSees::PromptValueError << "not enough arguments, expected -integration $integration\n"; + status = TCL_ERROR; + goto clean_up; + } + + argi++; + integration_type = argv[argi]; + // beamIntegr = GetBeamIntegration(argv[argi]); + + // if (beamIntegr == nullptr) { + // opserr << OpenSees::PromptValueError << "invalid integration type\n"; + // status = TCL_ERROR; + // goto clean_up; + // } + argi++; + } + + // Transform + else if (strcmp(argv[argi], "-transform") == 0) { + if (argc < argi + 2) { + opserr << OpenSees::PromptValueError << "not enough arguments, expected -transform $transform\n"; + status = TCL_ERROR; + goto clean_up; + } + + argi++; + if (Tcl_GetInt(interp, argv[argi], &transfTag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid transform\n"; + status = TCL_ERROR; + goto clean_up; + } + argi++; + } + + // Section + else if (strcmp(argv[argi], "-section") == 0) { + if (argc < argi + 2) { + opserr << OpenSees::PromptValueError << "not enough arguments, expected -section $section\n"; + status = TCL_ERROR; + goto clean_up; + } + + argi++; + int sec_tag; + if (Tcl_GetInt(interp, argv[argi], &sec_tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid sec_tag\n"; + status = TCL_ERROR; + goto clean_up; + } + + section_tags.push_back(sec_tag); + + argi++; + } + + + //else if (strcmp(argv[argi], "-sections") == 0) { + // split possible lists present in argv + //char *List = Tcl_Merge(inArgc, inArgv); + //if (List == nullptr) { + // opserr << OpenSees::PromptValueError << "problem merging list\n"; + // return TCL_ERROR; + //} + // int secc; + // TCL_Char ** secv; + // if (Tcl_SplitList(interp, argv[positions[2]], &secc, &secv) != TCL_OK) { + // opserr << OpenSees::PromptValueError << "problem splitting list\n"; + // return TCL_ERROR; + // } + //Tcl_Free((char *)List); + + //} + else { + positions.push_back(argi); + argi++; + } + } + } + + // + // II Parse Positional Arguments + // + + // Version d) + // positional arguments are: + // 0: nIP + // 1: -sections + // 2: secTag1 + // 3: secTag2... + if (positions.size() > 1 && strcmp(argv[positions[1]], "-sections") == 0) { + + int nIP; + if (Tcl_GetInt(interp, argv[positions[0]], &nIP) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid nIP\n"; + status = TCL_ERROR; + goto clean_up; + } + // TODO: Make sure 2+nIP < positions.size() + + // Get section tags + for (int i = 0; i < nIP; i++) { + int secTag; + if (Tcl_GetInt(interp, argv[positions[2+i]], &secTag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid section\n"; + status = TCL_ERROR; + goto clean_up; + } + section_tags.push_back(secTag); + } + + if (Tcl_GetInt(interp, argv[positions[2+nIP]], &transfTag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid transform\n"; + status = TCL_ERROR; + goto clean_up; + } + + } + + // Version e) ? + else if (positions.size() == 1) { + if (section_tags.empty()) { + status = TCL_ERROR; + goto clean_up; + } + } + + // Version a or b + else if (positions.size() == 2 || positions.size() > 3) { + // Here we create a BeamIntegrationRule (theRule) which is a pair of + // section tags and a BeamIntegration. In this case we do not + // delete the BeamIntegration because it is owned by theRule. + + // Geometric transformation + if (Tcl_GetInt(interp, argv[positions[0]], &transfTag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid transform " << argv[positions[0]] + << OpenSees::SignalMessageEnd; + status = TCL_ERROR; + goto clean_up; + } + + // Version b) + if (Tcl_GetInt(interp, argv[positions[1]], &itg_tag) == TCL_OK) { + deleteBeamIntegr = false; + removeHingeIntegr = false; + } + + // Version a) + else { + // If we fail to parse an integer tag for the integration, + // then we assume that the integration is specified as a + // BeamIntegration command + builder->findFreeTag(itg_tag); + std::string integrCommand{argv[positions[1]]}; + if (integrCommand.find(" ") == std::string::npos) { + for (int i =2; i< positions.size(); i++) { + integrCommand += " " + std::string(argv[positions[i]]); + } + } + integrCommand.insert(integrCommand.find(" "), " "+std::to_string(itg_tag)+" "); + integrCommand.insert(0, "beamIntegration "); + if (Tcl_Eval(interp, integrCommand.c_str()) != TCL_OK) { + opserr << OpenSees::PromptValueError << "failed to parse integration\n"; + status = TCL_ERROR; + goto clean_up; + } + + deleteBeamIntegr = false; + removeHingeIntegr = true; + } + + theRule = builder->getTypedObject(itg_tag); + if (theRule == nullptr) { + status = TCL_ERROR; + goto clean_up; + } + + beamIntegr = theRule->getBeamIntegration(); + const ID& secTags = theRule->getSectionTags(); + + for (int i=0; i < secTags.Size(); i++) + section_tags.push_back(secTags(i)); + } + + // Version c) + // + // .. nip section transf + else if (positions.size() == 3) { + + int nIP; + if (Tcl_GetInt(interp, argv[positions[0]], &nIP) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid nIP\n"; + status = TCL_ERROR; + goto clean_up; + } + if (nIP <= 0) { + opserr << OpenSees::PromptValueError << "invalid nIP, must be > 0\n"; + status = TCL_ERROR; + goto clean_up; + } + + // + int secTag; + if (Tcl_GetInt(interp, argv[positions[1]], &secTag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid secTag\n"; + status = TCL_ERROR; + goto clean_up; + } + + for (int i=0; i < nIP; i++) + section_tags.push_back(secTag); + + // Transform + if (Tcl_GetInt(interp, argv[positions[2]], &transfTag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid transform\n"; + status = TCL_ERROR; + goto clean_up; + } + } + + // + // Finalize the quadrature + // + // TODO + if (section_tags.size() == 1 && theRule == nullptr) { + if (strstr(argv[1], "isp") == 0) { + section_tags.resize(5, section_tags[0]); + } else { + section_tags.resize(5, section_tags[0]); + } + } + + if (beamIntegr == nullptr) { + if (integration_type == nullptr) { + if (strstr(argv[1], "ispBeam") == 0) { + integration_type = "Lobatto"; + } else { + integration_type = "Legendre"; + } + } + + if ((beamIntegr = GetBeamIntegration(integration_type, section_tags.size())) == nullptr) { + opserr << OpenSees::PromptValueError << "invalid integration type or size\n"; + status = TCL_ERROR; + goto clean_up; + } + deleteBeamIntegr = true; + } + + // + // + options.use_mass = use_mass; + { + Element *theElement = ndm == 2 + ? CreateFrame<2, CrdTransf, FrameSection>(*builder, argv[1], tag, multi_nodes, transfTag, + section_tags, *beamIntegr, mass, max_iter, tol, options) + : CreateFrame<3, CrdTransf, FrameSection>(*builder, argv[1], tag, multi_nodes, transfTag, + section_tags, *beamIntegr, mass, max_iter, tol, options); + + + if (theElement == nullptr) { + status = TCL_ERROR; + goto clean_up; + } + if (domain->addElement(theElement) == false) { + opserr << OpenSees::PromptValueError + << "could not add element to the domain" + << OpenSees::SignalMessageEnd; + delete theElement; + status = TCL_ERROR; + goto clean_up; + } + } + + +clean_up: + // + // Clean up + // + if (deleteBeamIntegr && beamIntegr != nullptr) + delete beamIntegr; + + if (removeHingeIntegr) { + builder->removeObject(itg_tag); + delete theRule; + } + + return status; +} + + +// +// BeamWithHinges +// +// element beamWithHinges tag? ndI? ndJ? secTagI? lenI? secTagJ? lenJ? +// E? A? I? transfTag? <-shear shearLength?> <-mass massDens?> +// <-iter maxIters tolerance> +// +int +TclBasicBuilder_addBeamWithHinges(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + + int NDM = builder->getNDM(); + int NDF = builder->getNDF(); + + // Plane frame element + if (NDM == 2 && NDF == 3) { + if (argc < 13) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: element beamWithHinges tag? ndI? ndJ? secTagI? lenI? " + "secTagJ? lenJ? "; + opserr << "E? A? I? transfTag? <-shear shearLength?> <-mass massDens?> " + "<-iter maxIters tolerance>" + << "\n"; + return TCL_ERROR; + } + + double massDens = 0.0; + int max_iters = 10; + double tol = 1.0e-10; + int tag, ndI, ndJ, secTagI, secTagJ, transfTag; + double lenI, lenJ, E, A, I; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid beamWithHinges tag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3], &ndI) != TCL_OK) { + opserr << "WARNING invalid ndI\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[4], &ndJ) != TCL_OK) { + opserr << "WARNING invalid ndJ\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[5], &secTagI) != TCL_OK) { + opserr << "WARNING invalid secTagI\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[6], &lenI) != TCL_OK) { + opserr << "WARNING invalid lenI\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[7], &secTagJ) != TCL_OK) { + opserr << "WARNING invalid ndJ\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[8], &lenJ) != TCL_OK) { + opserr << "WARNING invalid lenJ\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[9], &E) != TCL_OK) { + opserr << "WARNING invalid E\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[10], &A) != TCL_OK) { + opserr << "WARNING invalid A\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[11], &I) != TCL_OK) { + opserr << "WARNING invalid I\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[12], &transfTag) != TCL_OK) { + opserr << "WARNING invalid transfTag\n"; + return TCL_ERROR; + } + + bool isShear = false; + int shearTag = 0; + + if (argc > 13) { + for (int i = 13; i < argc; ++i) { + if (strcmp(argv[i], "-mass") == 0 && ++i < argc) { + if (Tcl_GetDouble(interp, argv[i], &massDens) != TCL_OK) { + opserr << "WARNING invalid massDens\n"; + opserr << "BeamWithHinges: " << tag << "\n"; + return TCL_ERROR; + } + } + + if (strcmp(argv[i], "-constHinge") == 0 && ++i < argc) { + if (Tcl_GetInt(interp, argv[i], &shearTag) != TCL_OK) { + opserr << "WARNING invalid constHinge tag\n"; + opserr << "BeamWithHinges: " << tag << "\n"; + return TCL_ERROR; + } + isShear = true; + } + + if (strcmp(argv[i], "-iter") == 0 && i + 2 < argc) { + if (Tcl_GetInt(interp, argv[++i], &max_iters) != TCL_OK) { + opserr << "WARNING invalid maxIters\n"; + opserr << "BeamWithHinges: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[++i], &tol) != TCL_OK) { + opserr << "WARNING invalid tolerance\n"; + opserr << "BeamWithHinges: " << tag << "\n"; + return TCL_ERROR; + } + } + } + } + + // Retrieve section I from the model builder + FrameSection *sectionI = builder->getTypedObject(secTagI); + if (sectionI == nullptr) + return TCL_ERROR; + + // Retrieve section J from the model builder + FrameSection *sectionJ = builder->getTypedObject(secTagJ); + if (sectionJ == nullptr) + return TCL_ERROR; + + + CrdTransf *theTransf = builder->getTypedObject(transfTag); + if (theTransf == nullptr) + return TCL_ERROR; + + Element *theElement = nullptr; + int numSections = 0; + SectionForceDeformation *sections[10]; + BeamIntegration *theBeamIntegr = nullptr; + + ElasticSection2d elastic(8, E, A, I); + + if (strcmp(argv[1], "beamWithHinges1") == 0) { + theBeamIntegr = new HingeMidpointBeamIntegration(lenI, lenJ); + + numSections = 4; + + sections[0] = sectionI; + sections[1] = &elastic; + sections[2] = &elastic; + sections[3] = sectionJ; + + } else if (strcmp(argv[1], "beamWithHinges2") == 0) { + theBeamIntegr = new HingeRadauTwoBeamIntegration(lenI, lenJ); + + numSections = 6; + sections[0] = sectionI; + sections[1] = sectionI; + sections[2] = &elastic; + sections[3] = &elastic; + sections[4] = sectionJ; + sections[5] = sectionJ; + + } else if (strcmp(argv[1], "beamWithHinges3") == 0 || + strcmp(argv[1], "beamWithHinges") == 0) { + theBeamIntegr = new HingeRadauBeamIntegration(lenI, lenJ); + + numSections = 6; + sections[0] = sectionI; + sections[1] = &elastic; + sections[2] = &elastic; + sections[3] = &elastic; + sections[4] = &elastic; + sections[5] = sectionJ; + + } else if (strcmp(argv[1], "beamWithHinges4") == 0) { + theBeamIntegr = new HingeEndpointBeamIntegration(lenI, lenJ); + + numSections = 4; + sections[0] = sectionI; + sections[1] = &elastic; + sections[2] = &elastic; + sections[3] = sectionJ; + } + + if (theBeamIntegr == nullptr) { + opserr << "Unknown element type: " << argv[1] << "\n"; + return TCL_ERROR; + } + + if (isShear) { + FrameSection *sectionL = builder->getTypedObject(shearTag); + if (sectionL == nullptr) + return TCL_ERROR; + + sections[numSections++] = sectionL; + } + + theElement = new ForceBeamColumn2d(tag, ndI, ndJ, numSections, + sections, + *theBeamIntegr, *theTransf, massDens, + max_iters, tol); + + delete theBeamIntegr; + + if (builder->getDomain()->addElement(theElement) == false) { + opserr << "WARNING could not add element to domain.\n"; + return TCL_ERROR; + } + } + + else if (NDM == 3 && NDF == 6) { + if (argc < 16) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: element beamWithHinges tag? ndI? ndJ? secTagI? lenI? " + "secTagJ? lenJ? "; + opserr << "E? A? Iz? Iy? G? J? transfTag? <-shear shearLength?> <-mass " + "massDens?> <-iter maxIters tolerance>" + << "\n"; + return TCL_ERROR; + } + + int tag, ndI, ndJ, secTagI, secTagJ, transfTag; + double lenI, lenJ, E, A, Iz, Iy, G, J; + double massDens = 0.0; + int max_iters = 10; + double tol = 1.0e-10; + double shearLength = 1.0; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid beamWithHinges tag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3], &ndI) != TCL_OK) { + opserr << "WARNING invalid ndI\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[4], &ndJ) != TCL_OK) { + opserr << "WARNING invalid ndJ\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[5], &secTagI) != TCL_OK) { + opserr << "WARNING invalid secTagI\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[6], &lenI) != TCL_OK) { + opserr << "WARNING invalid lenI\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[7], &secTagJ) != TCL_OK) { + opserr << "WARNING invalid ndJ\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[8], &lenJ) != TCL_OK) { + opserr << "WARNING invalid lenJ\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[9], &E) != TCL_OK) { + opserr << "WARNING invalid E\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[10], &A) != TCL_OK) { + opserr << "WARNING invalid A\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[11], &Iz) != TCL_OK) { + opserr << "WARNING invalid Iz\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[12], &Iy) != TCL_OK) { + opserr << "WARNING invalid Iy\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[13], &G) != TCL_OK) { + opserr << "WARNING invalid G\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[14], &J) != TCL_OK) { + opserr << "WARNING invalid J\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[15], &transfTag) != TCL_OK) { + opserr << "WARNING invalid transfTag\n"; + return TCL_ERROR; + } + + + if (argc > 16) { + for (int i = 16; i < argc; ++i) { + if (strcmp(argv[i], "-mass") == 0 && ++i < argc) { + if (Tcl_GetDouble(interp, argv[i], &massDens) != TCL_OK) { + opserr << "WARNING invalid massDens\n"; + opserr << "BeamWithHinges: " << tag << "\n"; + return TCL_ERROR; + } + } + + if (strcmp(argv[i], "-shear") == 0 && ++i < argc) { + if (Tcl_GetDouble(interp, argv[i], &shearLength) != TCL_OK) { + opserr << "WARNING invalid shear\n"; + return TCL_ERROR; + } + } + + if (strcmp(argv[i], "-iter") == 0 && i + 2 < argc) { + if (Tcl_GetInt(interp, argv[++i], &max_iters) != TCL_OK) { + opserr << "WARNING invalid maxIters\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[++i], &tol) != TCL_OK) { + opserr << "WARNING invalid tolerance\n"; + return TCL_ERROR; + } + } + } + } + + // Retrieve section I from the model builder + SectionForceDeformation *sectionI = builder->getTypedObject(secTagI); + if (sectionI == nullptr) + return TCL_ERROR; + + // Retrieve section J from the model builder + SectionForceDeformation *sectionJ = builder->getTypedObject(secTagJ); + if (sectionJ == nullptr) + return TCL_ERROR; + + + CrdTransf *theTransf = builder->getTypedObject(transfTag); + if (theTransf == nullptr) + return TCL_ERROR; + + + Element *theElement = nullptr; + int numSections = 0; + SectionForceDeformation *sections[10]; + BeamIntegration *theBeamIntegr = nullptr; + + ElasticSection3d elastic(0, E, A, Iz, Iy, G, J); + + if (strcmp(argv[1], "beamWithHinges1") == 0) { + theBeamIntegr = new HingeMidpointBeamIntegration(lenI, lenJ); + + numSections = 4; + sections[0] = sectionI; + sections[1] = &elastic; + sections[2] = &elastic; + sections[3] = sectionJ; + + } else if (strcmp(argv[1], "beamWithHinges2") == 0) { + theBeamIntegr = new HingeRadauTwoBeamIntegration(lenI, lenJ); + + numSections = 6; + sections[0] = sectionI; + sections[1] = sectionI; + sections[2] = &elastic; + sections[3] = &elastic; + sections[4] = sectionJ; + sections[5] = sectionJ; + + } else if (strcmp(argv[1], "beamWithHinges3") == 0 || + strcmp(argv[1], "beamWithHinges") == 0) { + theBeamIntegr = new HingeRadauBeamIntegration(lenI, lenJ); + + numSections = 6; + sections[0] = sectionI; + sections[1] = &elastic; + sections[2] = &elastic; + sections[3] = &elastic; + sections[4] = &elastic; + sections[5] = sectionJ; + + } else if (strcmp(argv[1], "beamWithHinges4") == 0) { + theBeamIntegr = new HingeEndpointBeamIntegration(lenI, lenJ); + + numSections = 4; + sections[0] = sectionI; + sections[1] = &elastic; + sections[2] = &elastic; + sections[3] = sectionJ; + } + + if (theBeamIntegr == nullptr) { + opserr << "Unknown element type: " << argv[1] << "\n"; + return TCL_ERROR; + } + + // TODO fix shear for beamWithHinges + /* + if (isShear) { + SectionForceDeformation *sectionL = builder->getTypedObject(shearTag); + + if (sectionL == 0) { + opserr << "WARNING section L does not exist\n"; + opserr << "section: " << shearTag; + opserr << "\nBeamWithHinges: " << tag << "\n"; + return TCL_ERROR; + } + sections[numSections++] = sectionL; + } + */ + + theElement = new ForceBeamColumn3d(tag, ndI, ndJ, numSections, sections, + *theBeamIntegr, *theTransf, massDens, + max_iters, tol); + + delete theBeamIntegr; + + // Add to the domain + if (builder->getDomain()->addElement(theElement) == false) { + opserr << "WARNING could not add " + "element to domain "; + opserr << tag << "\n"; + return TCL_ERROR; + } + } + + else { + opserr << "ERROR -- model dimension: " << NDM + << " and nodal degrees of freedom: " << NDF + << " are incompatible for BeamWithHinges element" << "\n"; + return TCL_ERROR; + } + + return TCL_OK; +} diff --git a/SRC/runtime/commands/modeling/element/plane.cpp b/SRC/runtime/commands/modeling/element/plane.cpp new file mode 100644 index 0000000000..23db57e5b1 --- /dev/null +++ b/SRC/runtime/commands/modeling/element/plane.cpp @@ -0,0 +1,1262 @@ +//===----------------------------------------------------------------------===// +// +// OpenSees - Open System for Earthquake Engineering Simulation +// +//===----------------------------------------------------------------------===// +// +// Description: This file contains the implementation of the +// TclBasicBuilder_addFourNodeQuad() command. +// +// Written: fmk +// Created: 07/99 +// +#include +#include +#include +#include +#include +#ifdef _MSC_VER +# include +# define strcasecmp _stricmp +#else +# include +#endif +#include +#include +#include +#include +#include +#include
+#include +#include +#include +#include +#include +#include +#include +#include +#include +// +#include +#include +#include + +#include +#include + +namespace { +static +std::string toLower( const std::string & s ) +{ + std::string copy = s; + transform( copy.begin( ), copy.end( ), copy.begin( ), + [](unsigned char c) { return std::tolower(c); }); + return copy; +} + +static bool +equalsIgnoreCase(const std::string & lhs, const std::string & rhs ) +{ + return toLower(lhs) == toLower( rhs ); +} + +class CaseInsensitive +{ + public: + size_t operator( ) ( const std::string & s ) const + { + static std::hash hf; + return hf( toLower( s ) ); + } + + bool operator( ) ( const std::string & lhs, const std::string & rhs ) const + { + return equalsIgnoreCase( lhs, rhs ); + } +}; +} // namespace + +using namespace OpenSees; + +static std::unordered_map +NodeCounts = { + {"Quad", 4}, + {"FourNodeQuad", 4}, + {"quad8n", 8}, + {"EightNodeQuad", 8}, + {"FourNodeQuad3d", 4}, + {"FourNodeQuadWithSensitivity", 4}, + {"ConstantPressureVolumeQuad", 4}, + {"EnhancedQuad", 4}, + {"NineNodeQuad", 9}, + {"quad9n", 9}, + {"NineNodeMixedQuad", 9}, + {"LagrangeQuad", 4}, + {"Tri31", 3}, + {"CST", 3}, + {"T3", 3}, + {"SixNodeTri", 6} +}; + +int +TclBasicBuilder_addFourNodeQuad(ClientData clientData, Tcl_Interp *interp, int argc, + TCL_Char ** const argv) +{ + assert(clientData != nullptr); + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 + // 10 element name eleTag? iNode? jNode? kNode? lNode? thk? type? matTag? + // 14 element name eleTag? iNode? jNode? kNode? lNode? thk? type? matTag? + // + // element name eleTag? iNode? jNode? kNode? lNode? sec? + + if (builder->getNDM() != 2 || (builder->getNDF() != 2 && builder->getNDF() != 3)) { + opserr << OpenSees::PromptValueError + << "model dimensions and/or nodal DOF not compatible with quad element\n"; + return TCL_ERROR; + } + + + int tag; + if (argc < 6) { + opserr << OpenSees::PromptValueError + << "insufficient arguments for element " << argv[1] + << "\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid element tag " << argv[2] + << "\n"; + return TCL_ERROR; + } + int nen = -1; + + auto it = NodeCounts.find(argv[1]); + if (it != NodeCounts.end()) + nen = it->second; + + int argi = 3; + std::vector multi_nodes; + { + int list_argc; + TCL_Char **list_argv; + if (Tcl_SplitList(interp, argv[argi], &list_argc, &list_argv) == TCL_OK && list_argc >= 2) { + for (int i = 0; i < list_argc; ++i) { + int node; + if (Tcl_GetInt(interp, list_argv[i], &node) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid node " << list_argv[i] + << "\n"; + return TCL_ERROR; + } + multi_nodes.push_back(node); + } + nen = multi_nodes.size(); + Tcl_Free((char *)list_argv); + argi += 1; + + } else { + if (nen == -1) { + opserr << OpenSees::PromptValueError + << "Nodes must be supplied in a list for element type " << argv[1] + << "\n"; + return TCL_ERROR; + } + if (argi + nen > argc) { + opserr << OpenSees::PromptValueError + << "expected " << nen << " nodes for element type " << argv[1] + << "\n"; + return TCL_ERROR; + } + for (int i=0; i tracker; + std::set positional; + + // + // Keywords + // + for (int i=argi; i* section = builder->getTypedObject>(stag); + if (section == nullptr) + return TCL_ERROR; + + thickness = section->getThickness(); + nd_mat = section->getMaterial(); + mat_tag = nd_mat->getTag(); + tracker.consume(Position::Material); + tracker.consume(Position::Type); + tracker.consume(Position::Thickness); + } + else + // continue; + positional.insert(i); + } + + // + // Positional arguments + // + for (int i : positional) { + switch (tracker.current()) { + case Position::Material: + if (Tcl_GetInt(interp, argv[i], &mat_tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid material tag " << argv[i] << "\n"; + return TCL_ERROR; + } else { + nd_mat = builder->getTypedObject(mat_tag); + if (nd_mat == nullptr) + return TCL_ERROR; + + nd_mat = nd_mat->getCopy(type); + if (nd_mat == nullptr) { + opserr << OpenSees::PromptValueError << "invalid material\n"; + return TCL_ERROR; + } + } + tracker.increment(); + break; + + case Position::Thickness: + if (Tcl_GetDouble(interp, argv[i], &thickness) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid thickness\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::Type: + type = argv[i]; + + if (strcmp(type,"PlaneStrain") != 0 && + strcmp(type,"PlaneStress") != 0 && + strcmp(type,"PlaneStrain2D") != 0 && + strcmp(type,"PlaneStress2D") != 0) { + opserr << OpenSees::PromptValueError + << "improper material type: " << type << "\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::Pressure: + if (Tcl_GetDouble(interp, argv[i], &p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid pressure\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::Density: + if (Tcl_GetDouble(interp, argv[i], &rho) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid density\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::B1: + if (Tcl_GetDouble(interp, argv[i], &b1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b1\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::B2: + if (Tcl_GetDouble(interp, argv[i], &b2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b2\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::End: + default: + opserr << OpenSees::PromptParseError << "unexpected argument " << argv[i] << "\n"; + return TCL_ERROR; + } + } + // + // Check required positional arguments + // + while (tracker.current() != Position::End) { + switch (tracker.current()) { + case Position::Thickness: + opserr << OpenSees::PromptValueError + << "missing required positional argument thickness\n"; + return TCL_ERROR; + case Position::Type: + opserr << OpenSees::PromptValueError + << "missing required positional argument type\n"; + return TCL_ERROR; + case Position::Material: + opserr << OpenSees::PromptValueError + << "missing required positional argument material\n"; + return TCL_ERROR; + default: + break; + } + tracker.increment(); + } + } + + + // + // + // + Element* theElement = nullptr; + if (nen == 3) { + if (nd_mat == nullptr) { + opserr << OpenSees::PromptValueError << "invalid material\n"; + return TCL_ERROR; + } + + std::array nodes; + for (int i=0; i<3; i++) + nodes[i] = multi_nodes[i]; + + if (strcasecmp(argv[1], "Tri31") == 0) { + theElement = + new Tri31(tag, nodes, *nd_mat, thickness, p, rho, b1, b2); + } + } + + else if (nen == 4) { + std::array nodes; + for (int i=0; i<4; i++) + nodes[i] = multi_nodes[i]; + + if (strcasecmp(argv[1], "LagrangeQuad") == 0) { + Mate<2> *mat_2d = builder->getTypedObject>(mat_tag); + if (mat_2d == nullptr) + return TCL_ERROR; + + theElement = + new LagrangeQuad<4,4>(tag, nodes, *mat_2d, + thickness, p, rho, b1, b2); + + } else { + if (nd_mat == nullptr) { + opserr << OpenSees::PromptValueError + << "invalid material" + << "\n"; + return TCL_ERROR; + } + if (strcasecmp(argv[1], "EnhancedQuad") == 0) { + theElement = + new EnhancedQuad(tag, nodes, *nd_mat, thickness); + } + else if (strcasecmp(argv[1], "bbarQuad") == 0 || + strcasecmp(argv[1], "mixedQuad") == 0) { + theElement = new ConstantPressureVolumeQuad(tag, nodes[0], nodes[1], nodes[2], nodes[3], *nd_mat, thickness); + + } + else + theElement = + new FourNodeQuad(tag, nodes, *nd_mat, thickness, p, rho, b1, b2); + } + } + + else if (nen == 8) { + std::array nodes; + for (int i=0; i<8; i++) + nodes[i] = multi_nodes[i]; + if ((strcasecmp(argv[1], "eightnodequad") == 0) || + (strcasecmp(argv[1], "quad8n") == 0) || + (strcasecmp(argv[1], "quad") == 0)) { + if (nd_mat == nullptr) { + opserr << OpenSees::PromptValueError + << "invalid material" + << "\n"; + return TCL_ERROR; + } + theElement = + new EightNodeQuad(tag, nodes, *nd_mat, thickness, p, rho, b1, b2); + } + } + else if (nen == 9) { + std::array nodes; + for (int i=0; i<9; i++) + nodes[i] = multi_nodes[i]; + if ((strcasecmp(argv[1], "ninenodequad") == 0) || + (strcasecmp(argv[1], "quad9n") == 0) || + (strcasecmp(argv[1], "quad") == 0)) { + + if (nd_mat == nullptr) { + opserr << OpenSees::PromptValueError + << "invalid material" + << "\n"; + return TCL_ERROR; + } + theElement = + new NineNodeQuad(tag, nodes, *nd_mat, thickness, p, rho, b1, b2); + } + } + + if (theElement == nullptr) { + opserr << OpenSees::PromptValueError << "failed to create element\n"; + return TCL_ERROR; + } + + // + // + // + if (builder->getDomain()->addElement(theElement) == false) { + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + delete theElement; + return TCL_ERROR; + } + + if (type != nullptr) + delete nd_mat; + return TCL_OK; +} + + +int +TclBasicBuilder_addConstantPressureVolumeQuad(ClientData clientData, + Tcl_Interp *interp, int argc, + TCL_Char ** const argv) +{ + assert(clientData != nullptr); + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + + if (builder->getNDM() != 2 || builder->getNDF() != 2) { + opserr << OpenSees::PromptValueError + << "-- model dimensions and/or nodal DOF not compatible " + "with quad element\n"; + return TCL_ERROR; + } + + int argStart = 2; + + // check the number of arguments is correct + if ((argc - argStart) < 7) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: element ConstantPressureVolumeQuad eleTag? iNode? jNode? kNode? lNode? thk? matTag?\n"; + return TCL_ERROR; + } + + // get the id and end nodes + int tag, iNode, jNode, kNode, lNode, matID; + double thickness = 1.0; + + if (Tcl_GetInt(interp, argv[argStart], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid eleTag" << "\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[1 + argStart], &iNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid iNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[2 + argStart], &jNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid jNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3 + argStart], &kNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid kNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[4 + argStart], &lNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid lNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[5 + argStart], &thickness) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid thickness\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[6 + argStart], &matID) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid matID\n"; + return TCL_ERROR; + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + if (theMaterial == nullptr) + return TCL_ERROR; + + + // now create the ConstantPressureVolumeQuad and add it to the Domain + ConstantPressureVolumeQuad *theConstantPressureVolumeQuad = + new ConstantPressureVolumeQuad(tag, + iNode, jNode, kNode, lNode, *theMaterial, thickness); + + + if (builder->getDomain()->addElement(theConstantPressureVolumeQuad) == false) { + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + delete theConstantPressureVolumeQuad; + return TCL_ERROR; + } + + return TCL_OK; +} + + +/* ***************************************************************************** + + N I N E N O D E M I X E D Q U A D + + ***************************************************************************** + */ + +int +TclBasicBuilder_addNineNodeMixedQuad(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + + if (builder->getNDM() != 2 || builder->getNDF() != 2) { + opserr << OpenSees::PromptValueError << "-- model dimensions and/or nodal DOF not compatible " + "with quad element\n"; + return TCL_ERROR; + } + + // check the number of arguments is correct + int argStart = 2; + + if ((argc - argStart) < 11) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: element NineNodeMixedQuad eleTag?" + << " iNode? jNode? kNode? lNode? mNode, nNode, pNode, qNode, centerNode matTag?\n"; + return TCL_ERROR; + } + + // get the id and end nodes + int tag, iNode, jNode, kNode, lNode; + int mNode, nNode, pNode, qNode; + int centerNode; + int matID; + + if (Tcl_GetInt(interp, argv[argStart], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid NineNodeMixedQuad eleTag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[1 + argStart], &iNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid iNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[2 + argStart], &jNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid jNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3 + argStart], &kNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid kNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[4 + argStart], &lNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid lNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[5 + argStart], &mNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid mNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[6 + argStart], &nNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid nNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[7 + argStart], &pNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid pNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[8 + argStart], &qNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid qNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[9 + argStart], ¢erNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid centerNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[10 + argStart], &matID) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid matID\n"; + return TCL_ERROR; + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + if (theMaterial == nullptr) + return TCL_ERROR; + + + // now create the NineNodeMixedQuad and add it to the Domain + NineNodeMixedQuad *theNineNodeMixed = new NineNodeMixedQuad( + tag, iNode, jNode, kNode, lNode, mNode, nNode, pNode, + qNode, centerNode, *theMaterial); + + if (builder->getDomain()->addElement(theNineNodeMixed) == false) { + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + delete theNineNodeMixed; + return TCL_ERROR; + } + + return TCL_OK; +} + +int +TclBasicBuilder_addFourNodeQuadWithSensitivity(ClientData clientData, + Tcl_Interp *interp, int argc, + TCL_Char ** const argv) +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + + if (builder == 0 || clientData == 0) { + opserr << OpenSees::PromptValueError << "builder has been destroyed\n"; + return TCL_ERROR; + } + + if (builder->getNDM() != 2 || builder->getNDF() != 2) { + opserr << OpenSees::PromptValueError << "-- model dimensions and/or nodal DOF not compatible " + "with quad element\n"; + return TCL_ERROR; + } + + // check the number of arguments is correct + int argStart = 2; + + if ((argc - argStart) < 8) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: element FourNodeQuad eleTag? iNode? jNode? kNode? lNode? " + "thk? type? matTag? \n"; + return TCL_ERROR; + } + + // get the id and end nodes + int tag, iNode, jNode, kNode, lNode, matID; + double thickness = 1.0; + double p = 0.0; // uniform normal traction (pressure) + double r = 0.0; // mass density + double b1 = 0.0; + double b2 = 0.0; + + if (Tcl_GetInt(interp, argv[argStart], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid element tag" << "\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[1 + argStart], &iNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid iNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[2 + argStart], &jNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid jNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3 + argStart], &kNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid kNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[4 + argStart], &lNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid lNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[5 + argStart], &thickness) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid thickness\n"; + return TCL_ERROR; + } + + TCL_Char *type = argv[6 + argStart]; + + if (Tcl_GetInt(interp, argv[7 + argStart], &matID) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid matID\n"; + return TCL_ERROR; + } + + if ((argc - argStart) > 11) { + if (Tcl_GetDouble(interp, argv[8 + argStart], &p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid pressure\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[9 + argStart], &r) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid rho\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[10 + argStart], &b1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b1\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[11 + argStart], &b2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b2\n"; + return TCL_ERROR; + } + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + if (theMaterial == nullptr) + return TCL_ERROR; + + + // now create the FourNodeQuad and add it to the Domain + FourNodeQuadWithSensitivity *theFourNodeQuadWithSensitivity = + new FourNodeQuadWithSensitivity(tag, iNode, jNode, kNode, + lNode, *theMaterial, type, thickness, p, + r, b1, b2); + + if (builder->getDomain()->addElement(theFourNodeQuadWithSensitivity) == false) { + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + delete theFourNodeQuadWithSensitivity; + return TCL_ERROR; + } + + return TCL_OK; +} + +// +// Description: This file contains the implementation of +// TclBasicBuilder_addFourNodeQuadUP() , +// TclBasicBuilder_addNineFourNodeQuadUP() , +// TclBasicBuilder_addBBarFourNodeQuadUP(), +// +// Zhaohui Yang and Jinchi Lu (September 2009) +// +#include +#include + +#include +#include +#include + + +/* ***************************************************************************** + + Q U A D U_P + + ***************************************************************************** + */ + +int +TclBasicBuilder_addFourNodeQuadUP(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + + if (builder->getNDM() != 2 || builder->getNDF() != 3) { + opserr << OpenSees::PromptValueError << "-- model dimensions and/or nodal DOF not compatible " + "with QuadUP element\n"; + return TCL_ERROR; + } + + // check the number of arguments is correct + int argStart = 2; + + if ((argc - argStart) < 11) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: element FourNodeQuadUP eleTag? iNode? jNode? kNode? " + "lNode? thk? matTag? bulk? rho? perm_x? perm_y? \n"; + return TCL_ERROR; + } + + // get the id and end nodes + int tag, iNode, jNode, kNode, lNode, matID; + double thickness, bk, r, perm1, perm2; + double p = 0.0; // uniform normal traction (pressure) + double b1 = 0.0; + double b2 = 0.0; + + // TCL_Char *type; + if (Tcl_GetInt(interp, argv[argStart], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid FourNodeQuadUP eleTag" << "\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[1 + argStart], &iNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid iNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[2 + argStart], &jNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid jNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3 + argStart], &kNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid kNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[4 + argStart], &lNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid lNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[5 + argStart], &thickness) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid thickness\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[6 + argStart], &matID) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid matID\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[7 + argStart], &bk) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fluid bulk modulus\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[8 + argStart], &r) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fluid mass density\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[9 + argStart], &perm1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid lateral permeability\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[10 + argStart], &perm2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid vertical permeability\n"; + return TCL_ERROR; + } + + if ((argc - argStart) >= 12) { + if (Tcl_GetDouble(interp, argv[11 + argStart], &b1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b1\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 13) { + if (Tcl_GetDouble(interp, argv[12 + argStart], &b2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b2\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 14) { + if (Tcl_GetDouble(interp, argv[13 + argStart], &p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid pressure\n"; + return TCL_ERROR; + } + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + if (theMaterial == nullptr) + return TCL_ERROR; + + + // now create the FourNodeQuadUP and add it to the Domain + FourNodeQuadUP *theFourNodeQuadUP = new FourNodeQuadUP( + tag, iNode, jNode, kNode, lNode, *theMaterial, "PlaneStrain", + thickness, bk, r, perm1, perm2, b1, b2, p); + + if (builder->getDomain()->addElement(theFourNodeQuadUP) == false) { + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + delete theFourNodeQuadUP; + return TCL_ERROR; + } + + return TCL_OK; +} + + +/* ***************************************************************************** + + 9-4-N O D E Q U A D U_P + + ***************************************************************************** + */ + +int +TclBasicBuilder_addNineFourNodeQuadUP(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + + if (builder == 0 || clientData == 0) { + opserr << OpenSees::PromptValueError << "builder has been destroyed\n"; + return TCL_ERROR; + } + + if (builder->getNDM() != 2) { + opserr << OpenSees::PromptValueError << "-- model dimensions not compatible with 9-4-NodeQuadUP " + "element\n"; + return TCL_ERROR; + } + + // check the number of arguments is correct + int argStart = 2; + + if ((argc - argStart) < 16) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr + << "Want: element FourNodeQuadUP eleTag? Node1? ... Node9? thk? " + "matTag? bulk? rho? perm_x? perm_y? \n"; + return TCL_ERROR; + } + + // get the id and end nodes + int Ninetag, Node[9], matID; + double thickness, bk, r, perm1, perm2; + double b1 = 0.0; + double b2 = 0.0; + + if (Tcl_GetInt(interp, argv[argStart], &Ninetag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid FourNodeQuadUP eleTag" << "\n"; + return TCL_ERROR; + } + for (int i = 1; i <= 9; i++) { + if (Tcl_GetInt(interp, argv[i + argStart], &Node[i - 1]) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid Node\n"; + return TCL_ERROR; + } + } + + if (Tcl_GetDouble(interp, argv[10 + argStart], &thickness) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid thickness\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[11 + argStart], &matID) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid matID\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[12 + argStart], &bk) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fluid bulk modulus\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[13 + argStart], &r) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fluid mass density\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[14 + argStart], &perm1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid lateral permeability\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[15 + argStart], &perm2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid vertical permeability\n"; + return TCL_ERROR; + } + + if ((argc - argStart) >= 17) { + if (Tcl_GetDouble(interp, argv[16 + argStart], &b1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b1\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 18) { + if (Tcl_GetDouble(interp, argv[17 + argStart], &b2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b2\n"; + return TCL_ERROR; + } + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + if (theMaterial == nullptr) + return TCL_ERROR; + + + // now create the FourNodeQuadUP and add it to the Domain + NineFourNodeQuadUP *theNineFourNodeQuadUP = new NineFourNodeQuadUP( + Ninetag, Node[0], Node[1], Node[2], Node[3], Node[4], + Node[5], Node[6], Node[7], Node[8], *theMaterial, "PlaneStrain", + thickness, bk, r, perm1, perm2, b1, b2); + if (theNineFourNodeQuadUP == 0) { + opserr << OpenSees::PromptValueError << "ran out of memory creating element\n"; + return TCL_ERROR; + } + + if (builder->getDomain()->addElement(theNineFourNodeQuadUP) == false) { + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + delete theNineFourNodeQuadUP; + return TCL_ERROR; + } + + return TCL_OK; +} + + +/* ***************************************************************************** + + B B A R Q U A D U_P + + ***************************************************************************** + */ + +int +TclBasicBuilder_addBBarFourNodeQuadUP(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + + if (builder == 0 || clientData == 0) { + opserr << OpenSees::PromptValueError << "builder has been destroyed\n"; + return TCL_ERROR; + } + + if (builder->getNDM() != 2 || builder->getNDF() != 3) { + opserr << OpenSees::PromptValueError + << "model dimensions and/or nodal DOF not compatible " + "with QuadUP element\n"; + return TCL_ERROR; + } + + // check the number of arguments is correct + int argStart = 2; + + if ((argc - argStart) < 11) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: element bbarQuadUP eleTag? iNode? jNode? kNode? lNode? " + "thk? matTag? bulk? rho? perm_x? perm_y? \n"; + return TCL_ERROR; + } + + // get the id and end nodes + int BBartag, iNode, jNode, kNode, lNode, matID; + double thickness, bk, r, perm1, perm2; + double p = 0.0; // uniform normal traction (pressure) + double b1 = 0.0; + double b2 = 0.0; + + if (Tcl_GetInt(interp, argv[argStart], &BBartag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid BBarFourNodeQuadUP eleTag" << "\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[1 + argStart], &iNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid iNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[2 + argStart], &jNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid jNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3 + argStart], &kNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid kNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[4 + argStart], &lNode) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid lNode\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[5 + argStart], &thickness) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid thickness\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[6 + argStart], &matID) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid matID\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[7 + argStart], &bk) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fluid bulk modulus\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[8 + argStart], &r) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fluid mass density\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[9 + argStart], &perm1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid lateral permeability\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[10 + argStart], &perm2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid vertical permeability\n"; + return TCL_ERROR; + } + + if ((argc - argStart) >= 12) { + if (Tcl_GetDouble(interp, argv[11 + argStart], &b1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b1\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 13) { + if (Tcl_GetDouble(interp, argv[12 + argStart], &b2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b2\n"; + return TCL_ERROR; + } + } + if ((argc - argStart) >= 14) { + if (Tcl_GetDouble(interp, argv[13 + argStart], &p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid pressure\n"; + return TCL_ERROR; + } + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + if (theMaterial == nullptr) + return TCL_ERROR; + + + // now create the BBarFourNodeQuadUP and add it to the Domain + BBarFourNodeQuadUP *theBBarFourNodeQuadUP = new BBarFourNodeQuadUP( + BBartag, iNode, jNode, kNode, lNode, *theMaterial, + "PlaneStrain", thickness, bk, r, perm1, perm2, b1, b2, p); + + if (theBBarFourNodeQuadUP == nullptr) { + opserr << OpenSees::PromptValueError << "ran out of memory creating element\n"; + return TCL_ERROR; + } + + if (builder->getDomain()->addElement(theBBarFourNodeQuadUP) == false) { + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + delete theBBarFourNodeQuadUP; + return TCL_ERROR; + } + + return TCL_OK; +} + +int +TclBasicBuilder_addSixNodeTri(ClientData clientData, Tcl_Interp *interp, int argc, + TCL_Char ** const argv) +{ + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + + if (builder->getNDM() != 2 || builder->getNDF() != 2) { + opserr << OpenSees::PromptValueError << "-- model dimensions and/or nodal DOF not compatible " + "with quad element\n"; + return TCL_ERROR; + } + + // check the number of arguments is correct + int argStart = 2; + + if ((argc - argStart) < 10) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: element SixNodeTri eleTag? iNode? jNode? kNode? lNode? " + "nNode? mNode? pNode? qNode? thk? type? matTag? \n"; + return TCL_ERROR; + } + + int SixNodeTriId; + std::array nodes; + int matID; + double thickness = 1.0; + double p = 0.0; // uniform normal traction (pressure) + double rho = 0.0; // mass density + double b1 = 0.0; + double b2 = 0.0; + + if (Tcl_GetInt(interp, argv[argStart], &SixNodeTriId) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid SixNodeTri eleTag" << "\n"; + return TCL_ERROR; + } + + // Nodes + for (int i=0; i<6; i++) + if (Tcl_GetInt(interp, argv[1 + argStart + i], &nodes[i]) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid node\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[7 + argStart], &thickness) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid thickness\n"; + opserr << "SixNodeTri element: " << SixNodeTriId << "\n"; + return TCL_ERROR; + } + + TCL_Char *type = argv[8 + argStart]; + + if (Tcl_GetInt(interp, argv[9 + argStart], &matID) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid matID\n"; + return TCL_ERROR; + } + + if ((argc - argStart) > 13) { + if (Tcl_GetDouble(interp, argv[10 + argStart], &p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid pressure\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[11 + argStart], &rho) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b1\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[12 + argStart], &b1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b1\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[13 + argStart], &b2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid b2\n"; + return TCL_ERROR; + } + } + + NDMaterial *theMaterial = builder->getTypedObject(matID); + if (theMaterial == nullptr) + return TCL_ERROR; + + + // now create the SixNodeTri and add it to the Domain + SixNodeTri *theSixNodeTri = + new SixNodeTri(SixNodeTriId, nodes, + *theMaterial, type, thickness, p, rho, b1, b2); + + + if (builder->getDomain()->addElement(theSixNodeTri) == false) { + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + delete theSixNodeTri; + return TCL_ERROR; + } + + return TCL_OK; +} diff --git a/SRC/runtime/commands/modeling/element/shells.cpp b/SRC/runtime/commands/modeling/element/shells.cpp new file mode 100644 index 0000000000..e6d1da5509 --- /dev/null +++ b/SRC/runtime/commands/modeling/element/shells.cpp @@ -0,0 +1,421 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace OpenSees; + +#include +#include + #ifdef _MSC_VER + # include + # define strcasecmp _stricmp + #else + # include + #endif + +static +std::string +toLower( const std::string & s ) +{ + std::string copy = s; + transform( copy.begin( ), copy.end( ), copy.begin( ), + [](unsigned char c) { return std::tolower(c); }); + return copy; +} + +static bool +equalsIgnoreCase( const std::string & lhs, const std::string & rhs ) +{ + return toLower( lhs ) == toLower( rhs ); +} + +class CaseInsensitive +{ + public: + size_t operator( ) ( const std::string & s ) const + { + static std::hash hf; + return hf( toLower( s ) ); + } + + bool operator( ) ( const std::string & lhs, const std::string & rhs ) const + { + return equalsIgnoreCase( lhs, rhs ); + } +}; + +using namespace OpenSees; + +static std::unordered_map +NodeCounts = { + {"ASDShellQ4", 4}, + {"ShellMITC4", 4}, + {"ShellMITC9", 9}, + {"ShellDKGQ", 4}, + {"ShellNLDKGQ", 4}, + {"ShellDKGT", 3}, + // {"ASDShellT3", 3}, // TODO + {"ShellNLDKGT", 3}, + {"ShellANDeS", 4}, + {"ShellMITC4Thermal", 4}, + {"ShellNLDKGQThermal", 4}, +}; + +int +TclBasicBuilder_addShell(ClientData clientData, Tcl_Interp *interp, int argc, + TCL_Char ** const argv) +{ + assert(clientData != nullptr); + BasicModelBuilder *builder = (BasicModelBuilder*)clientData; + int tag; + if (argc < 4) { + opserr << OpenSees::PromptValueError + << "insufficient arguments for element " << argv[1] + << "\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid element tag " << argv[2] + << "\n"; + return TCL_ERROR; + } + + // Determine the number of nodes + int nen = -1; + auto it = NodeCounts.find(argv[1]); + if (it != NodeCounts.end()) + nen = it->second; + + int argi = 3; + // Parse node tags + std::vector multi_nodes; + { + int list_argc; + TCL_Char **list_argv; + if (Tcl_SplitList(interp, argv[argi], &list_argc, &list_argv) == TCL_OK && list_argc >= 2) { + for (int i = 0; i < list_argc; ++i) { + int node; + if (Tcl_GetInt(interp, list_argv[i], &node) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid node " << list_argv[i] + << "\n"; + return TCL_ERROR; + } + multi_nodes.push_back(node); + } + nen = multi_nodes.size(); + Tcl_Free((char *)list_argv); + argi += 1; + + } else { + if (nen == -1) { + opserr << OpenSees::PromptValueError + << "Nodes must be supplied in a list for element type " << argv[1] + << "\n"; + return TCL_ERROR; + } + if (argi + nen > argc) { + opserr << OpenSees::PromptValueError + << "expected " << nen << " nodes for element type " << argv[1] + << "\n"; + return TCL_ERROR; + } + for (int i=0; i tracker; + std::set positional; + + // + // Keywords + // + for (int i=argi; igetTypedObject(stag); + if (section == nullptr) + return TCL_ERROR; + + tracker.consume(Position::Section); + } + else if (strcmp(argv[i], "-updateBasis") == 0) { + updateBasis = true; + } + + else if ((strcasecmp(argv[i], "-corotational") == 0)) + corotational = true; + + else if (strcmp(argv[i], "-noeas") == 0) { + use_eas = false; + } + + else if (strcmp(argv[i], "-drillingStab") == 0) { + if (drill_mode != ASDShellQ4::DrillingDOF_Elastic) { + opserr << "Error: element ASDShellQ4: -drillingStab and -drillingNL options are mutually exclusive\n"; + return 0; + } + if (argc < i + 2) { + opserr << "Error: drilling stabilization parameter not provided with -drillingStab option\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i+1], &drilling_stab) != TCL_OK) { + opserr << "Error: cannot get drilling stabilization parameter with -drillingStab option\n"; + return TCL_ERROR; + } + drilling_stab = std::max(0.0, std::min(1.0, drilling_stab)); + drill_mode = ASDShellQ4::DrillingDOF_Elastic; + use_drill_stab = true; + i++; + } + else if (strcmp(argv[i], "-drillingNL") == 0) { + if (use_drill_stab) { + opserr << "Error: -drillingStab and -drillingNL options are mutually exclusive\n"; + return 0; + } + drill_mode = ASDShellQ4::DrillingDOF_NonLinear; + drilling_stab = 1.0; + } + // else if (strcmp(argv[i], "-local") == 0) { + // if (OPS_GetNumRemainingInputArgs() < 3) { + // opserr << "Error: element ASDShellQ4: not enough arguments for -local options (3 components are required)\n"; + // return 0; + // } + // for (int i = 0; i < 3; ++i) { + // double local_x_com; + // if (OPS_GetDoubleInput(&numData, &local_x_com) == 0) { + // local_x(i) = local_x_com; + // } + // else { + // opserr << "Error: element ASDShellQ4: cannot get the component " << i + 1 << " for the local X axis\n"; + // return 0; + // } + // } + // } + + else + positional.insert(i); + } + + // + // Positional arguments + // + for (int i : positional) { + switch (tracker.current()) { + case Position::Section: + if (Tcl_GetInt(interp, argv[i], &mat_tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid material tag " << argv[i] << "\n"; + return TCL_ERROR; + } else { + section = builder->getTypedObject(mat_tag); + if (section == nullptr) + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::End: + default: + opserr << OpenSees::PromptParseError << "unexpected argument " << argv[i] << "\n"; + return TCL_ERROR; + } + // + // Check required positional arguments + // + while (tracker.current() != Position::End) { + switch (tracker.current()) { + case Position::Section: + opserr << OpenSees::PromptValueError + << "missing required positional argument section\n"; + return TCL_ERROR; + default: + break; + } + tracker.increment(); + } + } + + // + // Create the element + // + Element* theElement = nullptr; + if (nen == 3) { + + std::array nodes; + for (int i=0; i<3; i++) + nodes[i] = multi_nodes[i]; + + if (strcasecmp(argv[1], "ShellDKGT") == 0) { + theElement = new ShellDKGT(tag, nodes[0], nodes[1], nodes[2], *section, b[0], b[1], b[2]); + + } else if (strcasecmp(argv[1], "ShellNLDKGT") == 0) { + theElement = new ShellNLDKGT(tag, nodes[0], nodes[1], nodes[2], *section); + + } + } + else if (nen == 4) { + std::array nodes; + for (int i=0; i<4; i++) + nodes[i] = multi_nodes[i]; + + if ((strcasecmp(argv[1], "ShellMITC4") == 0) || + (strcasecmp(argv[1], "Shell") == 0)) { + theElement = new ShellMITC4(tag, nodes[0], nodes[1], nodes[2], nodes[3], *section, updateBasis); + + } else if (strcasecmp(argv[1], "ShellDKGQ") == 0) { + theElement = new ShellDKGQ(tag, nodes[0], nodes[1], nodes[2], nodes[3], *section); + + } else if (strcasecmp(argv[1], "ShellNLDKGQ") == 0) { + theElement = new ShellNLDKGQ(tag, nodes[0], nodes[1], nodes[2], nodes[3], *section); + + } else if (strcasecmp(argv[1], "ASDShellQ4") == 0) { + + theElement = new ASDShellQ4(tag, + nodes[0], nodes[1], nodes[2], nodes[3], + section, local_x, corotational, use_eas, drill_mode, drilling_stab); + + } else if (strcasecmp(argv[1], "ShellNLDKGQThermal") == 0) { + theElement = new ShellNLDKGQThermal(tag, nodes[0], nodes[1], nodes[2], nodes[3], *section); + + } else if (strcasecmp(argv[1], "ShellMITC4Thermal") == 0) { + theElement = new ShellMITC4Thermal(tag, nodes[0], nodes[1], nodes[2], nodes[3], *section); + } + } + else if (nen == 9) { + std::array nodes; + for (int i=0; i<9; i++) + nodes[i] = multi_nodes[i]; + + if (strcasecmp(argv[1], "ShellMITC9") == 0) { + theElement = new ShellMITC9(tag, nodes[0], nodes[1], nodes[2], nodes[3], + nodes[4], nodes[5], nodes[6], nodes[7], nodes[8], *section); + } + } + + if (theElement == nullptr) { + opserr << OpenSees::PromptValueError << "failed to create element\n"; + return TCL_ERROR; + } + + // + // + // + if (builder->getDomain()->addElement(theElement) == false) { + opserr << OpenSees::PromptValueError << "could not add element to the domain\n"; + delete theElement; + return TCL_ERROR; + } + + return TCL_OK; +} + + +#include +Element* +TclDispatch_newShellANDeS(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char** const argv) +{ + + if (argc < 6) { + opserr << "Want: element ShellANDeS $tag $iNode $jNode $kNode $thick $E $nu $rho"; + return nullptr; + } + + int numArgs = OPS_GetNumRemainingInputArgs(); + + int iData[4]; + int numData = 4; + if (OPS_GetIntInput(&numData, iData) != 0) { + opserr << "WARNING invalid integer tag\n"; + return nullptr; + } + + double dData[11]; + numArgs = OPS_GetNumRemainingInputArgs(); + if (OPS_GetDoubleInput(&numArgs, dData) != 0) { + opserr << "WARNING invalid double thickness: element ShellANDeS \n"; + return nullptr; + } + + Element *theElement = nullptr; + + if (numArgs == 4) { + theElement = new ShellANDeS(iData[0], iData[1], iData[2], iData[3], + dData[0], dData[1], dData[2], dData[3]); + } else if (numArgs == 11) { + theElement = + new ShellANDeS(iData[0], iData[1], iData[2], iData[3], dData[0], + dData[1], dData[2], dData[3], dData[4], dData[5], + dData[6], dData[7], dData[8], dData[9], dData[10]); + } + + return theElement; +} diff --git a/SRC/runtime/commands/modeling/element/truss.cpp b/SRC/runtime/commands/modeling/element/truss.cpp new file mode 100644 index 0000000000..9cb40de445 --- /dev/null +++ b/SRC/runtime/commands/modeling/element/truss.cpp @@ -0,0 +1,407 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Written: cmp +// April 2025 +// +#include +#include +#include +// OpenSees +#include +#include +#include +#include +#include +#include +#include +#include +// Elements +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +# include +# define strcasecmp _stricmp +#else +# include +#endif +#define strcmp strcasecmp + +// +// element Truss $tag $iNode $jNode $A $matTag <-rho $rho> <-cMass $flag> <-doRayleigh $flag> <-useInitialDisp $flag> +// element Truss $tag $iNode $jNode $sectTag <-rho $rho> <-cMass $flag> <-doRayleigh $flag> +// element TrussSection $tag $iNode $jNode $sectTag <-rho $rho> <-cMass $flag> <-doRayleigh $flag> +// + + +template +static int +CreateTruss(ClientData clientData, Tcl_Interp *interp, int argc, + TCL_Char **argv) +{ + assert(clientData != nullptr); + + // Parsing is performed in three steps: + // 1. Collect nodes + // 2. Parse out keywords + // 3. Parse remaining positional arguments. + + ArgumentTracker tracker; + std::set positional; + + + BasicModelBuilder* builder = static_cast(clientData); + + int tag; + if (argc < 3 || (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK)) { + opserr << OpenSees::PromptValueError + << "failed to read integer tag\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Tag); + + double rho = 0.0; + int doRayleigh = 0; // by default rayleigh not done + int cMass = 0; // by default use lumped mass matrix + int ndm = builder->getNDM(); + double area = 0; + UniaxialMaterial *material = nullptr; + FrameSection *section = nullptr; + + // + // 1. Parse nodes + // + int nodes[2] = {0, 0}; + int node_end = 5; + if (argc < 4 || (Tcl_GetInt(interp, argv[3], &nodes[0]) != TCL_OK)) { + opserr << OpenSees::PromptValueError + << "failed to read integer node tag\n"; + return TCL_ERROR; + } + tracker.consume(Positions::iNode); + if (argc < 5 || (Tcl_GetInt(interp, argv[4], &nodes[1]) != TCL_OK)) { + opserr << OpenSees::PromptValueError + << "failed to read integer node tag\n"; + return TCL_ERROR; + } + tracker.consume(Positions::jNode); + + // + // 2. Keywords + // + for (int i=node_end; igetTypedObject(sec); + if (section == nullptr) + return TCL_ERROR; + + tracker.consume(Positions::Section); + tracker.consume(Positions::Area); + tracker.consume(Positions::Material); + } + + else if (strcmp(argv[i], "-material") == 0) { + int mat; + if (argc == ++i || Tcl_GetInt(interp, argv[i], &mat) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read material tag\n"; + return TCL_ERROR; + } + + material = builder->getTypedObject(mat); + if (material == nullptr) + return TCL_ERROR; + tracker.consume(Positions::Material); + } + else if ((strcmp(argv[i], "-A") == 0) || + (strcmp(argv[i], "-area") == 0)) { + if (argc == ++i || Tcl_GetDouble(interp, argv[i], &area) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read area\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Area); + } + else if (strcmp(argv[i], "-cMass") == 0) { + if (argc == ++i || Tcl_GetInt(interp, argv[i], &cMass) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read mass flag\n"; + return TCL_ERROR; + } + tracker.consume(Positions::MassFlag); + } + else if (strcmp(argv[i], "-doRayleigh") == 0) { + if (argc == ++i || Tcl_GetInt(interp, argv[i], &doRayleigh) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read rayleigh flag\n"; + return TCL_ERROR; + } + tracker.consume(Positions::RayleighFlag); + } + else if (strcmp(argv[i], "-useInitialDisp") == 0) { + if (argc == ++i || Tcl_GetInt(interp, argv[i], &doRayleigh) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read initial disp flag\n"; + return TCL_ERROR; + } + tracker.consume(Positions::UseInitialDisp); + } + else { + positional.insert(i); + } + } + + // + // 3. Positional arguments + // + for (int i : positional) { + + if (tracker.current() == Positions::EndRequired) + tracker.increment(); + + switch (tracker.current()) { + case Positions::Tag: + if (Tcl_GetInt(interp, argv[i], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read integer tag\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Positions::iNode: + if (Tcl_GetInt(interp, argv[i], &nodes[0]) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read integer node tag\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + case Positions::jNode: + if (Tcl_GetInt(interp, argv[i], &nodes[1]) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read integer node tag\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Positions::Material: { + int mat; + if (Tcl_GetInt(interp, argv[i], &mat) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read integer material tag\n"; + return TCL_ERROR; + } + material = builder->getTypedObject(mat); + if (material == nullptr) { + return TCL_ERROR; + } + tracker.increment(); + break; + } + + case Positions::Density: + if (Tcl_GetDouble(interp, argv[i], &rho) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read density\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Positions::MassFlag: + if (Tcl_GetInt(interp, argv[i], &cMass) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read mass flag\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + case Positions::RayleighFlag: + if (Tcl_GetInt(interp, argv[i], &doRayleigh) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read rayleigh flag\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + case Positions::UseInitialDisp: + if (Tcl_GetInt(interp, argv[i], &doRayleigh) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read initial disp flag\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Positions::Area: + if (Tcl_GetDouble(interp, argv[i], &area) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read area\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Positions::Section: + int sec; + if (Tcl_GetInt(interp, argv[i], &sec) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read section tag\n"; + return TCL_ERROR; + } + section = builder->getTypedObject(sec); + if (section == nullptr) + return TCL_ERROR; + tracker.increment(); + break; + + case Positions::EndRequired: + // This will not be reached + break; + + case Positions::End: + opserr << OpenSees::PromptValueError + << "unexpected argument " << argv[i] << "\n"; + return TCL_ERROR; + } + } + + // + // 4. Check required positional arguments + // + if (tracker.current() < Positions::EndRequired) { + opserr << OpenSees::PromptValueError + << "missing required arguments: "; + while (tracker.current() != Positions::EndRequired) { + switch (tracker.current()) { + case Positions::Tag: + opserr << "tag "; + break; + case Positions::Material: + opserr << "material "; + break; + default: + break; + } + tracker.increment(); + } + return TCL_ERROR; + } + + // + // + // + if (section == nullptr) { + if (tracker.contains(Positions::Area)) { + opserr << OpenSees::PromptValueError + << "missing required argument area\n"; + return TCL_ERROR; + } + if (material == nullptr) { + opserr << OpenSees::PromptValueError + << "missing required argument material\n"; + return TCL_ERROR; + } + + auto fiber_section = new FrameFiberSection3d(0, 1, nullptr, true, 0.0, 0); + fiber_section->addFiber(*material, area, 0, 0); + section = fiber_section; + } + + // + // + // + if (strstr(argv[1], "Corot") != nullptr && strstr(argv[1], "2") == nullptr) { + if (ndm != 3) { + opserr << OpenSees::PromptValueError + << "CorotTruss only valid in 3D\n"; + return TCL_ERROR; + } + + builder->getDomain()->addElement(new CorotTrussSection(tag, ndm, nodes[0], nodes[1], *section, rho, cMass, doRayleigh)); + } + + else if (strstr(argv[1], "Corot") == nullptr && strstr(argv[1], "2") == nullptr) { + builder->getDomain()->addElement(new TrussSection(tag, ndm, nodes[0], nodes[1], *section, rho, cMass, doRayleigh)); + } + return TCL_OK; +} + + +int +TclCommand_addTruss(ClientData clientData, + Tcl_Interp *interp, + Tcl_Size argc, + TCL_Char ** const argv) +{ + + if (strstr(argv[1], "ection") != nullptr || + ((strcasecmp(argv[1], "Truss") == 0) && (argc == 6))) { + enum class Arguments : int { + Tag, + iNode, + jNode, + Section, + EndRequired, + End, + Density, + MassFlag, + RayleighFlag, + UseInitialDisp, + Area, + Material, + }; + return CreateTruss(clientData, interp, argc, argv); + } + else { + enum class Arguments : int { + Tag, + iNode, + jNode, + Area, + Material, + EndRequired, + End, + Density, + MassFlag, + RayleighFlag, + UseInitialDisp, + Section, + }; + return CreateTruss(clientData, interp, argc, argv); + } + +} \ No newline at end of file diff --git a/SRC/runtime/commands/modeling/geomTransf.cpp b/SRC/runtime/commands/modeling/geomTransf.cpp index f0656db02f..3b88444885 100644 --- a/SRC/runtime/commands/modeling/geomTransf.cpp +++ b/SRC/runtime/commands/modeling/geomTransf.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -9,10 +18,11 @@ // cmp // #include +#include #include #include +#include #include -#include #include #include @@ -20,54 +30,325 @@ #include #include #include -//#include #include #include -#include -#include -#include -// -// Create a coordinate transformation -// -int -TclCommand_addGeomTransf(ClientData clientData, Tcl_Interp *interp, int argc, - const char ** const argv) +#include +#include + +using namespace OpenSees; +int +TclCommand_addTransformBuilder(ClientData clientData, Tcl_Interp *interp, int argc, + const char ** const argv) { assert(clientData != nullptr); BasicModelBuilder *builder = static_cast(clientData); // Make sure there is a minimum number of arguments - if (argc < 2) { - opserr << G3_ERROR_PROMPT << "insufficient number of geomTransf arguments\n"; - opserr << " Expected: geomTransf type? tag? \n"; + if (argc < 3) { + opserr << OpenSees::PromptValueError << "insufficient number of arguments\n"; return TCL_ERROR; } int ndm = builder->getNDM(); - int ndf = builder->getNDF(); // number of degrees of freedom per node + + if (ndm != 2 && ndm != 3) + return TCL_ERROR; - // create 2d coordinate transformation - if ((ndm == 2 && ndf == 3) || (ndm == 2 && ndf == 4)) { + int tag; + const char *name = argv[1]; + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid tag\n"; + return TCL_ERROR; + } - int crdTransfTag; - Vector jntOffsetI(2), - jntOffsetJ(2); + FrameTransformBuilder& transform = *new FrameTransformBuilder(ndm, tag, name); + + // Parse orientation vector + int argi = 3; + bool parsed_xz = (ndm == 2); + int argxz = 0; + while (argi != argc) { + if (strcmp(argv[argi], "-jntOffset") == 0) { + argi++; + transform.offsets[1].zero(); + for (int i = 0; i < ndm; ++i) { + if (argi == argc || + Tcl_GetDouble(interp, argv[argi++], &transform.offsets[1][i]) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid offset at end I\n"; + return TCL_ERROR; + } + } + + transform.offsets[2].zero(); + for (int i = 0; i < ndm; ++i) { + if (argi == argc || + Tcl_GetDouble(interp, argv[argi++], &transform.offsets[2][i]) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid offset at end J\n"; + return TCL_ERROR; + } + } + } + + else if (strcmp(argv[argi], "-orient") == 0) { + // -orient {x y z} + argi++; + if (parsed_xz) { + opserr << OpenSees::PromptValueError + << "orientation already provided\n"; + return TCL_ERROR; + } + + if (argi == argc) { + opserr << OpenSees::PromptValueError + << "missing orientation vector\n"; + return TCL_ERROR; + } + + const char ** xzarg; + int xznum; + Tcl_SplitList(interp, argv[argi], &xznum, &xzarg); + if (xznum != 3) { + Tcl_Free((char *)xzarg); + opserr << OpenSees::PromptValueError + << "invalid orientation vector\n"; + return TCL_ERROR; + } + for (int i=0; i<3; ++i) + if (Tcl_GetDouble(interp, xzarg[i], &transform.vz[i]) != TCL_OK) { + opserr << OpenSees::PromptValueError << "failed to parse vecxz\n"; + return TCL_ERROR; + } + + Tcl_Free((char *)xzarg); + argi++; + parsed_xz = true; + } + + else if (strcmp(argv[argi], "-pull") == 0) { + // -pull iter|incr|init|default + argi++; + if (argi == argc) { + opserr << OpenSees::PromptValueError + << "missing pull type\n"; + return TCL_ERROR; + } + + if (strcmp(argv[argi], "iter") == 0) { + transform.offset_flags |= LogIter; + } else if (strcmp(argv[argi], "incr") == 0) { + transform.offset_flags |= LogIncr; + } else if (strcmp(argv[argi], "init") == 0) { + transform.offset_flags |= LogInit; + } else if (strcmp(argv[argi], "default") == 0) { + transform.offset_flags |= LogDefault; + } else { + opserr << OpenSees::PromptValueError + << "invalid pull type\n"; + return TCL_ERROR; + } + } + + else if (strcmp(argv[argi], "-offset-local") == 0) { + transform.offset_flags |= OffsetLocal; + argi++; + } + else if (strcmp(argv[argi], "-offset-length") == 0) { + transform.offset_flags |= OffsetNormalized; + argi++; + } + + else if (strcmp(argv[argi], "-offset") == 0) { + // -offset {1 {x y z}; 2 {x y z}} + argi++; + if (argi == argc) { + opserr << OpenSees::PromptValueError << "missing offset block.\n"; + return TCL_ERROR; + } + constexpr static const char * const offset_nodes[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9"}; + constexpr static int MAX_OFFSETS = sizeof(offset_nodes)/sizeof(offset_nodes[0]); + auto TclCommand_addOffset = [](ClientData cd, Tcl_Interp* interp, int oargc, const char** const oargv) ->int { + + FrameTransformBuilder* transform = static_cast(cd); + assert(transform != nullptr); + if (oargc < 2) { + opserr << OpenSees::PromptValueError + << "insufficient number of offset arguments\n"; + return TCL_ERROR; + } + int offset_tag; + if (Tcl_GetInt(interp, oargv[0], &offset_tag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid offset tag\n"; + return TCL_ERROR; + } + if (offset_tag < 1 || offset_tag > MAX_OFFSETS) { + opserr << OpenSees::PromptValueError + << "invalid offset tag\n"; + return TCL_ERROR; + } + if (oargc < 2) { + opserr << OpenSees::PromptValueError + << "missing offset vector\n"; + return TCL_ERROR; + } + + const char ** xzarg; + int xznum; + if (oargc == 2) + Tcl_SplitList(interp, oargv[1], &xznum, &xzarg); + else { + xznum = oargc - 1; + xzarg = oargv + 1; + } + + for (int i=0; ioffsets[offset_tag][i]) != TCL_OK) { + if (oargc == 2) + Tcl_Free((char *)xzarg); + opserr << OpenSees::PromptValueError + << "failed to parse offset vector\n"; + return TCL_ERROR; + } + if (oargc == 2) + Tcl_Free((char *)xzarg); + return TCL_OK; + }; + + for (int i=0; i\n"; + if (Tcl_Eval(interp, argv[argi]) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to parse offset block\n"; + return TCL_ERROR; + } else { + for (int i=0; i= argc) { + opserr << OpenSees::PromptValueError << "missing orientation vector\n"; return TCL_ERROR; } + const char ** xzarg; + int xznum; + Tcl_SplitList(interp, argv[argxz], &xznum, &xzarg); + if (xznum == 3) { + for (int i=0; i<3; ++i) + if (Tcl_GetDouble(interp, xzarg[i], &transform.vz[i]) != TCL_OK) { + Tcl_Free((char *)xzarg); + opserr << OpenSees::PromptValueError + << "Failed to parse vectxz\n"; + return TCL_ERROR; + } + argi++; + parsed_xz = true; + } + Tcl_Free((char *)xzarg); + } - int argi = 2; - if (Tcl_GetInt(interp, argv[argi++], &crdTransfTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid tag\n" - " Expected: geomTransf type? tag? <-jntOffset dXi? dYi? dXj? dYj?>\n"; + if (!parsed_xz) { + if (argxz+3 > argc) { + opserr << OpenSees::PromptValueError + << "missing orientation vector\n"; + return TCL_ERROR; + } + for (int i=0; i<3; i++) + if (Tcl_GetDouble(interp, argv[argxz++], &transform.vz[i]) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid vecxz component\n"; + return TCL_ERROR; + } + } + + transform.vz /= transform.vz.norm(); + + if (builder->addTaggedObject(transform) != TCL_OK) + return TCL_ERROR; + + return TCL_OK; +} + + +int +TclCommand_addGeomTransf(ClientData clientData, Tcl_Interp *interp, int argc, + const char ** const argv) + +{ + if (TclCommand_addTransformBuilder(clientData, interp, argc, argv) != TCL_OK) + return TCL_ERROR; + + if (strcmp(argv[0], "transform") == 0) + return TCL_OK; + + + assert(clientData != nullptr); + BasicModelBuilder *builder = static_cast(clientData); + + + // Make sure there is a minimum number of arguments + if (argc < 3) { + opserr << OpenSees::PromptValueError + << "insufficient number of arguments\n"; + return TCL_ERROR; + } + + int tag; + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid tag" + << "\n"; + return TCL_ERROR; + } + + int ndm = builder->getNDM(); + int ndf = builder->getNDF(); + + if (ndm == 3 && !getenv("CRD")) { + auto tb = builder->getTypedObject(tag); + if (tb == nullptr) { + opserr << OpenSees::PromptValueError + << "transformation not found with tag " << tag + << "\n"; + return TCL_ERROR; + } + CrdTransf* t = new BasicFrameTransf3d(tb->template create<2,6>()); + if (t == nullptr) { + opserr << OpenSees::PromptValueError + << "failed to create transformation with tag " << tag + << "\n"; return TCL_ERROR; } + return builder->addTaggedObject(*t); + } + + // + // 2D Case + // + if ((ndm == 2 && ndf == 3) || (ndm == 2 && ndf == 4)) { + Vector jntOffsetI(2), + jntOffsetJ(2); + + int argi = 3; // Additional options at end of command @@ -77,8 +358,9 @@ TclCommand_addGeomTransf(ClientData clientData, Tcl_Interp *interp, int argc, for (int i = 0; i < 2; ++i) { if (argi == argc || Tcl_GetDouble(interp, argv[argi++], &jntOffsetI(i)) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid jntOffset value\n" - " Expected: geomTransf type? tag? <-jntOffset dXi? dYi? dXj? dYj?>\n"; + opserr << OpenSees::PromptValueError + << "invalid jntOffset value" + << "\n"; return TCL_ERROR; } } @@ -86,75 +368,74 @@ TclCommand_addGeomTransf(ClientData clientData, Tcl_Interp *interp, int argc, for (int i = 0; i < 2; ++i) { if (argi == argc || Tcl_GetDouble(interp, argv[argi++], &jntOffsetJ(i)) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid jntOffset value\n" - " Expected: geomTransf type? tag? <-jntOffset dXi? dYi? dXj? dYj?>\n"; + opserr << OpenSees::PromptValueError + << "invalid jntOffset value" + << "\n"; return TCL_ERROR; } } } else { - opserr << G3_ERROR_PROMPT << "bad command\n Expected: geomTransf type? tag? " - "<-jntOffset dXi? dYi? dXj? dYj?>\n"; - opserr << "invalid: " << argv[argi] << "\n"; + opserr << OpenSees::PromptValueError + << "unexpected argument " << argv[argi] + << "\n"; return TCL_ERROR; } } + // // construct the transformation + // - FrameTransform2d *crdTransf2d = nullptr; + CrdTransf *crdTransf2d = nullptr; if (strcmp(argv[1], "Linear") == 0) -// if (getenv("CRD")) { -// crdTransf2d = new LinearCrdTransf2d02(crdTransfTag, jntOffsetI, jntOffsetJ); -// } else - crdTransf2d = new LinearCrdTransf2d(crdTransfTag, jntOffsetI, jntOffsetJ); + crdTransf2d = new LinearCrdTransf2d(tag, jntOffsetI, jntOffsetJ); else if (strcmp(argv[1], "LinearInt") == 0) crdTransf2d = - new LinearCrdTransf2dInt(crdTransfTag, jntOffsetI, jntOffsetJ); + new LinearCrdTransf2dInt(tag, jntOffsetI, jntOffsetJ); else if (strcmp(argv[1], "PDelta") == 0 || strcmp(argv[1], "LinearWithPDelta") == 0) - crdTransf2d = new PDeltaCrdTransf2d(crdTransfTag, jntOffsetI, jntOffsetJ); + crdTransf2d = new PDeltaCrdTransf2d(tag, jntOffsetI, jntOffsetJ); - else if (strcmp(argv[1], "Corotational") == 0 && ndf == 3) - crdTransf2d = new CorotCrdTransf2d(crdTransfTag, jntOffsetI, jntOffsetJ); + else if ((strcmp(argv[1], "Corotational") == 0 || strcmp(argv[1], "Corotational02") == 0) && ndf == 3) + crdTransf2d = new CorotCrdTransf2d(tag, jntOffsetI, jntOffsetJ); - else if (strcmp(argv[1], "Corotational") == 0 && ndf == 4) + else if ((strcmp(argv[1], "Corotational") == 0 || strcmp(argv[1], "Corotational02") == 0) && ndf == 4) crdTransf2d = - new CorotCrdTransfWarping2d(crdTransfTag, jntOffsetI, jntOffsetJ); + new CorotCrdTransfWarping2d(tag, jntOffsetI, jntOffsetJ); else { - opserr << G3_ERROR_PROMPT << "invalid Type\n"; - opserr << argv[1] << "\n"; + opserr << OpenSees::PromptValueError + << "invalid Type: " << argv[1] + << "\n"; return TCL_ERROR; } - // add the transformation to the modelBuilder - if (builder->addTaggedObject(*crdTransf2d) != TCL_OK) + // + if (builder->addTaggedObject(*crdTransf2d) != TCL_OK) return TCL_ERROR; + } - } else if (ndm == 3 && ndf == 6) { - int crdTransfTag; - Vector vecxzPlane(3); // vector that defines local xz plane - Vector jntOffsetI(3), jntOffsetJ(3); // joint offsets in global coordinates + else if (ndm == 3 && ndf >= 6) { + // vector that defines local xz plane + Vector vecxzPlane(3); + // joint offsets in global coordinates + Vector jntOffsetI(3), jntOffsetJ(3); if (argc < 6) { - opserr << G3_ERROR_PROMPT - << "insufficient arguments\n" - << " Expected: geomTransf type? tag? " - "vecxzPlaneX? vecxzPlaneY? vecxzPlaneZ? <-jntOffset dXi? dYi? " - "dZi? dXj? dYj? dZj? >\n"; + opserr << OpenSees::PromptValueError + << "insufficient arguments" + << "\n"; return TCL_ERROR; } int argi = 2; - if (Tcl_GetInt(interp, argv[argi++], &crdTransfTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid tag\n Expected: geomTransf type? tag? " - "vecxzPlaneX? vecxzPlaneY? vecxzPlaneZ? <-jntOffset dXi? dYi? " - "dZi? dXj? dYj? dZj? >\n"; + if (Tcl_GetInt(interp, argv[argi++], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid tag\n"; return TCL_ERROR; } @@ -167,7 +448,8 @@ TclCommand_addGeomTransf(ClientData clientData, Tcl_Interp *interp, int argc, if (xznum == 3) { for (int i=0; i<3; ++i) if (Tcl_GetDouble(interp, xzarg[i], &vecxzPlane(i)) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "Failed to parse vectxz\n"; + opserr << OpenSees::PromptValueError + << "Failed to parse vectxz\n"; return TCL_ERROR; } @@ -178,28 +460,27 @@ TclCommand_addGeomTransf(ClientData clientData, Tcl_Interp *interp, int argc, if (!parsed_xz) { if (Tcl_GetDouble(interp, argv[argi++], &vecxzPlane(0)) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid vecxzPlaneX\n Expected: geomTransf type? tag? " - "vecxzPlaneX? vecxzPlaneY? vecxzPlaneZ? <-jntOffset dXi? dYi? " - "dZi? dXj? dYj? dZj? >\n"; + opserr << OpenSees::PromptValueError + << "invalid vecxzPlaneX\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &vecxzPlane(1)) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid vecxzPlaneY\n Expected: geomTransf type? tag? " - "vecxzPlaneX? vecxzPlaneY? vecxzPlaneZ? <-jntOffset dXi? dYi? " - "dZi? dXj? dYj? dZj? >\n"; + opserr << OpenSees::PromptValueError + << "invalid vecxzPlaneY\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &vecxzPlane(2)) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid vecxzPlaneZ\n Expected: geomTransf type? tag? " - "vecxzPlaneX? vecxzPlaneY? vecxzPlaneZ? <-jntOffset dXi? dYi? " - "dZi? dXj? dYj? dZj? >\n"; + opserr << OpenSees::PromptValueError + << "invalid vecxzPlaneZ\n"; return TCL_ERROR; } } - // additional keyword options at end of command + // + // Additional keyword options + // while (argi != argc) { if (strcmp(argv[argi], "-jntOffset") == 0) { @@ -207,9 +488,7 @@ TclCommand_addGeomTransf(ClientData clientData, Tcl_Interp *interp, int argc, for (int i = 0; i < 3; ++i) { if (argi == argc || Tcl_GetDouble(interp, argv[argi++], &jntOffsetI(i)) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid jntOffset value\n Expected: geomTransf " - "type? tag? vecxzPlaneX? vecxzPlaneY? vecxzPlaneZ? " - "<-jntOffset dXi? dYi? dZi? dXj? dYj? dZj? >\n"; + opserr << OpenSees::PromptValueError << "invalid jntOffset\n"; return TCL_ERROR; } } @@ -217,63 +496,53 @@ TclCommand_addGeomTransf(ClientData clientData, Tcl_Interp *interp, int argc, for (int i = 0; i < 3; ++i) { if (argi == argc || Tcl_GetDouble(interp, argv[argi++], &jntOffsetJ(i)) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid jntOffset value\n Expected: geomTransf " - "type? tag? vecxzPlaneX? vecxzPlaneY? vecxzPlaneZ? " - "<-jntOffset dXi? dYi? dZi? dXj? dYj? dZj? >\n"; + opserr << OpenSees::PromptValueError << "invalid jntOffset\n"; return TCL_ERROR; } } } else { - opserr << G3_ERROR_PROMPT << "bad command\n Expected: geomTransf type? tag? " - "vecxzPlaneX? vecxzPlaneY? vecxzPlaneZ? <-jntOffset dXi? " - "dYi? dZi? dXj? dYj? dZj? > \n"; - opserr << " invalid: " << argv[argi] << "\n"; + opserr << OpenSees::PromptValueError << "unexpected argument: " << argv[argi] << "\n"; return TCL_ERROR; } } - // construct the transformation object - FrameTransform3d *crdTransf3d=nullptr; + // + // construct the transformation + // + CrdTransf *crdTransf3d=nullptr; if (strcmp(argv[1], "Linear") == 0) - if (!getenv("CRD")) - crdTransf3d = new LinearFrameTransf3d(crdTransfTag, vecxzPlane, jntOffsetI, jntOffsetJ); - else - crdTransf3d = new LinearCrdTransf3d(crdTransfTag, vecxzPlane, jntOffsetI, jntOffsetJ); + crdTransf3d = new LinearCrdTransf3d(tag, vecxzPlane, jntOffsetI, jntOffsetJ); else if (strcmp(argv[1], "PDelta") == 0 || strcmp(argv[1], "LinearWithPDelta") == 0) - if (!getenv("CRD")) - crdTransf3d = new PDeltaFrameTransf3d(crdTransfTag, vecxzPlane, jntOffsetI, jntOffsetJ); - else - crdTransf3d = new PDeltaCrdTransf3d(crdTransfTag, vecxzPlane, jntOffsetI, jntOffsetJ); + crdTransf3d = new PDeltaCrdTransf3d(tag, vecxzPlane, jntOffsetI, jntOffsetJ); else if (strcmp(argv[1], "Corotational") == 0) - // By default use new faster version - if (!getenv("CRD")) - crdTransf3d = new CorotFrameTransf3d(crdTransfTag, vecxzPlane, jntOffsetI, jntOffsetJ); - else - crdTransf3d = new CorotCrdTransf3d(crdTransfTag, vecxzPlane, jntOffsetI, jntOffsetJ); + crdTransf3d = new CorotCrdTransf3d(tag, vecxzPlane, jntOffsetI, jntOffsetJ); else { - opserr << G3_ERROR_PROMPT << "invalid Type\n"; + opserr << OpenSees::PromptValueError << "invalid Type\n"; return TCL_ERROR; } if (crdTransf3d == nullptr) { - opserr << G3_ERROR_PROMPT << "Failed to create transform\n"; + opserr << OpenSees::PromptValueError << "Failed to create transform\n"; return TCL_ERROR; } // add the transformation to the modelBuilder - if (builder->addTaggedObject(*crdTransf3d) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "could not add " - "geometric transformation to model Builder\n"; + if (builder->addTaggedObject(*crdTransf3d) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "Failed to add transformation to model\n"; return TCL_ERROR; } - } else { - opserr << G3_ERROR_PROMPT << "ndm = " << ndm << " and ndf = " << ndf + } + + else { + opserr << OpenSees::PromptValueError + << "ndm = " << ndm << " and ndf = " << ndf << " is incompatible with available frame elements\n"; return TCL_ERROR; } diff --git a/SRC/runtime/commands/modeling/invoking/invoke.cpp b/SRC/runtime/commands/modeling/invoking/invoke.cpp index 52c4bb1274..0ec4f4289d 100644 --- a/SRC/runtime/commands/modeling/invoking/invoke.cpp +++ b/SRC/runtime/commands/modeling/invoking/invoke.cpp @@ -1,9 +1,10 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// -// +// https://xara.so +//===----------------------------------------------------------------------===// // Written: cmp // Created: Spring 2023 // @@ -11,7 +12,7 @@ #include #include -#include +#include Tcl_CmdProc TclCommand_useUniaxialMaterial; Tcl_CmdProc TclCommand_useCrossSection; @@ -32,7 +33,7 @@ TclCommand_invoke(ClientData clientData, Tcl_Interp* interp, int argc, char cons { // check number of arguments in command line if (argc < 4) { - opserr << G3_ERROR_PROMPT << "bad arguments - want: using {...}"; + opserr << OpenSees::PromptValueError << "bad arguments - want: using {...}"; return TCL_ERROR; } diff --git a/SRC/runtime/commands/modeling/invoking/invoke_material.cpp b/SRC/runtime/commands/modeling/invoking/invoke_material.cpp index 549f76df3d..5c11665daf 100644 --- a/SRC/runtime/commands/modeling/invoking/invoke_material.cpp +++ b/SRC/runtime/commands/modeling/invoking/invoke_material.cpp @@ -1,3 +1,11 @@ +//===----------------------------------------------------------------------===// +// +// xara +// +//===----------------------------------------------------------------------===// +// https://xara.so +//===----------------------------------------------------------------------===// + // ============================================================================ // 2021 By Jose Abell @ Universidad de los Andes, Chile diff --git a/SRC/runtime/commands/modeling/invoking/invoke_section.cpp b/SRC/runtime/commands/modeling/invoking/invoke_section.cpp index 80cbe9f6c2..053d2cc53f 100644 --- a/SRC/runtime/commands/modeling/invoking/invoke_section.cpp +++ b/SRC/runtime/commands/modeling/invoking/invoke_section.cpp @@ -1,9 +1,10 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// -// +// https://xara.so +//===----------------------------------------------------------------------===// // Written: cmp // @@ -13,8 +14,9 @@ #include #include +#include #include -#include +#include #include #include #include @@ -23,10 +25,12 @@ static Tcl_CmdProc SectionTest_setStrainSection; static Tcl_CmdProc SectionTest_getStressSection; static Tcl_CmdProc SectionTest_getTangSection; static Tcl_CmdProc SectionTest_getResponseSection; +static Tcl_CmdProc SectionTest_Commit; -static int count; -static int countsTillCommit; +using namespace OpenSees; +// static int count; +// static int countsTillCommit; // invoke Section $tag $commands int @@ -39,7 +43,7 @@ TclCommand_useCrossSection(ClientData clientData, Tcl_Interp *interp, int argc, ((BasicModelBuilder*)clientData)->getTypedObject(std::atoi(argv[2])); if (theSection == nullptr) { - opserr << G3_ERROR_PROMPT << "no section found with tag '" << argv[2] << "'\n"; + opserr << OpenSees::PromptValueError << "no section found with tag '" << argv[2] << "'\n"; return TCL_ERROR; } else { // theSection = theSection->getCopy(); @@ -53,6 +57,9 @@ TclCommand_useCrossSection(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_CreateCommand(interp, "stress", SectionTest_getStressSection, (ClientData)theSection, NULL); + + Tcl_CreateCommand(interp, "commit", + SectionTest_Commit, (ClientData)theSection, NULL); Tcl_CreateCommand(interp, "tangent", SectionTest_getTangSection, (ClientData)theSection, NULL); @@ -71,6 +78,7 @@ TclCommand_useCrossSection(ClientData clientData, Tcl_Interp *interp, int argc, Tcl_DeleteCommand(interp, "strain"); Tcl_DeleteCommand(interp, "stress"); Tcl_DeleteCommand(interp, "tangent"); + Tcl_DeleteCommand(interp, "commit"); Tcl_DeleteCommand(interp, "responseSectionTest"); return TCL_OK; @@ -85,18 +93,21 @@ SectionTest_setStrainSection(ClientData clientData, Tcl_Interp *interp, // check number of arguments in command line if (argc < 2) { - opserr << G3_ERROR_PROMPT << "bad command - want: strainSectionTest strain?\n"; + opserr << OpenSees::PromptValueError << "bad command - want: strainSectionTest strain?\n"; return TCL_ERROR; } // get the sectionID form command line // Need to set the data based on argc, otherwise it crashes when setting // "data(i-1) = strain" - static Vector data(argc - 1); + // VectorND<12> e{}; + int order = theSection->getOrder(); + Vector data(order); double strain; - for (int i = 1; i < argc; ++i) { + for (int i = 1; i < argc && i < order; ++i) { if (Tcl_GetDouble(interp, argv[i], &strain) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "could not read strain: strainSectionTest strain1? " + opserr << OpenSees::PromptValueError + << "could not read strain: strainSectionTest strain1? " "strain2? ... strainN?\n"; return TCL_ERROR; } @@ -105,12 +116,15 @@ SectionTest_setStrainSection(ClientData clientData, Tcl_Interp *interp, theSection->setTrialSectionDeformation(data); - if (count == countsTillCommit) { - theSection->commitState(); - count = 1; - } else - count++; + return TCL_OK; +} +static int +SectionTest_Commit(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + SectionForceDeformation *theSection = (SectionForceDeformation*)clientData; + const Vector &stress = theSection->commitState(); return TCL_OK; } @@ -154,13 +168,13 @@ SectionTest_getResponseSection(ClientData clientData, Tcl_Interp *interp, theSection->setResponse(argv + 1, argc - 1, dummy); if (theResponse == nullptr) { - opserr << G3_ERROR_PROMPT << "Response returned a null pointer\n"; + opserr << OpenSees::PromptValueError << "Response returned a null pointer\n"; return TCL_ERROR; } if (theResponse->getResponse() < 0) { delete theResponse; - opserr << G3_ERROR_PROMPT << "Failed to get response\n"; + opserr << OpenSees::PromptValueError << "Failed to get response\n"; return TCL_ERROR; } diff --git a/SRC/runtime/commands/modeling/invoking/invoke_stress.cpp b/SRC/runtime/commands/modeling/invoking/invoke_stress.cpp index 51a64910b0..6c5360b37a 100644 --- a/SRC/runtime/commands/modeling/invoking/invoke_stress.cpp +++ b/SRC/runtime/commands/modeling/invoking/invoke_stress.cpp @@ -1,9 +1,10 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// -// +// https://xara.so +//===----------------------------------------------------------------------===// // Written: cmp // #include @@ -13,7 +14,7 @@ #include #include #include -#include +#include typedef const char TCL_Char; @@ -64,10 +65,6 @@ int TclCommand_usePlaneStress(ClientData clientData, Tcl_Interp *interp, int arg - - - - Tcl_DeleteCommand(interp, "setMaterial"); Tcl_DeleteCommand(interp, "setStrain"); Tcl_DeleteCommand(interp, "getStress"); diff --git a/SRC/runtime/commands/modeling/invoking/invoke_uniaxial.cpp b/SRC/runtime/commands/modeling/invoking/invoke_uniaxial.cpp index ba071b3724..937d62c96a 100644 --- a/SRC/runtime/commands/modeling/invoking/invoke_uniaxial.cpp +++ b/SRC/runtime/commands/modeling/invoking/invoke_uniaxial.cpp @@ -1,9 +1,10 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// -// +// https://xara.so +//===----------------------------------------------------------------------===// // // Description: This file contains the implementaion of functions // used to directly invoke methods of a UniaxialMaterial from a @@ -17,7 +18,7 @@ #include #include -#include +#include #include #include @@ -29,7 +30,7 @@ static Tcl_CmdProc TclCommand_getStressUniaxialMaterial; static Tcl_CmdProc TclCommand_getTangUniaxialMaterial; static Tcl_CmdProc TclCommand_integrateUniaxialMaterial; -const struct {const char*name; const Tcl_CmdProc*func;} command_table[] = { +const struct {const char*name; Tcl_CmdProc*func;} command_table[] = { {"strain", TclCommand_setStrainUniaxialMaterial }, {"commit", TclCommand_commitState }, {"stress", TclCommand_getStressUniaxialMaterial }, @@ -41,9 +42,7 @@ const struct {const char*name; const Tcl_CmdProc*func;} command_table[] = { // {"uniaxialTest", TclCommand_setUniaxialMaterial} }; -// -// THE FUNCTIONS INVOKED BY THE INTERPRETER -// + int TclCommand_useUniaxialMaterial(ClientData clientData, Tcl_Interp *interp, int argc, @@ -53,7 +52,7 @@ TclCommand_useUniaxialMaterial(ClientData clientData, // Get the tag of the material to invoke int tag; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "could not read tag"; + opserr << OpenSees::PromptValueError << "could not read tag"; return TCL_ERROR; } @@ -62,15 +61,11 @@ TclCommand_useUniaxialMaterial(ClientData clientData, // is preserved between invocations. UniaxialMaterial *theMaterial = ((BasicModelBuilder*)clientData)->getTypedObject(tag); - // UniaxialMaterial *theMaterial = - // ((BasicModelBuilder*)clientData)->getTypedObject(argv[2]); + if (theMaterial == nullptr) { - opserr << G3_ERROR_PROMPT << "no material found with tag '" << tag << "'\n"; + opserr << OpenSees::PromptValueError << "no material found with tag '" << tag << "'\n"; return TCL_ERROR; - - } else { - // theMaterial = theOrigMaterial->getCopy(); } @@ -113,15 +108,15 @@ TclCommand_setStrainUniaxialMaterial(ClientData clientData, UniaxialMaterial* theMaterial = (UniaxialMaterial*)clientData; if (argc < 2) { - opserr << G3_ERROR_PROMPT - << "bad arguments - want: strainUniaxialTest strain? \n"; + opserr << OpenSees::PromptValueError + << "missing " << 2 - argc << " arguments, want: strain strain? \n"; return TCL_ERROR; } // get the tag from command line double strain; if (Tcl_GetDouble(interp, argv[1], &strain) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "could not read strain: strainUniaxialTest strain? " + opserr << OpenSees::PromptValueError << "could not read strain: strainUniaxialTest strain? " "\n"; return TCL_ERROR; } @@ -133,7 +128,7 @@ TclCommand_setStrainUniaxialMaterial(ClientData clientData, if (strcmp(argv[i], "-commit")==0){ commit = true; } else if (Tcl_GetDouble(interp, argv[2], &temperature) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "could not read strain: strainUniaxialTest strain? " + opserr << OpenSees::PromptValueError << "could not read strain: strain strain? " "\n"; return TCL_ERROR; } @@ -295,12 +290,12 @@ TclCommand_integrateUniaxialMaterial(ClientData clientData, UniaxialMaterial* material = static_cast(clientData); if (Tcl_GetDouble(interp, argv[1], &dt) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem reading time step, got '" << argv[1] << "'\n"; + opserr << OpenSees::PromptValueError << "problem reading time step, got '" << argv[1] << "'\n"; return TCL_ERROR; } if (Tcl_SplitList(interp, argv[2], &n, &str_values) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem splitting path list " << argv[2] << "\n"; + opserr << OpenSees::PromptValueError << "problem splitting path list " << argv[2] << "\n"; return TCL_ERROR; } @@ -308,42 +303,42 @@ TclCommand_integrateUniaxialMaterial(ClientData clientData, while (argi < argc) { if (strcmp(argv[argi], "-alphaf") == 0) { if (Tcl_GetDouble(interp, argv[1+argi], &conf.alpha_f) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; + opserr << OpenSees::PromptValueError << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; return TCL_ERROR; } argi += 2; } else if (strcmp(argv[argi], "-alpham") == 0) { if (Tcl_GetDouble(interp, argv[1+argi], &conf.alpha_m) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; + opserr << OpenSees::PromptValueError << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; return TCL_ERROR; } argi += 2; } else if (strcmp(argv[argi], "-beta") == 0) { if (Tcl_GetDouble(interp, argv[1+argi], &conf.beta) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; + opserr << OpenSees::PromptValueError << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; return TCL_ERROR; } argi += 2; } else if (strcmp(argv[argi], "-gamma") == 0) { if (Tcl_GetDouble(interp, argv[1+argi], &conf.gamma) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; + opserr << OpenSees::PromptValueError << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; return TCL_ERROR; } argi += 2; } else if (strcmp(argv[argi], "-mass") == 0) { if (Tcl_GetDouble(interp, argv[1+argi], &M) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; + opserr << OpenSees::PromptValueError << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; return TCL_ERROR; } argi += 2; } else if (strcmp(argv[argi], "-damp") == 0) { if (Tcl_GetDouble(interp, argv[1+argi], &C) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; + opserr << OpenSees::PromptValueError << "problem reading " << argv[argi] << ", got '" << argv[argi+1] << "'\n"; return TCL_ERROR; } argi += 2; diff --git a/SRC/runtime/commands/modeling/material.hpp b/SRC/runtime/commands/modeling/material.hpp deleted file mode 100644 index e55b72fbe3..0000000000 --- a/SRC/runtime/commands/modeling/material.hpp +++ /dev/null @@ -1,188 +0,0 @@ -#include -#include -#include - -extern OPS_Routine OPS_ASDConcrete3DMaterial; -extern OPS_Routine OPS_ReinforcedConcretePlaneStressMaterial; -extern OPS_Routine OPS_FAReinforcedConcretePlaneStressMaterial; -extern OPS_Routine OPS_FAFourSteelRCPlaneStressMaterial; -extern OPS_Routine OPS_RAFourSteelRCPlaneStressMaterial; -extern OPS_Routine OPS_PrestressedConcretePlaneStressMaterial; -extern OPS_Routine OPS_FAPrestressedConcretePlaneStressMaterial; -extern OPS_Routine OPS_FAFourSteelPCPlaneStressMaterial; -extern OPS_Routine OPS_RAFourSteelPCPlaneStressMaterial; -// extern OPS_Routine OPS_MaterialCMM; -// extern OPS_Routine OPS_NewMaterialCMM; -extern OPS_Routine OPS_NewPlasticDamageConcrete3d; -extern OPS_Routine OPS_NewPlasticDamageConcretePlaneStress; -extern OPS_Routine OPS_ElasticIsotropicMaterial; -extern OPS_Routine OPS_ElasticIsotropic3D; -extern OPS_Routine OPS_IncrementalElasticIsotropicThreeDimensional; -extern OPS_Routine OPS_ElasticOrthotropicMaterial; -extern OPS_Routine OPS_DruckerPragerMaterial; -extern OPS_Routine OPS_BoundingCamClayMaterial; -extern OPS_Routine OPS_ContactMaterial2DMaterial; -extern OPS_Routine OPS_ContactMaterial3DMaterial; -extern OPS_Routine OPS_InitialStateAnalysisWrapperMaterial; -extern OPS_Routine OPS_ManzariDafaliasMaterial; -extern OPS_Routine OPS_ManzariDafaliasMaterialRO; -extern OPS_Routine OPS_PM4SandMaterial; -extern OPS_Routine OPS_PM4SiltMaterial; -extern OPS_Routine OPS_J2CyclicBoundingSurfaceMaterial; -extern OPS_Routine OPS_CycLiqCPMaterial; -extern OPS_Routine OPS_CycLiqCPSPMaterial; -extern OPS_Routine OPS_InitStressNDMaterial; -extern OPS_Routine OPS_InitStrainNDMaterial; -extern OPS_Routine OPS_StressDensityMaterial; -extern OPS_Routine OPS_J2PlateFibreMaterial; -extern OPS_Routine OPS_PlaneStressLayeredMaterial; -extern OPS_Routine OPS_PlaneStressRebarMaterial; -extern OPS_Routine OPS_PlateFiberMaterial; -extern OPS_Routine OPS_BeamFiberMaterial; -extern OPS_Routine OPS_BeamFiberMaterial2d; -extern OPS_Routine OPS_BeamFiberMaterial2dPS; -extern OPS_Routine OPS_LinearCap; -extern OPS_Routine OPS_AcousticMedium; -extern OPS_Routine OPS_UVCmultiaxial; -extern OPS_Routine OPS_UVCplanestress; -extern OPS_Routine OPS_SAniSandMSMaterial; -extern OPS_Routine OPS_OrthotropicRotatingAngleConcreteT2DMaterial01; // M. J. Nunez - UChile -extern OPS_Routine OPS_SmearedSteelDoubleLayerT2DMaterial01; // M. J. Nunez - UChile - -extern OPS_Routine OPS_ElasticIsotropicMaterialThermal; // L.Jiang [SIF] -extern OPS_Routine OPS_DruckerPragerMaterialThermal; // L.Jiang [SIF] -extern OPS_Routine OPS_PlasticDamageConcretePlaneStressThermal; // L.Jiang [SIF] - -extern OPS_Routine OPS_ElasticOrthotropicPlaneStress; -extern OPS_Routine OPS_OrthotropicMaterial; -extern OPS_Routine OPS_Series3DMaterial; -extern OPS_Routine OPS_Parallel3DMaterial; - -extern OPS_Routine OPS_AllASDPlasticMaterials; - -#ifdef _HAVE_Faria1998 -extern OPS_Routine OPS_NewFaria1998Material; -extern OPS_Routine OPS_NewConcreteMaterial; -#endif - -extern OPS_Routine OPS_FSAMMaterial; // K Kolozvari - -#ifdef _HAVE_Damage2p -extern OPS_Routine OPS_Damage2p; -#endif - -static std::unordered_map material_dispatch = { - {"InitStressMaterial", OPS_InitStressNDMaterial}, - {"InitStrainMaterial", OPS_InitStrainNDMaterial}, - {"InitStrain", OPS_InitStrainNDMaterial}, - - {"ReinforcedConcretePlaneStress", OPS_ReinforcedConcretePlaneStressMaterial}, - {"PlaneStressLayeredMaterial", OPS_PlaneStressLayeredMaterial}, - {"PlaneStressRebarMaterial", OPS_PlaneStressRebarMaterial}, - -#ifdef OPS_USE_ASDPlasticMaterials - {"ASDPlasticMaterial", OPS_AllASDPlasticMaterials}, -#endif - - {"ASDConcrete3D", OPS_ASDConcrete3DMaterial}, - - {"PlasticDamageConcrete", OPS_NewPlasticDamageConcrete3d}, - - {"PlasticDamageConcretePlaneStress", OPS_NewPlasticDamageConcretePlaneStress}, - - - {"J2PlateFibre", OPS_J2PlateFibreMaterial}, - {"PlateFiber", OPS_PlateFiberMaterial}, - - // Beam fiber - {"BeamFiber", OPS_BeamFiberMaterial}, - {"BeamFiber2d", OPS_BeamFiberMaterial2d}, - {"BeamFiber2dPS", OPS_BeamFiberMaterial2dPS}, - - - {"DruckerPragerThermal", OPS_DruckerPragerMaterialThermal}, -#if 0 - {"CDPPlaneStressThermal", OPS_PlasticDamageConcretePlaneStressThermal}, -#endif - - -#ifdef _HAVE_Faria1998 - {"Faria1998", OPS_NewFaria1998Material}, - {"Concrete", OPS_NewConcreteMaterial}, -#endif - - {"FAReinforcedConcretePlaneStress", OPS_FAReinforcedConcretePlaneStressMaterial}, - {"RAFourSteelRCPlaneStress", OPS_RAFourSteelRCPlaneStressMaterial}, - {"FAFourSteelRCPlaneStress", OPS_FAFourSteelRCPlaneStressMaterial}, - -#ifdef _HAVE_Damage2p - {"Damage2p", OPS_Damage2p}, -#endif - - {"PrestressedConcretePlaneStress", OPS_PrestressedConcretePlaneStressMaterial}, - {"FAPrestressedConcretePlaneStress", OPS_FAPrestressedConcretePlaneStressMaterial}, - {"RAFourSteetPCPlaneStress", OPS_RAFourSteelPCPlaneStressMaterial}, - - {"FAFourSteelPCPlaneStress", OPS_FAFourSteelPCPlaneStressMaterial}, - - {"DruckerPrager", OPS_DruckerPragerMaterial}, - - {"TruncatedDP", OPS_LinearCap}, - - // K Kolozvari - {"FSAM", OPS_FSAMMaterial}, - - {"AcousticMedium", OPS_AcousticMedium}, - - {"UVCplanestress", OPS_UVCplanestress}, - - {"UVCmultiaxial", OPS_UVCmultiaxial}, - -//{"MaterialCMM", OPS_MaterialCMM}, - - {"CycLiqCP", OPS_CycLiqCPMaterial}, - - {"CycLiqCPSP", OPS_CycLiqCPSPMaterial}, - - {"BoundingCamClay", OPS_BoundingCamClayMaterial}, - - {"ManzariDafalias", OPS_ManzariDafaliasMaterial}, - - {"ManzariDafaliasRO", OPS_ManzariDafaliasMaterialRO}, - - {"PM4Sand", OPS_PM4SandMaterial}, - - {"J2CyclicBoundingSurface", OPS_J2CyclicBoundingSurfaceMaterial}, - - {"PM4Silt", OPS_PM4SiltMaterial}, - - {"ContactMaterial2D", OPS_ContactMaterial2DMaterial}, - - {"ContactMaterial3D", OPS_ContactMaterial3DMaterial}, - - {"InitialStateAnalysisWrapper", OPS_InitialStateAnalysisWrapperMaterial}, - - {"stressDensity", OPS_StressDensityMaterial}, - - {"ElasticIsotropic3D", OPS_ElasticIsotropic3D}, - - {"ElasticIsotropic", OPS_ElasticIsotropicMaterial}, - - {"ElasticOrthotropic", OPS_ElasticOrthotropicMaterial}, - - {"ElasticIsotropic3DThermal", OPS_ElasticIsotropicMaterialThermal}, - - {"IncrementalElasticIsotropic3D", OPS_IncrementalElasticIsotropicThreeDimensional}, - - {"OrthotropicRAConcrete", OPS_OrthotropicRotatingAngleConcreteT2DMaterial01}, - {"SmearedSteelDoubleLayer", OPS_SmearedSteelDoubleLayerT2DMaterial01}, - - {"SAniSandMS", OPS_SAniSandMSMaterial}, - - {"OrthotropicMaterial", OPS_OrthotropicMaterial}, - {"ElasticOrthotropicPlaneStress", OPS_ElasticOrthotropicPlaneStress}, - {"Series3DMaterial", OPS_Series3DMaterial}, - {"Parallel3DMaterial", OPS_Parallel3DMaterial}, - {"Parallel3D", OPS_Parallel3DMaterial}, -}; - diff --git a/SRC/runtime/commands/modeling/material/CMakeLists.txt b/SRC/runtime/commands/modeling/material/CMakeLists.txt new file mode 100644 index 0000000000..c40f25a68e --- /dev/null +++ b/SRC/runtime/commands/modeling/material/CMakeLists.txt @@ -0,0 +1,16 @@ + + +target_sources(OPS_Runtime PRIVATE + material.cpp + nDMaterial.cpp + + shell.cpp + fedeas.cpp + legacy.cpp + wrapper.cpp + plastic.cpp + elastic.cpp + concrete.cpp + isotropy.cpp + boucwen.cpp +) \ No newline at end of file diff --git a/SRC/runtime/commands/modeling/material/boucwen.cpp b/SRC/runtime/commands/modeling/material/boucwen.cpp new file mode 100644 index 0000000000..3a7c87c2f6 --- /dev/null +++ b/SRC/runtime/commands/modeling/material/boucwen.cpp @@ -0,0 +1,640 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Written: cmp +// +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +# define strcasecmp _stricmp +#else +# include +#endif +#define strcmp strcasecmp + +#include +#include +#include +#include + +template +static int +ParseBoucWen(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + + BasicModelBuilder *builder = static_cast(clientData); + + ArgumentTracker tracker; + std::set positional; + + int tag; + double E, Fy, alpha; + double beta = 0.5, gamma=0.5; + double Ao=1, + delta_a = 0, + delta_n = 0, + delta_v = 0; + + double pinch_slope = 0.0; + double pinch_slip = 0.0; + double pinch_start = 0.0; + double pinch_rate = 0.0; + double pinch_size = 0.0; + double pinch_lamda = 0.5; + + int iterations = 25; + double tolerance = 1e-8; + double n = 1.0; + + // BoucWenOriginal-only + double mu = 2.0, alphaNL = 0.0; + + // + // Begin parse + // + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid uniaxialMaterial tag\n"; + return TCL_ERROR; + } + + for (int i=2; i= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Fy) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Fy); + } + else if ((strcasecmp(argv[i], "-E") == 0) || (strcmp(argv[i], "-ko") == 0)) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &E) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::E); + } + else if (strcasecmp(argv[i], "-alpha") == 0 || strcasecmp(argv[i], "-b") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &alpha) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Alpha); + } + else if (strcasecmp(argv[i], "-n") == 0 || strcasecmp(argv[i], "-N") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &n) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::N); + } + + else if (strcmp(argv[i], "-beta") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &beta) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Beta); + } + else if (strcmp(argv[i], "-gamma") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &gamma) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Gamma); + } + // + // Damage + // + else if (strcmp(argv[i], "-Ao") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Ao) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Ao); + } + else if (strcmp(argv[i], "-delta_a") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &delta_a) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::DeltaA); + } + else if (strcmp(argv[i], "-delta_n") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &delta_n) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::DeltaN); + } + else if (strcmp(argv[i], "-delta_v") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &delta_v) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::DeltaV); + } + // + // Pinching + // + else if (strcmp(argv[i], "-pinch_slope") == 0 || strcmp(argv[i], "-p") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &pinch_slope) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::PinchSlope); + } + else if (strcmp(argv[i], "-pinch_start") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &pinch_start) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::PinchStart); + } + else if (strcmp(argv[i], "-pinch_rate") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &pinch_rate) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::PinchRate); + } + else if (strcmp(argv[i], "-pinch_slip") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &pinch_slip) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::PinchSlip); + } + else if (strcmp(argv[i], "-pinch_size") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &pinch_size) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::PinchSize); + } + else if (strcmp(argv[i], "-pinch_lamda") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &pinch_lamda) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::PinchLamda); + } + // + // Numerics + // + else if (strcmp(argv[i], "-tolerance") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &tolerance) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Tolerance); + } + else if (strcmp(argv[i], "-iterations") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[i], &iterations) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Iterations); + } + else + positional.insert(i); + } + + + for (int i: positional) { + if (tracker.current() == Positions::EndRequired) + tracker.increment(); + + switch (tracker.current()) { + case Positions::Tag : + if (Tcl_GetInt(interp, argv[i], &tag) != TCL_OK) { + opserr << "Invalid tag " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Tag); + break; + + case Positions::Fy: + if (Tcl_GetDouble(interp, argv[i], &Fy) != TCL_OK) { + opserr << "Invalid value for Fy " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Fy); + break; + case Positions::E: + if (Tcl_GetDouble(interp, argv[i], &E) != TCL_OK) { + opserr << "Invalid value for E " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::E); + break; + case Positions::Alpha: + if (Tcl_GetDouble(interp, argv[i], &alpha) != TCL_OK) { + opserr << "Invalid value for Alpha " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Alpha); + break; + case Positions::N: + if (Tcl_GetDouble(interp, argv[i], &n) != TCL_OK) { + opserr << "Invalid value for N " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::N); + break; + case Positions::Beta: + if (Tcl_GetDouble(interp, argv[i], &beta) != TCL_OK) { + opserr << "Invalid value for beta " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Beta); + break; + case Positions::Gamma: + if (Tcl_GetDouble(interp, argv[i], &gamma) != TCL_OK) { + opserr << "Invalid value for gamma " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Gamma); + break; + case Positions::Tolerance: + if (Tcl_GetDouble(interp, argv[i], &tolerance) != TCL_OK) { + opserr << "Invalid value for tolerance " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Tolerance); + break; + case Positions::Iterations: + if (Tcl_GetInt(interp, argv[i], &iterations) != TCL_OK) { + opserr << "Invalid value for iterations " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Iterations); + break; + // + // Degradation + // + case Positions::Ao: + if (Tcl_GetDouble(interp, argv[i], &Ao) != TCL_OK) { + opserr << "Invalid value for Ao " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Ao); + break; + case Positions::DeltaA: + if (Tcl_GetDouble(interp, argv[i], &delta_a) != TCL_OK) { + opserr << "Invalid value for delta_a " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::DeltaA); + break; + case Positions::DeltaN: + if (Tcl_GetDouble(interp, argv[i], &delta_n) != TCL_OK) { + opserr << "Invalid value for delta_n " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::DeltaN); + break; + case Positions::DeltaV: + if (Tcl_GetDouble(interp, argv[i], &delta_v) != TCL_OK) { + opserr << "Invalid value for delta_v " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::DeltaV); + break; + // + // Schellenberg extras + // + case Positions::AlphaNL: + if (Tcl_GetDouble(interp, argv[i], &alphaNL) != TCL_OK) { + opserr << "Invalid value for alphaNL " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::AlphaNL); + break; + case Positions::Mu: + if (Tcl_GetDouble(interp, argv[i], &mu) != TCL_OK) { + opserr << "Invalid value for mu " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Mu); + break; + + case Positions::PinchRate: + case Positions::PinchSlip: + case Positions::PinchSize: + case Positions::PinchSlope: + case Positions::PinchStart: + case Positions::PinchLamda: + break; + // + // + case Positions::EndRequired: + // This will not be reached + break; + + case Positions::End: + opserr << "Invalid value for option " << argv[i] << "\n"; + return TCL_ERROR; + } + } + + if (tracker.current() < Positions::EndRequired) { + opserr << "Missing required arguments: "; + while (tracker.current() != Positions::End) { + switch (tracker.current()) { + case Positions::Fy: + opserr << "Fy "; + break; + case Positions::E: + opserr << "E "; + break; + case Positions::Alpha: + opserr << "Alpha "; + break; + case Positions::N: + opserr << "N "; + break; + case Positions::Beta: + opserr << "Beta "; + break; + case Positions::Gamma: + opserr << "Gamma "; + break; + case Positions::Ao: + opserr << "Ao "; + break; + case Positions::DeltaA: + opserr << "delta_a "; + break; + case Positions::DeltaV: + opserr << "delta_v "; + break; + case Positions::DeltaN: + opserr << "delta_n "; + break; + + case Positions::Tolerance: + opserr << "tolerance "; + break; + case Positions::Iterations: + opserr << "iterations "; + break; + + case Positions::PinchSlope: + opserr << "PinchSlope "; + break; + case Positions::PinchStart: + opserr << "PinchStart "; + break; + case Positions::PinchRate: + opserr << "PinchRate "; + break; + case Positions::PinchSize: + opserr << "PinchSize "; + break; + + case Positions::Mu: + case Positions::AlphaNL: + case Positions::EndRequired: + case Positions::End: + default: + break; + } + + if (tracker.current() == Positions::EndRequired) + break; + + tracker.consume(tracker.current()); + } + opserr << "\n"; + return TCL_ERROR; + } + + // + // + // + + // + // + // + UniaxialMaterial *theMaterial = nullptr; + if ((strcmp(argv[1], "BWBF") == 0) || + (strcmp(argv[1], "Bouc") == 0)) { + + theMaterial = + new BWBF(tag, + E, + Fy, + alpha, + n, + beta, + delta_a, delta_v, delta_n, + // + pinch_slope, + pinch_slip, + pinch_start, + pinch_rate, + pinch_size, + pinch_lamda, + // + tolerance, + iterations); + } + else if ((strcmp(argv[1], "BoucWen") == 0)) { + + theMaterial = + new BoucWenMaterial(tag, alpha, E, n, gamma, beta, Ao, + delta_a, delta_v, delta_n, + tolerance, iterations); + } + else if (strcmp(argv[1], "BoucWenOriginal") == 0) { + theMaterial = + new BoucWenOriginal(tag, E, Fy, alpha, alphaNL, mu, + n, beta, gamma, + tolerance, iterations); + } + else if (strcmp(argv[1], "BWBN") == 0) { + theMaterial = + new BWBN(tag, alpha, E, n, gamma, beta, Ao, + pinch_start, pinch_slip, pinch_slope, + pinch_size, pinch_rate, pinch_lamda, + tolerance, iterations); + } + else { + opserr << "WARNING BoucWen: invalid material type\n"; + return TCL_ERROR; + } + + if (theMaterial == nullptr) + return TCL_ERROR; + + return builder->addTaggedObject(*theMaterial); +} + + +int +TclCommand_newBoucWen(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + + if (strcmp(argv[1], "BWBF") == 0 || + strcmp(argv[1], "Bouc") == 0) { + + enum class Positions: int { + Tag, + E, Fy, Alpha, N, + EndRequired, + Beta, + Tolerance, Iterations, + Ao, DeltaA, DeltaV, DeltaN, + PinchSlope, PinchStart, PinchRate, PinchSize, PinchSlip, PinchLamda, + EndAllowed, + Mu, AlphaNL, + Gamma, + End + }; + + return ParseBoucWen(clientData, interp, argc, argv); + } + + else if ((strcmp(argv[1], "BoucWen") == 0)) { + + enum class Positions: int { + Tag, + Alpha, E, N, Gamma, Beta, Ao, DeltaA, DeltaV, DeltaN, + EndRequired, + EndAllowed, + Fy, + Tolerance, Iterations, + PinchSlope, PinchStart, PinchRate, PinchSize, PinchSlip, PinchLamda, + Mu, AlphaNL, + End + }; + return ParseBoucWen(clientData, interp, argc, argv); + } + + else if ((strcmp(argv[1], "BWBN") == 0)) { + + enum class Positions: int { + Tag, + Alpha, E, N, Gamma, Beta, Ao, + PinchStart, PinchSlip, PinchSlope, PinchSize, PinchRate, PinchLamda, + EndRequired, + EndAllowed, + Fy, + Tolerance, Iterations, + DeltaA, DeltaV, DeltaN, + Mu, AlphaNL, + End + }; + return ParseBoucWen(clientData, interp, argc, argv); + } + + else if (strcmp(argv[1], "BoucWenOriginal") == 0) { + // A. Schellenberg + enum class Positions: int { + Tag, + E, Fy, Alpha, + EndRequired, + AlphaNL, + Mu, + N, Beta, Gamma, + Tolerance, Iterations, + End, + Ao, DeltaA, DeltaV, DeltaN, + PinchSlope, PinchStart, PinchRate, PinchSize, PinchSlip, PinchLamda, + }; + return ParseBoucWen(clientData, interp, argc, argv); + } + + return TCL_ERROR; +} diff --git a/SRC/runtime/commands/modeling/material/concrete.cpp b/SRC/runtime/commands/modeling/material/concrete.cpp new file mode 100644 index 0000000000..20e403ecf3 --- /dev/null +++ b/SRC/runtime/commands/modeling/material/concrete.cpp @@ -0,0 +1,408 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Written: cmp +// April 2025 +// +#include +#include +#include +#ifdef _MSC_VER +# include +# define strcasecmp _stricmp +#else +# include +#endif +#include +#include +#include +#include +#include "isotropy.h" + +#include + +int +TclCommand_newConcreteMaterial(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + + assert(clientData != nullptr); + enum class Position { + Tag, E, Nu, PeakTension, PeakCompression, EndRequired, + Beta, Ap, An, Bn, + Density, + G, K, Lambda, + End, + }; + ArgumentTracker tracker; + std::set positional; + + + // Count the number of required isotropic parameters. + // This is needed to accommodate uniaxial materials, which generally + // only require one isotropic parameter (ie, E). + int niso = ( + (Position::E < Position::EndRequired) + + (Position::G < Position::EndRequired) + + (Position::Nu < Position::EndRequired) + + (Position::K < Position::EndRequired) + + (Position::Lambda < Position::EndRequired) + ); + + // + // Values we're parsing for + // + int tag; + double density = 0.0; + // Isotropy + IsotropicConstants consts {}; + // Plasticity + double Fc, Ft=0; + // Hardening + double beta = 0.6; + double Ap = 0.5, + An = 2.0, + Bn = 0.75; + + + // + // 1. Keyword arguments + // + + // Isotropy + IsotropicParse iso {consts, niso}; + if (TclCommand_setIsotropicParameters((ClientData)&iso, interp, argc, argv) == TCL_OK) { + tracker.consume(Position::E); + tracker.consume(Position::G); + tracker.consume(Position::Nu); + tracker.consume(Position::K); + tracker.consume(Position::Lambda); + } + + // Other arguments + for (int i=2; i= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &density) != TCL_OK) { + opserr << "Invalid density value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + } + + // Compression + else if (strcmp(argv[i], "-Fc") == 0 || + strcmp(argv[i], "-fc") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Fc) != TCL_OK) { + opserr << "Invalid " << &argv[i-1][1] << " value " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::PeakCompression); + } + // Tension + else if ((strcmp(argv[i], "-Ft") == 0)) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Ft) != TCL_OK) { + opserr << "Invalid " << &argv[i-1][1] << " value " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::PeakTension); + } + // + // Hardening + // + else if (strcmp(argv[i], "-beta") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &beta) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Beta); + } + // + // + else if (strcmp(argv[i], "-Ap") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Ap) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Ap); + } + else if (strcmp(argv[i], "-An") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &An) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::An); + } + else if (strcmp(argv[i], "-Bn") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Bn) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Bn); + } + else + positional.insert(i); + } + + // + // 2) Positional arguments + // + for (int i : positional) { + + if (tracker.current() == Position::EndRequired) + tracker.increment(); + + switch (tracker.current()) { + // General + case Position::Tag : + if (Tcl_GetInt(interp, argv[i], &tag) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid section Elastic tag.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Density: + if (Tcl_GetDouble (interp, argv[i], &density) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid density.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + // Isotropy + case Position::E: + if (Tcl_GetDouble (interp, argv[i], &consts.E) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid E.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::G: + if (Tcl_GetDouble (interp, argv[i], &consts.G) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid G.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::K: + if (Tcl_GetDouble (interp, argv[i], &consts.K) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid K.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::Nu: + if (Tcl_GetDouble (interp, argv[i], &consts.nu) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid nu.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::Lambda: + if (Tcl_GetDouble (interp, argv[i], &consts.lambda) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Lame lambda.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + // Yielding + case Position::PeakCompression: + if (Tcl_GetDouble(interp, argv[i], &Fc) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Fc.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::PeakTension: + if (Tcl_GetDouble (interp, argv[i], &Ft) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Ft.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Beta: + if (Tcl_GetDouble (interp, argv[i], &beta) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid beta.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Ap: + if (Tcl_GetDouble (interp, argv[i], &Ap) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Ap.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::An: + if (Tcl_GetDouble (interp, argv[i], &An) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid An.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Bn: + if (Tcl_GetDouble (interp, argv[i], &Bn) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Bn.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + + case Position::EndRequired: + // This will not be reached + break; + + case Position::End: + opserr << OpenSees::PromptParseError << "unexpected argument " << argv[i] << ".\n"; + return TCL_ERROR; + } + } + + + // + // 3. Check for required arguments + // + if (tracker.current() < Position::EndRequired) { + opserr << OpenSees::PromptParseError + << "missing required arguments: "; + while (tracker.current() != Position::EndRequired) { + switch (tracker.current()) { + case Position::Tag : + opserr << "tag "; + break; + // Isotropy + case Position::E: + opserr << "E "; + break; + case Position::G: + opserr << "G "; + break; + case Position::K: + opserr << "K "; + break; + case Position::Nu: + opserr << "nu "; + break; + case Position::Lambda: + opserr << "lambda "; + break; + // Yielding + case Position::PeakCompression: + opserr << "Fc "; + break; + case Position::PeakTension: + opserr << "Ft "; + break; + case Position::Ap: + opserr << "Ap "; + break; + // Hardening + case Position::An: + opserr << "An "; + break; + case Position::Bn: + opserr << "Bn "; + break; + case Position::Beta: + opserr << "beta "; + break; + + case Position::EndRequired: + case Position::End: + default: + break; + } + + if (tracker.current() == Position::EndRequired) + break; + + tracker.consume(tracker.current()); + } + + opserr << "\n"; + + return TCL_ERROR; + } + + // + // Create the material (TODO) + // + BasicModelBuilder *builder = static_cast(clientData); + if ((strcmp(argv[1], "PlasticDamageConcrete3d") == 0) || + (strcasecmp(argv[1], "PlasticDamageConcrete") == 0) || + (strcmp(argv[1], "FariaPlasticDamage") == 0)) { + + NDMaterial* theMaterial = new FariaPlasticDamage3d(tag, consts.E, consts.nu, Ft, Fc, + beta, Ap, An, Bn, density); + if (builder->addTaggedObject(*theMaterial) != TCL_OK ) { + delete theMaterial; + return TCL_ERROR; + } + return TCL_OK; + } + + return TCL_ERROR; +} diff --git a/SRC/runtime/commands/modeling/material/elastic.cpp b/SRC/runtime/commands/modeling/material/elastic.cpp new file mode 100644 index 0000000000..b61c391779 --- /dev/null +++ b/SRC/runtime/commands/modeling/material/elastic.cpp @@ -0,0 +1,488 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// cmp +// +#include +#include +#include + +#include +#include +#include "BasicModelBuilder.h" +#include "Logging.h" +#include "Parsing.h" +#include "ArgumentTracker.h" +#include "isotropy.h" + +#include +#include +#include +#include + +#include +#include "ElasticIsotropicPlaneStress2D.h" +#include "ElasticIsotropicPlaneStrain2D.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +template +int +TclCommand_newElasticParser(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + assert(clientData != nullptr); + + ArgumentTracker tracker; + std::set positional; + + int niso = ( + (Position::E < Position::EndRequired) + + (Position::G < Position::EndRequired) + + (Position::Nu < Position::EndRequired) + + (Position::K < Position::EndRequired) + + (Position::Lambda < Position::EndRequired) + ); + + int tag; + double density = 0.0; + // Isotropy + IsotropicConstants consts {}; + // Viscosity + double eta=0; + + + // Isotropy + IsotropicParse iso {consts, niso}; + if (TclCommand_setIsotropicParameters((ClientData)&iso, interp, argc, argv) == TCL_OK) { + tracker.consume(Position::E); + tracker.consume(Position::G); + tracker.consume(Position::Nu); + tracker.consume(Position::K); + tracker.consume(Position::Lambda); + } + + // + // Keywords + // + for (int i=2; i= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &density) != TCL_OK) { + opserr << "Invalid density value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + } + else + positional.insert(i); + } + + // + // Positional arguments + // + for (int i : positional) { + + if (tracker.current() == Position::EndRequired) + tracker.increment(); + + switch (tracker.current()) { + case Position::Tag : + if (Tcl_GetInt(interp, argv[i], &tag) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid section Elastic tag.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::E: + if (Tcl_GetDouble (interp, argv[i], &consts.E) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid E.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::G: + if (Tcl_GetDouble (interp, argv[i], &consts.G) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid G.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::K: + if (Tcl_GetDouble (interp, argv[i], &consts.K) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid K.\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::Nu: + if (Tcl_GetDouble (interp, argv[i], &consts.nu) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid nu.\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::Lambda: + if (Tcl_GetDouble (interp, argv[i], &consts.lambda) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Lame lambda.\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::Eta: + if (Tcl_GetDouble (interp, argv[i], &eta) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid eta.\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::Density: + if (Tcl_GetDouble (interp, argv[i], &density) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid density.\n"; + return TCL_ERROR; + } + tracker.increment(); + break; + + case Position::EndRequired: + // This will not be reached + break; + + case Position::End: + opserr << OpenSees::PromptParseError << "unexpected argument " << argv[i] << ".\n"; + return TCL_ERROR; + } + } + + if (tracker.current() < Position::EndRequired) { + opserr << OpenSees::PromptParseError + << "missing required arguments: "; + + while (tracker.current() != Position::EndRequired) { + switch (tracker.current()) { + case Position::Tag : + opserr << "tag "; + break; + case Position::E: + opserr << "E "; + break; + case Position::G: + opserr << "G "; + break; + case Position::K: + opserr << "K "; + break; + case Position::Nu: + opserr << "nu "; + break; + case Position::Lambda: + opserr << "lambda "; + break; + + case Position::EndRequired: + case Position::End: + default: + break; + } + + if (tracker.current() == Position::EndRequired) + break; + + tracker.consume(tracker.current()); + } + + opserr << "\n"; + + return TCL_ERROR; + } + + // + // Create the material + // + BasicModelBuilder *builder = static_cast(clientData); + + if ((strcmp(argv[1], "ElasticIsotropic") == 0) || + (strcmp(argv[1], "Elastic") == 0)) { + double E = consts.E; + double nu = consts.nu; + if (builder->addTaggedObject(*new ElasticIsotropicMaterial(tag, E, nu, density)) != TCL_OK ) { + return TCL_ERROR; + } + if (strcmp(argv[0], "material") == 0) { + if (builder->addTaggedObject(*new ElasticMaterial(tag, E, eta, E, density)) != TCL_OK ) { + return TCL_ERROR; + } + if (builder->addTaggedObject>(*new ElasticIsotropic<3>(tag, E, nu, density)) != TCL_OK ) { + return TCL_ERROR; + } + } + return TCL_OK; + } + else if (strcmp(argv[1], "ElasticIsotropic3D") == 0) { + double E = consts.E; + double nu = consts.nu; + if (builder->addTaggedObject(*new ElasticIsotropicThreeDimensional(tag, E, nu, density)) != TCL_OK ) { + return TCL_ERROR; + } + return TCL_OK; + } + + return TCL_ERROR; +} + +int +TclCommand_newElasticMaterial(ClientData clientData, Tcl_Interp *interp, + Tcl_Size argc, TCL_Char ** const argv) +{ + // + if (strcmp(argv[1], "ElasticIsotropic") == 0 || + strcmp(argv[1], "Elastic") == 0 || + strcmp(argv[1], "PlaneStressSimplifiedJ2") == 0) { + + // "ElasticIsotropic" tag? E? nu? rho? + enum class Position : int { + Tag, E, Nu, EndRequired, + Density, End, + G, K, Lambda, Eta + }; + return TclCommand_newElasticParser(clientData, interp, argc, argv); + } + + return TCL_ERROR; +} + +int +TclCommand_newElasticUniaxialMaterial(ClientData clientData, Tcl_Interp *interp, + Tcl_Size argc, TCL_Char ** const argv) +{ + enum class Position : int { + Tag, Epos, EndRequired, + Eta, Eneg, Density, End + }; + + ArgumentTracker tracker; + std::set positional; + + int tag; + double Epos = 0.0; + double Eneg = 0.0; + double density = 0.0; + double eta = 0.0; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptParseError + << "invalid tag." + << OpenSees::SignalMessageEnd; + return TCL_ERROR; + } + tracker.consume(Position::Tag); + + for (int i=3; i= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Epos) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Epos); + if (!tracker.contains(Position::Eneg)) { + Eneg = Epos; // Default to Epos if Eneg is not specified + } + } + else if (strcmp(argv[i], "-Eneg") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Eneg) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Eneg); + } + else if (strcmp(argv[i], "-rho") == 0 || strcmp(argv[i], "-density") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &density) != TCL_OK) { + opserr << "Invalid density value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Density); + } + else if (strcmp(argv[i], "-eta") == 0 || strcmp(argv[i], "-viscosity") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &eta) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Eta); + } + else + positional.insert(i); + } + + for (int i : positional) { + if (tracker.current() == Position::EndRequired) + tracker.increment(); + + switch (tracker.current()) { + case Position::Tag : + if (Tcl_GetInt(interp, argv[i], &tag) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid tag.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Epos: + if (Tcl_GetDouble (interp, argv[i], &Epos) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Epos.\n"; + return TCL_ERROR; + } else { + Eneg = Epos; + tracker.increment(); + break; + } + case Position::Eneg: + if (Tcl_GetDouble (interp, argv[i], &Eneg) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Eneg.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Density: + if (Tcl_GetDouble (interp, argv[i], &density) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid density.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Eta: + if (Tcl_GetDouble (interp, argv[i], &eta) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid eta.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::EndRequired: + case Position::End: + opserr << OpenSees::PromptParseError + << "unexpected argument " << argv[i] << ".\n"; + return TCL_ERROR; + } + } + + + if (tracker.current() < Position::EndRequired) { + opserr << OpenSees::PromptParseError + << "missing required arguments: "; + + while (tracker.current() != Position::EndRequired) { + switch (tracker.current()) { + case Position::Tag : + opserr << "tag "; + break; + case Position::Epos: + opserr << "Epos "; + break; + case Position::Eneg: + opserr << "Eneg "; + break; + case Position::Density: + opserr << "density "; + break; + case Position::Eta: + opserr << "eta "; + break; + + case Position::EndRequired: + case Position::End: + default: + break; + } + + if (tracker.current() == Position::EndRequired) + break; + + tracker.consume(tracker.current()); + } + + opserr << "\n"; + + return TCL_ERROR; + } + + BasicModelBuilder *builder = static_cast(clientData); + if (strcmp(argv[1], "Elastic") == 0) { + if (builder->addTaggedObject(*new ElasticMaterial(tag, Epos, eta, Eneg, density)) != TCL_OK ) { + return TCL_ERROR; + } + return TCL_OK; + } + + return TCL_ERROR; +} + + +enum class MaterialSymmetry { + Triclinic , // 21 + Monoclinic , // 13 + Orthorhombic , // 9 + Tetragonal , // 7 +//Tetragonal , // 6 + Rhombohedral , // 7 +//Rhombohedral , // 6 + Hexagonal , // 5 + Cubic , // 3 + Isotropic // 2 +}; + diff --git a/SRC/runtime/commands/modeling/material/fedeas.cpp b/SRC/runtime/commands/modeling/material/fedeas.cpp new file mode 100644 index 0000000000..7043853aac --- /dev/null +++ b/SRC/runtime/commands/modeling/material/fedeas.cpp @@ -0,0 +1,678 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Written: cmp +// +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +# define strcasecmp _stricmp +#else +# include +#endif +#define strcmp strcasecmp + +#include +#include +#include +#include +#include +#include +#include + + +template +static int +FedeasConcrParse(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + + BasicModelBuilder *builder = static_cast(clientData); + + ArgumentTracker tracker; + std::set positional; + + + int tag; + double fpc, epsc0, fpcu, epscu; + double rat=0.1, ft=0, Ets=0; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid uniaxialMaterial tag\n"; + return TCL_ERROR; + } + + for (int i=2; i= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &fpc) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (tracker.contains(Positions::ft)) + ft = 0.1*fpc; + tracker.consume(Positions::fpc); + } + else if ((strcasecmp(argv[i], "-epsc0") == 0) || (strcmp(argv[i], "-ec0") == 0)) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &epsc0) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::epsc0); + } + else if (strcasecmp(argv[i], "-fpcu") == 0 || strcasecmp(argv[i], "-Fcu") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &fpcu) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::fpcu); + } + else if (strcasecmp(argv[i], "-epscu") == 0 || strcmp(argv[i], "-ecu") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &epscu) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::epscu); + } + else + positional.insert(i); + } + + + for (int i: positional) { + if (tracker.current() == Positions::EndRequired) + tracker.increment(); + + switch (tracker.current()) { + case Positions::Tag : + if (Tcl_GetInt(interp, argv[i], &tag) != TCL_OK) { + opserr << "Invalid tag " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Tag); + break; + + case Positions::fpc: + if (Tcl_GetDouble(interp, argv[i], &fpc) != TCL_OK) { + opserr << "Invalid value for Fc " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::fpc); + break; + case Positions::epsc0: + if (Tcl_GetDouble(interp, argv[i], &epsc0) != TCL_OK) { + opserr << "Invalid value for ec0 " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::epsc0); + break; + case Positions::fpcu: + if (Tcl_GetDouble(interp, argv[i], &fpcu) != TCL_OK) { + opserr << "Invalid value for Fcu " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::fpcu); + break; + case Positions::epscu: + if (Tcl_GetDouble(interp, argv[i], &epscu) != TCL_OK) { + opserr << "Invalid value for ecu " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::epscu); + break; + case Positions::rat: + if (Tcl_GetDouble(interp, argv[i], &rat) != TCL_OK) { + opserr << "Invalid value for option " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::rat); + break; + case Positions::ft: + if (Tcl_GetDouble(interp, argv[i], &ft) != TCL_OK) { + opserr << "Invalid value for option " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::ft); + break; + case Positions::Ets: + if (Tcl_GetDouble(interp, argv[i], &Ets) != TCL_OK) { + opserr << "Invalid value for option " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Ets); + break; + + case Positions::EndRequired: + // This will not be reached + break; + + case Positions::End: + opserr << "Invalid value for option " << argv[i] << "\n"; + return TCL_ERROR; + } + } + + if (tracker.current() < Positions::EndRequired) { + opserr << "Missing required arguments: "; + while (tracker.current() != Positions::End) { + switch (tracker.current()) { + case Positions::fpc: + opserr << "fpc "; + break; + case Positions::epsc0: + opserr << "epsc0 "; + break; + case Positions::fpcu: + opserr << "Fcu "; + break; + case Positions::epscu: + opserr << "epscu "; + break; + case Positions::rat: + opserr << "rat "; + break; + case Positions::ft: + opserr << "ft "; + break; + case Positions::Ets: + opserr << "Ets "; + break; + case Positions::EndRequired: + case Positions::End: + default: + break; + } + + if (tracker.current() == Positions::End) + break; + + tracker.consume(tracker.current()); + } + opserr << "\n"; + return TCL_ERROR; + } + + // + // + // + if (fpcu > 0.0) { + fpcu *= -1; + // opswrn << OpenSees::SignalWarning << "Fcu should be negative\n"; + } + + // + // + // + UniaxialMaterial *theMaterial = nullptr; + if (strcmp(argv[1], "Concrete1") == 0 || + strcasecmp(argv[1], "Concrete01") == 0) { + + theMaterial = new Concrete01(tag, fpc, epsc0, fpcu, epscu); + } + + else if ((strcmp(argv[1], "concr2") == 0) || + (strcmp(argv[1], "Concrete02") == 0)) { + + theMaterial = + new Concrete02(tag, fpc, epsc0, fpcu, epscu, rat, ft, Ets); + } + + if (theMaterial == nullptr) + return TCL_ERROR; + + return builder->addTaggedObject(*theMaterial); +} + + +template +static int +FedeasSteelParse(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + BasicModelBuilder *builder = static_cast(clientData); + + ArgumentTracker tracker; + std::set positional; + + UniaxialMaterial *theMaterial = nullptr; + + int tag; + double fy, E, b; + + double a1 = 0.0, + a2 = 1.0, + a3 = 0.0, + a4 = 1.0; + double R0 = 15.0, + cR1 = 0.925, + cR2 = 0.15; + + for (int i=2; i= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &fy) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::fy); + } + else if (strcmp(argv[i], "-E") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &E) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::E); + } + else if (strcmp(argv[i], "-b") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &b) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::b); + } + else if (strcmp(argv[i], "-R0") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &R0) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::R0); + } + else if (strcmp(argv[i], "-cR1") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &cR1) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::cR1); + } + else if (strcmp(argv[i], "-cR2") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &cR2) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::cR2); + } + else if (strcmp(argv[i], "-a1") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &a1) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::a1); + } + else if (strcmp(argv[i], "-a2") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &a2) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::a2); + } + else if (strcmp(argv[i], "-a3") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &a3) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::a3); + } + else if (strcmp(argv[i], "-a4") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &a4) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::a4); + } + else + positional.insert(i); + } + + // + // Positional arguments + // + for (int i : positional) { + + if (tracker.current() == Positions::EndRequired) + tracker.increment(); + + switch (tracker.current()) { + case Positions::Tag: + if (Tcl_GetInt(interp, argv[i], &tag) != TCL_OK) { + opserr << "invalid tag.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::fy : + if (Tcl_GetDouble(interp, argv[i], &fy) != TCL_OK) { + opserr << "invalid Fy.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::E: + if (Tcl_GetDouble(interp, argv[i], &E) != TCL_OK) { + opserr << "invalid E.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::b: + if (Tcl_GetDouble(interp, argv[i], &b) != TCL_OK) { + opserr << "invalid b.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::R0: + if (Tcl_GetDouble(interp, argv[i], &R0) != TCL_OK) { + opserr << "invalid R0.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::cR1: + if (Tcl_GetDouble(interp, argv[i], &cR1) != TCL_OK) { + opserr << "invalid cR1.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::cR2: + if (Tcl_GetDouble(interp, argv[i], &cR2) != TCL_OK) { + opserr << "invalid cR2.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::a1: + if (Tcl_GetDouble(interp, argv[i], &a1) != TCL_OK) { + opserr << "invalid a1.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::a2: + if (Tcl_GetDouble(interp, argv[i], &a2) != TCL_OK) { + opserr << "invalid a2.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::a3: + if (Tcl_GetDouble(interp, argv[i], &a3) != TCL_OK) { + opserr << "invalid a3.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::a4: + if (Tcl_GetDouble(interp, argv[i], &a4) != TCL_OK) { + opserr << "invalid a4.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Positions::sig0: + if (Tcl_GetDouble(interp, argv[i], &a4) != TCL_OK) { + opserr << "invalid sig0.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Positions::EndRequired: + // This will not be reached + break; + + case Positions::End: + opserr << "unexpected argument " << argv[i] << ".\n"; + return TCL_ERROR; + } + } + + // Check all required arguments are present + if (tracker.current() < Positions::EndRequired) { + opserr << "missing required arguments: "; + while (tracker.current() != Positions::EndRequired) { + switch (tracker.current()) { + case Positions::Tag : + opserr << "tag "; + break; + case Positions::fy : + opserr << "Fy "; + break; + case Positions::E: + opserr << "E "; + break; + case Positions::b: + opserr << "b "; + break; + case Positions::R0: + opserr << "R0 "; + break; + case Positions::cR1: + opserr << "cR1 "; + break; + case Positions::cR2: + opserr << "cR2 "; + break; + case Positions::a1: + opserr << "a1 "; + break; + case Positions::a2: + opserr << "a2 "; + break; + case Positions::a3: + opserr << "a3 "; + break; + case Positions::a4: + opserr << "a4 "; + break; + case Positions::sig0: + opserr << "sig0 "; + break; + + case Positions::EndRequired: + case Positions::End: + default: + break; + } + + if (tracker.current() == Positions::EndRequired) + break; + + tracker.consume(tracker.current()); + } + + opserr << "\n"; + + return TCL_ERROR; + } + + + if (strcmp(argv[1], "Steel1") == 0 || + strcmp(argv[1], "Steel01") == 0) { + theMaterial = new Steel01(tag, fy, E, b, a1, a2, a3, a4); + } + + else if (strcmp(argv[1], "Steel01Thermal") == 0) { + theMaterial = new Steel01Thermal(tag, fy, E, b, a1, a2, a3, a4); + } + + else if ((strcmp(argv[1], "Steel2") == 0)) { + theMaterial = new Steel2(tag, fy, E, b, R0, cR1, cR2, a1, a2, a3, a4); + } + + else if ((strcmp(argv[1], "Steel02") == 0)) { + theMaterial = new Steel02(tag, fy, E, b, R0, cR1, cR2, a1, a2, a3, a4); + } + + else if ((strcmp(argv[1], "Steel02Thermal") == 0)) { + theMaterial = new Steel02Thermal(tag, fy, E, b, R0, cR1, cR2); + } + + if (theMaterial == nullptr) + return TCL_ERROR; + + return builder->addTaggedObject(*theMaterial); +} + + +int +TclCommand_newFedeasSteel(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + + if (strcmp(argv[1], "Steel01") == 0 || + strcmp(argv[1], "Steel01Thermal") == 0 || + strcmp(argv[1], "Steel1") == 0) { + + // uniaxialMaterial Steel01 tag? fy? E? b? + enum class Positions: int { + Tag, + fy, E, b, EndRequired, + a1, a2, a3, a4, End, + R0, cR1, cR2, sig0 + }; + + return FedeasSteelParse(clientData, interp, argc, argv); + } + + else if ((strcmp(argv[1], "Steel02") == 0) || + (strcmp(argv[1], "Steel2") == 0) || + (strcmp(argv[1], "Steel02Thermal") == 0) || + (strcmp(argv[1], "SteelMP") == 0) + ) { + + // uniaxialMaterial Steel02 $tag $Fy $E $b $R0 $cR1 $cR2 <$a1 $a2 $a3 $a4 $sigInit> + enum class Positions: int { + Tag, + fy, E, b, EndRequired, + R0, cR1, cR2, a1, a2, a3, a4, sig0, End + }; + return FedeasSteelParse(clientData, interp, argc, argv); + } + + return TCL_ERROR; +} + + +int +TclCommand_newFedeasConcrete(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + + if (strcmp(argv[1], "Concrete01") == 0 || + strcmp(argv[1], "Concrete1") == 0) { + + // uniaxialMaterial Concrete01 tag? fpc? epsc0? fpcu? epscu? + enum class Positions: int { + Tag, + fpc, epsc0, fpcu, epscu, EndRequired, + End, + rat, ft, Ets + }; + + return FedeasConcrParse(clientData, interp, argc, argv); + } + + else if ((strcmp(argv[1], "Concrete02") == 0) || + (strcmp(argv[1], "Concrete2") == 0) || + (strcmp(argv[1], "Concrete02Thermal") == 0) + ) { + + // uniaxialMaterial Concrete02 tag? fpc? epsc0? fpcu? epscu? rat? ft? Ets? + enum class Positions: int { + Tag, + fpc, epsc0, fpcu, epscu, EndRequired, + rat, ft, Ets, + End + }; + return FedeasConcrParse(clientData, interp, argc, argv); + } + + return TCL_ERROR; +} + + diff --git a/SRC/runtime/commands/modeling/material/isotropy.cpp b/SRC/runtime/commands/modeling/material/isotropy.cpp new file mode 100644 index 0000000000..00eae94af3 --- /dev/null +++ b/SRC/runtime/commands/modeling/material/isotropy.cpp @@ -0,0 +1,426 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// + +#include "isotropy.h" +#include +#include +#include +#include +#include + +namespace Isotropy { + enum class Parameter : int { + YoungModulus = 1 << 0, // E + ShearModulus = 1 << 1, // G + BulkModulus = 1 << 2, // K + PoissonsRatio = 1 << 3, // ν + LameLambda = 1 << 4 // λ, Lame's first parameter + }; +} + +namespace { + const int E_FLAG = static_cast(Isotropy::Parameter::YoungModulus); + const int G_FLAG = static_cast(Isotropy::Parameter::ShearModulus); + const int K_FLAG = static_cast(Isotropy::Parameter::BulkModulus); + const int NU_FLAG = static_cast(Isotropy::Parameter::PoissonsRatio); + const int LAMBDA_FLAG = static_cast(Isotropy::Parameter::LameLambda); + + const double TOL = 1e-12; + + // Convert any input pair (flag1,in1) and (flag2,in2) to the canonical pair (E, ν). + // Returns 0 on success, nonzero on failure. + int convertToEN(int flag1, double in1, + int flag2, double in2, + double &E, double &nu) + { + // Case A: Already (E, ν) + if ((flag1 == E_FLAG && flag2 == NU_FLAG) || + (flag1 == NU_FLAG && flag2 == E_FLAG)) { + E = (flag1 == E_FLAG) ? in1 : in2; + nu = (flag1 == NU_FLAG) ? in1 : in2; + return 0; + } + // Case B: (G, ν): E = 2G(1+ν) + if ((flag1 == G_FLAG && flag2 == NU_FLAG) || + (flag1 == NU_FLAG && flag2 == G_FLAG)) { + double G = (flag1 == G_FLAG) ? in1 : in2; + nu = (flag1 == NU_FLAG) ? in1 : in2; + E = 2.0 * G * (1.0 + nu); + return 0; + } + // Case C: (K, ν): E = 3K(1-2ν) + if ((flag1 == K_FLAG && flag2 == NU_FLAG) || + (flag1 == NU_FLAG && flag2 == K_FLAG)) { + double K = (flag1 == K_FLAG) ? in1 : in2; + nu = (flag1 == NU_FLAG) ? in1 : in2; + E = 3.0 * K * (1.0 - 2.0 * nu); + return 0; + } + // Case D: (λ, ν): E = λ (1+ν)(1-2ν)/ν (if ν != 0) + if ((flag1 == LAMBDA_FLAG && flag2 == NU_FLAG) || + (flag1 == NU_FLAG && flag2 == LAMBDA_FLAG)) { + double lambda = (flag1 == LAMBDA_FLAG) ? in1 : in2; + nu = (flag1 == NU_FLAG) ? in1 : in2; + if (std::fabs(nu) < TOL) + return -1; + E = lambda * (1.0 + nu) * (1.0 - 2.0 * nu) / nu; + return 0; + } + // Case E: (G, K): Use standard formulas: + // ν = (3K - 2G) / (2(3K+G)) + // E = 9K·G/(3K+G) + if ((flag1 == G_FLAG && flag2 == K_FLAG) || + (flag1 == K_FLAG && flag2 == G_FLAG)) { + double G = (flag1 == G_FLAG) ? in1 : in2; + double K = (flag1 == K_FLAG) ? in1 : in2; + if (std::fabs(3.0*K + G) < TOL) + return -1; + nu = (3.0 * K - 2.0 * G) / (2.0 * (3.0 * K + G)); + E = 9.0 * K * G / (3.0 * K + G); + return 0; + } + // Case F: (G, λ): From known relations for isotropic materials: + // ν = λ / [2(λ+G)] + // E = G(3λ+2G)/(λ+G) + if ((flag1 == G_FLAG && flag2 == LAMBDA_FLAG) || + (flag1 == LAMBDA_FLAG && flag2 == G_FLAG)) { + double G = (flag1 == G_FLAG) ? in1 : in2; + double lambda = (flag1 == LAMBDA_FLAG) ? in1 : in2; + if (std::fabs(lambda + G) < TOL) return -1; + nu = lambda / (2.0 * (lambda + G)); + E = G * (3.0 * lambda + 2.0 * G) / (lambda + G); + return 0; + } + // Case G: (K, λ): Use the relation K = λ + 2G/3. + // Hence G = 3(K - λ)/2, then + // ν = λ / (3K - λ) + // E = 9K(K - λ)/(3K - λ) + if ((flag1 == K_FLAG && flag2 == LAMBDA_FLAG) || + (flag1 == LAMBDA_FLAG && flag2 == K_FLAG)) { + double K = (flag1 == K_FLAG) ? in1 : in2; + double lambda = (flag1 == LAMBDA_FLAG) ? in1 : in2; + if (std::fabs(3.0*K - lambda) < TOL) return -1; + nu = lambda / (3.0 * K - lambda); + E = 9.0 * K * (K - lambda) / (3.0 * K - lambda); + return 0; + } + // Case H: (E, G): ν = E/(2G) - 1. + if ((flag1 == E_FLAG && flag2 == G_FLAG) || + (flag1 == G_FLAG && flag2 == E_FLAG)) { + E = (flag1 == E_FLAG) ? in1 : in2; + double G = (flag1 == G_FLAG) ? in1 : in2; + if (std::fabs(G) < TOL) + return -1; + nu = E / (2.0 * G) - 1.0; + return 0; + } + // Case I: (E, K): ν = (3K - E)/(6K). + if ((flag1 == E_FLAG && flag2 == K_FLAG) || + (flag1 == K_FLAG && flag2 == E_FLAG)) { + E = (flag1 == E_FLAG) ? in1 : in2; + double K = (flag1 == K_FLAG) ? in1 : in2; + if (std::fabs(K) < TOL) return -1; + nu = (3.0 * K - E) / (6.0 * K); + return 0; + } + // Case J: (E, λ): This leads to a quadratic in ν. + if ((flag1 == E_FLAG && flag2 == LAMBDA_FLAG) || + (flag1 == LAMBDA_FLAG && flag2 == E_FLAG)) { + E = (flag1 == E_FLAG) ? in1 : in2; + double lambda = (flag1 == LAMBDA_FLAG) ? in1 : in2; + // Equation: λ(1+ν)(1-2ν) = Eν → 2λ ν² + (λ+E)ν - λ = 0. + double a = 2.0 * lambda; + double b = lambda + E; + double c = -lambda; + double disc = b*b - 4.0 * a * c; + if (disc < 0.0) + return -1; + double sqrt_disc = std::sqrt(disc); + double nu1 = (-b + sqrt_disc) / (2.0 * a); + double nu2 = (-b - sqrt_disc) / (2.0 * a); + // Choose the solution in the physical range (-1, 0.5). + if (nu1 > -1.0 && nu1 < 0.5) { + nu = nu1; + return 0; + } + if (nu2 > -1.0 && nu2 < 0.5) { + nu = nu2; + return 0; + } + return -1; + } + + // Any other combination is not supported. + return -1; + } +} // namespace + + +int +isotropic_constants(int flag1, double in1, int flag2, double in2, IsotropicConstants &iso) +{ + // Convert to canonical (E, ν) + double E, nu; + if (convertToEN(flag1, in1, flag2, in2, E, nu) != 0) + return -1; + + iso.E = E; + iso.nu = nu; + iso.G = E / (2.0 * (1.0 + nu)); + iso.K = E / (3.0 * (1.0 - 2.0 * nu)); + iso.lambda = E * nu / ((1.0 + nu) * (1.0 - 2.0 * nu)); + return 0; +} + + +int +isotropic_convert(int flag1, double in1, + int flag2, double in2, + int flag_out, + double & out) +{ + + // First converts the given input pair into (E, ν) and then computes the requested + // property (if not already provided as one of the inputs). + + // If the output is already one of the inputs, return it. + if (flag_out == flag1) { + out = in1; + return 0; + } + if (flag_out == flag2) { + out = in2; + return 0; + } + + // Convert to canonical (E, ν) + double E, nu; + if (convertToEN(flag1, in1, flag2, in2, E, nu) != 0) + return -1; + + // Now, based solely on (E, ν), compute the desired property. + if (flag_out == E_FLAG) { + out = E; + return 0; + } + if (flag_out == NU_FLAG) { + out = nu; + return 0; + } + if (flag_out == G_FLAG) { + // G = E / [2(1+ν)] + out = E / (2.0 * (1.0 + nu)); + return 0; + } + if (flag_out == K_FLAG) { + // K = E / [3(1-2ν)] + if (std::fabs(1.0 - 2.0*nu) < TOL) return -1; + out = E / (3.0 * (1.0 - 2.0*nu)); + return 0; + } + if (flag_out == LAMBDA_FLAG) { + // λ = E·ν / [(1+ν)(1-2ν)] + if (std::fabs((1.0+nu)*(1.0-2.0*nu)) < TOL) return -1; + out = E * nu / ((1.0 + nu) * (1.0 - 2.0*nu)); + return 0; + } + return -1; +} + + +int +TclCommand_setIsotropicParameters( + ClientData clientData, + Tcl_Interp *interp, + Tcl_Size argc, + TCL_Char ** const argv) +{ + // We expect the syntax: + // material Isotropic $tag + // The tag is still the first non-option argument (argv[2]). + // Among the options, exactly two independent elastic parameters must be provided. + // Valid elastic options: -E, -G, -K, -nu, -lambda. + + bool gotParam1 = false, + gotParam2 = false; + + int flag1 = 0, + flag2 = 0; + double val1 = 0.0, + val2 = 0.0; + + IsotropicParse* data = static_cast(clientData); + IsotropicConstants* iso = &data->constants; + std::set& positions = data->positions; + + assert(iso != nullptr); + + // Process the remaining arguments. + for (int i = 0; i < argc; i++) { + if ((strcmp(argv[i], "-E") == 0) || + (strcmp(argv[i], "-youngs-modulus") == 0)) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &iso->E) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (!gotParam1) { + gotParam1 = true; + val1 = iso->E; + flag1 = static_cast(Isotropy::Parameter::YoungModulus); + } + else if (!gotParam2) { + gotParam2 = true; + val2 = iso->E; + flag2 = static_cast(Isotropy::Parameter::YoungModulus); + } + else { + opserr << "Too many elastic parameter options provided.\n"; + return TCL_ERROR; + } + positions.insert(i-1); + positions.insert(i); + } + + else if (strcmp(argv[i], "-G") == 0 || + strcmp(argv[i], "-shear-modulus") == 0 || + strcmp(argv[i], "-mu") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i], &iso->G) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (!gotParam1) { + gotParam1 = true; + val1 = iso->G; + flag1 = static_cast(Isotropy::Parameter::ShearModulus); + } + else if (!gotParam2) { + gotParam2 = true; + val2 = iso->G; + flag2 = static_cast(Isotropy::Parameter::ShearModulus); + } + else { + opserr << "Too many elastic parameter options provided.\n"; + return TCL_ERROR; + } + positions.insert(i-1); + positions.insert(i); + } + else if (strcmp(argv[i], "-K") == 0 || strcmp(argv[i], "-bulk-modulus") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + double val; + if (Tcl_GetDouble(interp, argv[i], &val) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (!gotParam1) { + gotParam1 = true; + val1 = val; + flag1 = static_cast(Isotropy::Parameter::BulkModulus); + } + else if (!gotParam2) { + gotParam2 = true; + val2 = val; + flag2 = static_cast(Isotropy::Parameter::BulkModulus); + } + else { + opserr << "Too many elastic parameter options provided.\n"; + return TCL_ERROR; + } + positions.insert(i-1); + positions.insert(i); + } + else if (strcmp(argv[i], "-nu") == 0 || strcmp(argv[i], "-poissons-ratio") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + double val; + if (Tcl_GetDouble(interp, argv[i], &val) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (!gotParam1) { + gotParam1 = true; + val1 = val; + flag1 = static_cast(Isotropy::Parameter::PoissonsRatio); + } + else if (!gotParam2) { + gotParam2 = true; + val2 = val; + flag2 = static_cast(Isotropy::Parameter::PoissonsRatio); + } + else { + opserr << "Too many elastic parameter options provided.\n"; + return TCL_ERROR; + } + positions.insert(i-1); + positions.insert(i); + } + else if (strcmp(argv[i], "-lambda") == 0 || strcmp(argv[i], "-lame-lambda") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + double val; + if (Tcl_GetDouble(interp, argv[i], &val) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (!gotParam1) { + gotParam1 = true; + val1 = val; + flag1 = static_cast(Isotropy::Parameter::LameLambda); + } + else if (!gotParam2) { + gotParam2 = true; + val2 = val; + flag2 = static_cast(Isotropy::Parameter::LameLambda); + } + else { + opserr << "Too many elastic parameter options provided.\n"; + return TCL_ERROR; + } + positions.insert(i-1); + positions.insert(i); + } + } + + // Compute canonical Young's modulus and Poisson's ratio. + int ret = isotropic_constants(flag1, val1, flag2, val2, *iso); + if (data->required == 1 && gotParam1) + return TCL_OK; + + if (!gotParam1 || !gotParam2) { + // opserr << "Must specify exactly two independent elastic parameters.\n"; + return TCL_ERROR; + } + + if (ret != 0) + return TCL_ERROR; + + return TCL_OK; +} diff --git a/SRC/runtime/commands/modeling/material/isotropy.h b/SRC/runtime/commands/modeling/material/isotropy.h new file mode 100644 index 0000000000..88508ee3bb --- /dev/null +++ b/SRC/runtime/commands/modeling/material/isotropy.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +#pragma once +#include +#include +#include + +struct IsotropicConstants { + double E; // Young's modulus + double G; // Shear modulus + double K; // Bulk modulus + double nu; // Poisson's ratio + double lambda; // Lamé's first parameter +}; + +struct IsotropicParse { + IsotropicConstants &constants; + int required; + std::set positions; +}; + +//--------------------------------------------------------------------- +// Conversion routine: +// Given two independent isotropic elastic constants—specified by the pair +// (flag1, in1) and (flag2, in2)—compute the requested output property, +// as indicated by flag_out. If one of the outputs is already among the +// inputs its value is returned; otherwise the function first converts +// the pair to the canonical pair (E, ν) and then computes the desired value. +// +// The function returns 0 on success and a nonzero value if the conversion +// cannot be performed (for example, due to an unrecognized combination or +// division by zero). +// +// Example: To compute the shear modulus (G) from a pair of inputs, +// flag_out should be set to the value corresponding to Isotropy::Parameter::ShearModulus +// + +int +TclCommand_setIsotropicParameters(ClientData, Tcl_Interp *, Tcl_Size argc, TCL_Char **argv); + +int isotropic_convert(int flag1, double in1, + int flag2, double in2, + int flag_out, + double & out); + +int isotropic_constants(int flag1, double in1, int flag2, double in2, IsotropicConstants &iso); diff --git a/SRC/runtime/commands/modeling/material/legacy.cpp b/SRC/runtime/commands/modeling/material/legacy.cpp new file mode 100644 index 0000000000..fafac45336 --- /dev/null +++ b/SRC/runtime/commands/modeling/material/legacy.cpp @@ -0,0 +1,617 @@ +//===----------------------------------------------------------------------===// +// +// OpenSees - Open System for Earthquake Engineering Simulation +// +//===----------------------------------------------------------------------===// +// +#include +#include +#include +#include +#include +#include + +#include // MHS +#include // ZHY +#include // Won Lee +#include +#include // NM + + +int +TclDispatch_LegacyUniaxials(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char**const argv) +{ + assert(clientData != nullptr); + BasicModelBuilder *builder = static_cast(clientData); + UniaxialMaterial *theMaterial = nullptr; + + if (strcmp(argv[1], "Elastic2") == 0) { + if (argc < 4 || argc > 5) { + opserr << OpenSees::PromptValueError << "invalid number of arguments\n"; + opserr << "Want: uniaxialMaterial Elastic tag? E? " << "\n"; + return TCL_ERROR; + } + + int tag; + double E; + double eta = 0.0; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid uniaxialMaterial Elastic tag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid E\n"; + opserr << "uniaxiaMaterial Elastic: " << tag << "\n"; + return TCL_ERROR; + } + + if (argc == 5) { + if (Tcl_GetDouble(interp, argv[4], &eta) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid eta\n"; + opserr << "uniaxialMaterial Elastic: " << tag << "\n"; + return TCL_ERROR; + } + } + + // Parsing was successful, allocate the material + theMaterial = new Elastic2Material(tag, E, eta); + + } else if (strcmp(argv[1], "ENT") == 0) { + if (argc < 4) { + opserr << OpenSees::PromptValueError << "invalid number of arguments\n"; + opserr << "Want: uniaxialMaterial ENT tag? E?" << "\n"; + return TCL_ERROR; + } + + int tag; + double E; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid uniaxialMaterial ENT tag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid E\n"; + opserr << "uniaxiaMaterial ENT: " << tag << "\n"; + return TCL_ERROR; + } + + // Parsing was successful, allocate the material + theMaterial = new ENTMaterial(tag, E); + + } + + else if (strcmp(argv[1], "BarSlip") == 0) { + if (argc != 17 && argc != 15) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: uniaxialMaterial BarSlip tag? fc? fy? Es? fu? Eh? db? " + "ld? nb? width? depth? bsflag? type? " + << "\n"; + return TCL_ERROR; + } + + int tag, nb, bsf, typ, dmg=1, unt=1; + double fc, fy, Es, fu, Eh, ld, width, depth, db; + + int argStart = 2; + + if (Tcl_GetInt(interp, argv[argStart++], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid tag\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[argStart++], &fc) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fc\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[argStart++], &fy) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fy\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[argStart++], &Es) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid Es\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[argStart++], &fu) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fu\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[argStart++], &Eh) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid Eh\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[argStart++], &db) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid db\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[argStart++], &ld) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid ld\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[argStart++], &nb) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid nbars\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[argStart++], &width) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid width\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[argStart++], &depth) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid depth\n"; + return TCL_ERROR; + } + + int y; + y = argStart; + + if ((strcmp(argv[y], "strong") == 0) || + (strcmp(argv[y], "Strong") == 0) || (strcmp(argv[y], "weak") == 0) || + (strcmp(argv[y], "Weak") == 0)) { + if ((strcmp(argv[y], "strong") == 0) || + (strcmp(argv[y], "Strong") == 0)) { + bsf = 0; + } + + if ((strcmp(argv[y], "weak") == 0) || (strcmp(argv[y], "Weak") == 0)) { + bsf = 1; + } + } else { + opserr << OpenSees::PromptValueError << "invalid bond strength specified\n"; + return TCL_ERROR; + } + y++; + + if ((strcmp(argv[y], "beamtop") == 0) || + (strcmp(argv[y], "beamTop") == 0) || + (strcmp(argv[y], "beambot") == 0) || + (strcmp(argv[y], "beamBot") == 0) || + (strcmp(argv[y], "beambottom") == 0) || + (strcmp(argv[y], "beamBottom") == 0) || + (strcmp(argv[y], "beam") == 0) || (strcmp(argv[y], "Beam") == 0) || + (strcmp(argv[y], "Column") == 0) || + (strcmp(argv[y], "column") == 0)) { + if ((strcmp(argv[y], "beamtop") == 0) || + (strcmp(argv[y], "beamTop") == 0) || + (strcmp(argv[y], "beam") == 0) || (strcmp(argv[y], "Beam") == 0)) { + typ = 0; + } + + if ((strcmp(argv[y], "beambot") == 0) || + (strcmp(argv[y], "beamBot") == 0) || + (strcmp(argv[y], "beambottom") == 0) || + (strcmp(argv[y], "beamBottom") == 0)) { + typ = 1; + } + + if ((strcmp(argv[y], "column") == 0) || + (strcmp(argv[y], "Column") == 0)) { + typ = 2; + } + } else { + opserr << OpenSees::PromptValueError << "invalid location of bar specified\n"; + return TCL_ERROR; + } + if (argc == 17) { + y++; + + if ((strcmp(argv[y], "damage1") == 0) || + (strcmp(argv[y], "Damage1") == 0) || + (strcmp(argv[y], "damage2") == 0) || + (strcmp(argv[y], "Damage2") == 0) || + (strcmp(argv[y], "nodamage") == 0) || + (strcmp(argv[y], "Nodamage") == 0) || + (strcmp(argv[y], "NoDamage") == 0) || + (strcmp(argv[y], "noDamage") == 0)) { + if ((strcmp(argv[y], "damage1") == 0) || + (strcmp(argv[y], "Damage1") == 0)) { + dmg = 1; + } else if ((strcmp(argv[y], "damage2") == 0) || + (strcmp(argv[y], "Damage2") == 0)) { + dmg = 2; + } else if ((strcmp(argv[y], "nodamage") == 0) || + (strcmp(argv[y], "Nodamage") == 0) || + (strcmp(argv[y], "NoDamage") == 0) || + (strcmp(argv[y], "noDamage") == 0)) { + dmg = 0; + } + + } else { + opserr << OpenSees::PromptValueError << "invalid damage specified\n"; + return TCL_ERROR; + } + + y++; + + if ((strcmp(argv[y], "mpa") == 0) || (strcmp(argv[y], "MPa") == 0) || + (strcmp(argv[y], "mPa") == 0) || (strcmp(argv[y], "Mpa") == 0) || + (strcmp(argv[y], "psi") == 0) || (strcmp(argv[y], "Psi") == 0) || + (strcmp(argv[y], "PSI") == 0) || (strcmp(argv[y], "Pa") == 0) || + (strcmp(argv[y], "pa") == 0) || (strcmp(argv[y], "psf") == 0) || + (strcmp(argv[y], "Psf") == 0) || (strcmp(argv[y], "PSF") == 0) || + (strcmp(argv[y], "ksi") == 0) || (strcmp(argv[y], "Ksi") == 0) || + (strcmp(argv[y], "KSI") == 0) || (strcmp(argv[y], "ksf") == 0) || + (strcmp(argv[y], "Ksf") == 0) || (strcmp(argv[y], "KSF") == 0)) { + if ((strcmp(argv[y], "mpa") == 0) || (strcmp(argv[y], "MPa") == 0) || + (strcmp(argv[y], "mPa") == 0) || (strcmp(argv[y], "Mpa") == 0)) { + unt = 1; + } else if ((strcmp(argv[y], "psi") == 0) || + (strcmp(argv[y], "Psi") == 0) || + (strcmp(argv[y], "PSI") == 0)) { + unt = 2; + } else if ((strcmp(argv[y], "Pa") == 0) || + (strcmp(argv[y], "pa") == 0)) { + unt = 3; + } else if ((strcmp(argv[y], "psf") == 0) || + (strcmp(argv[y], "Psf") == 0) || + (strcmp(argv[y], "PSF") == 0)) { + unt = 4; + } else if ((strcmp(argv[y], "ksi") == 0) || + (strcmp(argv[y], "Ksi") == 0) || + (strcmp(argv[y], "KSI") == 0)) { + unt = 5; + } else if ((strcmp(argv[y], "ksf") == 0) || + (strcmp(argv[y], "Ksf") == 0) || + (strcmp(argv[y], "KSF") == 0)) { + unt = 6; + } + } else { + opserr << OpenSees::PromptValueError << "invalid unit specified\n"; + return TCL_ERROR; + } + } + + // allocate the material + if (argc == 15) { + theMaterial = new BarSlipMaterial(tag, fc, fy, Es, fu, Eh, db, ld, nb, + width, depth, bsf, typ); + } + + if (argc == 17) { + theMaterial = new BarSlipMaterial(tag, fc, fy, Es, fu, Eh, db, ld, nb, + width, depth, bsf, typ, dmg, unt); + } + + } + + else if (strcmp(argv[1], "ShearPanel") == 0) { + if (argc != 42 && argc != 31) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: uniaxialMaterial ShearPanel tag? stress1p? strain1p? " + "stress2p? strain2p? stress3p? strain3p? stress4p? strain4p? " + << "\n rDispP? rForceP? uForceP? " + << "\n gammaK1? gammaK2? gammaK3? " + "gammaK4? gammaKLimit? gammaD1? gammaD2? gammaD3? gammaD4? " + << "\ngammaDLimit? gammaF1? gammaF2? gammaF3? gammaF4? " + "gammaFLimit? gammaE? YieldStress? "; + return TCL_ERROR; + } + + int tag; + double stress1p, stress2p, stress3p, stress4p; + double strain1p, strain2p, strain3p, strain4p; + double stress1n, stress2n, stress3n, stress4n; + double strain1n, strain2n, strain3n, strain4n; + double rDispP, rForceP, uForceP, rDispN, rForceN, uForceN; + double gammaK1, gammaK2, gammaK3, gammaK4, gammaKLimit; + double gammaD1, gammaD2, gammaD3, gammaD4, gammaDLimit; + double gammaF1, gammaF2, gammaF3, gammaF4, gammaFLimit; + double gammaE, yStr; + + int i = 2; + + if (Tcl_GetInt(interp, argv[i++], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid uniaxialMaterial ShearPanel tag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &stress1p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid stress1p\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &strain1p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid strain1p\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &stress2p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid stress2p\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &strain2p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid strain2p\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &stress3p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid stress3p\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &strain3p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid strain3p\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &stress4p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid stress4p\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &strain4p) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid strain4p\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (argc == 42) { + if (Tcl_GetDouble(interp, argv[i++], &stress1n) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid stress1n\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &strain1n) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid strain1n\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &stress2n) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid stress2n\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &strain2n) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid strain2n\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &stress3n) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid stress3n\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &strain3n) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid strain3n\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &stress4n) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid stress4n\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &strain4n) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid strain4n\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + } + + if (Tcl_GetDouble(interp, argv[i++], &rDispP) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid rDispP\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &rForceP) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid rForceP\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &uForceP) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid uForceP\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (argc == 42) { + if (Tcl_GetDouble(interp, argv[i++], &rDispN) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid rDispN\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &rForceN) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid rForceN\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &uForceN) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid uForceN\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + } + + if (Tcl_GetDouble(interp, argv[i++], &gammaK1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaK1\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaK2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaK2\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaK3) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaK3\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaK4) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaK4\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaKLimit) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaKLimit\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaD1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaD1\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaD2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaD2\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaD3) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaD3\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaD4) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaD4\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaDLimit) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaDLimit\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaF1) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaF1\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaF2) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaF2\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaF3) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaF3\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaF4) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaF4\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i++], &gammaFLimit) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaFLimit\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &gammaE) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid gammaE\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[i++], &yStr) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid yield stress\n"; + opserr << "ShearPanel material: " << tag << "\n"; + return TCL_ERROR; + } + + // allocate the pinching material + if (argc == 42) { + theMaterial = new ShearPanelMaterial( + tag, stress1p, strain1p, stress2p, strain2p, stress3p, strain3p, + stress4p, strain4p, stress1n, strain1n, stress2n, strain2n, + stress3n, strain3n, stress4n, strain4n, rDispP, rForceP, uForceP, + rDispN, rForceN, uForceN, gammaK1, gammaK2, gammaK3, gammaK4, + gammaKLimit, gammaD1, gammaD2, gammaD3, gammaD4, gammaDLimit, + gammaF1, gammaF2, gammaF3, gammaF4, gammaFLimit, gammaE, yStr); + } + if (argc == 31) { + theMaterial = new ShearPanelMaterial( + tag, stress1p, strain1p, stress2p, strain2p, stress3p, strain3p, + stress4p, strain4p, rDispP, rForceP, uForceP, gammaK1, gammaK2, + gammaK3, gammaK4, gammaKLimit, gammaD1, gammaD2, gammaD3, gammaD4, + gammaDLimit, gammaF1, gammaF2, gammaF3, gammaF4, gammaFLimit, + gammaE, yStr); + } + } + + else if (strcmp(argv[1], "Concrete01WithSITC") == 0) { + if (argc < 7) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: uniaxialMaterial Concrete01 tag? fpc? epsc0? fpcu? " + "epscu? " + << "\n"; + return TCL_ERROR; + } + + int tag; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid uniaxialMaterial Concrete01 tag" << "\n"; + return TCL_ERROR; + } + + // Read required Concrete01 material parameters + double fpc, epsc0, fpcu, epscu; + + if (Tcl_GetDouble(interp, argv[3], &fpc) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fpc\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[4], &epsc0) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid epsc0\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[5], &fpcu) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid fpcu\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[6], &epscu) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid epscu\n"; + return TCL_ERROR; + } + + if (argc == 7) + // Parsing was successful, allocate the material + theMaterial = new Concrete01WithSITC(tag, fpc, epsc0, fpcu, epscu); + else { + double endStrainSITC; + if (Tcl_GetDouble(interp, argv[7], &endStrainSITC) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid epscu\n"; + return TCL_ERROR; + } + theMaterial = + new Concrete01WithSITC(tag, fpc, epsc0, fpcu, epscu, endStrainSITC); + } + } + + if (theMaterial == nullptr) + return TCL_ERROR; + + if (builder->addTaggedObject(*theMaterial) != TCL_OK) { + delete theMaterial; + return TCL_ERROR; + } + + return TCL_OK; +} + diff --git a/SRC/runtime/commands/modeling/material/material.cpp b/SRC/runtime/commands/modeling/material/material.cpp new file mode 100644 index 0000000000..1a581f803c --- /dev/null +++ b/SRC/runtime/commands/modeling/material/material.cpp @@ -0,0 +1,69 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** With a lot of additions by ** +** Boris Jeremic (jeremic@ucdavis.edu) ** +** Zaohui Yang (zhyang@ucdavis.edu) ** +** Zhao Cheng (zcheng@ucdavis.edu) ** +** ** +** ****************************************************************** */ +// +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + + +Tcl_CmdProc TclCommand_newPlasticMaterial; +Tcl_CmdProc TclCommand_newElasticMaterial; + + + +int +TclCommand_addMaterial(ClientData clientData, Tcl_Interp* interp, + Tcl_Size argc, TCL_Char** const argv) +{ + static + std::unordered_map MaterialLibrary = { + {"ElasticIsotropic", TclCommand_newElasticMaterial}, + {"Elastic", TclCommand_newElasticMaterial}, + {"Isotropic", TclCommand_newElasticMaterial}, + {"J2", TclCommand_newPlasticMaterial}, + {"J2Simplified", TclCommand_newPlasticMaterial}, + {"J2BeamFiber", TclCommand_newPlasticMaterial}, + }; + + + if (argc < 2) { + opserr << OpenSees::PromptValueError + << "missing argument type" + << "\n"; + return TCL_ERROR; + } + + + auto cmd = MaterialLibrary.find(std::string(argv[1])); + if (cmd != MaterialLibrary.end()) + return (*cmd->second)(clientData, interp, argc, &argv[0]); + + return TCL_ERROR; + +} diff --git a/SRC/runtime/commands/modeling/material/material.hpp b/SRC/runtime/commands/modeling/material/material.hpp new file mode 100644 index 0000000000..30b651465f --- /dev/null +++ b/SRC/runtime/commands/modeling/material/material.hpp @@ -0,0 +1,290 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// +// +// stress | strain +// 1 2 3 4 5 6 | +// xx yy zz xy yz xz | 11 22 33 12 23 31 +// PSn: 1 2 3 | 1 2 0 3 0 0 +// PSe: 1 2 0 3 - ? | 1 2 [1] 3 [2] [3] +// PF : 1 2 - 3 4 5 | 1 2 [1] 3 4 5 +// BF : 1 0 0 2 0 3 | 1 [1] [2] 2 [3] 3 +// AS?: 1 2 3 4 - +// +// strains ordered 00, 11, 22, 01 +// i.e. 11, 22, 33, 12 +// +// strain(0) = eps_00 +// strain(1) = eps_11 +// strain(2) = eps_22 +// strain(3) = 2*eps_01 +// +// same ordering for stresses but no 2 +// +// +// strains ordered : eps11, eps22, eps33, 2*eps12, 2*eps23, 2*eps31 +// NDmaterial strain order = 11, 22, 33, 12, 23, 31 +// PlaneStress strain order = 11, 22, 12, 33, 23, 31 +// BeamFiber strain order = 11, 12, 31, 22, 33, 23 +// PlateFiber strain order = 11, 22, 12, 23, 31, 33 +// 0 1 2 3 4 5 + +// Platefiber: 22, 33, 13, and 23 are condensed out. + +// PlateFiberMaterial strain order = 11, 22, 12, 23, 31, 33 + +// +// 0 1 2 3 4 5 +// ND : 11 22 33 12 23 31 +// PS : 11 22 12 33 23 31 +// PF : 11 22 12 23 31 33 | +// BF : 11 12 13 | 22 33 23 +// AS : 11 22 33 12 +// +#include +#include +#include +#include +#include +#include +#include +#include + +extern Tcl_CmdProc TclCommand_addPlaneWrapper; +extern Tcl_CmdProc TclCommand_newJ2Material; +extern Tcl_CmdProc TclCommand_newJ2Simplified; +extern Tcl_CmdProc TclCommand_newPlasticMaterial; +extern Tcl_CmdProc TclCommand_newConcreteMaterial; +extern Tcl_CmdProc TclCommand_newElasticMaterial; +extern Tcl_CmdProc TclCommand_addWrappingMaterial; +extern Tcl_CmdProc TclCommand_newPlateRebar; +extern Tcl_CmdProc TclCommand_newPlateFiber; + +extern OPS_Routine OPS_ElasticOrthotropicPlaneStress; +extern OPS_Routine OPS_OrthotropicMaterial; +extern OPS_Routine OPS_Series3DMaterial; +extern OPS_Routine OPS_Parallel3DMaterial; +extern OPS_Routine OPS_J2PlateFibreMaterial; +extern OPS_Routine OPS_J2CyclicBoundingSurfaceMaterial; +extern OPS_Routine OPS_ASDConcrete3DMaterial; +extern OPS_Routine OPS_ReinforcedConcretePlaneStressMaterial; +extern OPS_Routine OPS_FAReinforcedConcretePlaneStressMaterial; +extern OPS_Routine OPS_FAFourSteelRCPlaneStressMaterial; +extern OPS_Routine OPS_RAFourSteelRCPlaneStressMaterial; +extern OPS_Routine OPS_PrestressedConcretePlaneStressMaterial; +extern OPS_Routine OPS_FAPrestressedConcretePlaneStressMaterial; +extern OPS_Routine OPS_FAFourSteelPCPlaneStressMaterial; +extern OPS_Routine OPS_RAFourSteelPCPlaneStressMaterial; +// extern OPS_Routine OPS_MaterialCMM; +// extern OPS_Routine OPS_NewMaterialCMM; +extern OPS_Routine OPS_NewPlasticDamageConcretePlaneStress; +extern OPS_Routine OPS_ElasticIsotropicMaterial; +extern OPS_Routine OPS_IncrementalElasticIsotropicThreeDimensional; +extern OPS_Routine OPS_ElasticOrthotropicMaterial; +extern OPS_Routine OPS_BoundingCamClayMaterial; +extern OPS_Routine OPS_ContactMaterial2DMaterial; +extern OPS_Routine OPS_ContactMaterial3DMaterial; +extern OPS_Routine OPS_InitialStateAnalysisWrapperMaterial; +extern OPS_Routine OPS_ManzariDafaliasMaterial; +extern OPS_Routine OPS_ManzariDafaliasMaterialRO; +extern OPS_Routine OPS_PM4SandMaterial; +extern OPS_Routine OPS_PM4SiltMaterial; +extern OPS_Routine OPS_LinearElasticGGmaxMaterial; +extern OPS_Routine OPS_CycLiqCPMaterial; +extern OPS_Routine OPS_CycLiqCPSPMaterial; +extern OPS_Routine OPS_InitStressNDMaterial; +extern OPS_Routine OPS_StressDensityMaterial; +extern OPS_Routine OPS_PlaneStressLayeredMaterial; +extern OPS_Routine OPS_LinearCap; +extern OPS_Routine OPS_AcousticMedium; +extern OPS_Routine OPS_UVCmultiaxial; +extern OPS_Routine OPS_UVCplanestress; +extern OPS_Routine OPS_SAniSandMSMaterial; +extern OPS_Routine OPS_OrthotropicRotatingAngleConcreteT2DMaterial01; // M. J. Nunez - UChile +extern OPS_Routine OPS_SmearedSteelDoubleLayerT2DMaterial01; // M. J. Nunez - UChile + +extern OPS_Routine OPS_ElasticIsotropicMaterialThermal; // L.Jiang [SIF] +extern OPS_Routine OPS_DruckerPragerMaterialThermal; // L.Jiang [SIF] +extern OPS_Routine OPS_PlasticDamageConcretePlaneStressThermal; // L.Jiang [SIF] + +extern OPS_Routine OPS_AllASDPlasticMaterials; + +#ifdef _HAVE_Faria1998 +extern OPS_Routine OPS_NewFaria1998Material; +extern OPS_Routine OPS_NewConcreteMaterial; +#endif + +extern OPS_Routine OPS_FSAMMaterial; // K Kolozvari + +#ifdef _HAVE_Damage2p +extern OPS_Routine OPS_Damage2p; +#endif + + +extern "C" +int OPS_ResetInputNoBuilder(ClientData, Tcl_Interp *, int cArg, + int mArg, TCL_Char ** const argv, Domain *); + + +template static int +dispatch(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char** const argv) +{ + BasicModelBuilder *builder = static_cast(clientData); + + OPS_ResetInputNoBuilder(clientData, interp, 2, argc, argv, 0); + + G3_Runtime *rt = G3_getRuntime(interp); + NDMaterial* theMaterial = (NDMaterial*)fn( rt, argc, argv ); + if (theMaterial == nullptr) { + return TCL_ERROR; + } + + if (builder->addTaggedObject(*theMaterial) != TCL_OK) { + opserr << OpenSees::PromptValueError << "Failed to add material to the model builder.\n"; + delete theMaterial; + return TCL_ERROR; + } + return TCL_OK; +} + +template +static int +dispatch(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char** const argv) +{ + assert(clientData != nullptr); + return fn( clientData, interp, argc, argv ); +} + +namespace OpenSees { +static std::unordered_map MaterialLibrary = { +// +// Elastic +// +// Isotropic + {"ElasticIsotropic3D", dispatch}, + {"ElasticIsotropic", dispatch}, + {"ElasticIsotropic3DThermal", dispatch}, +// Orthotropic + {"ElasticOrthotropic", dispatch}, + {"ElasticOrthotropicPlaneStress", dispatch}, +// +// Plasticity +// + {"J2", dispatch}, + {"J2Plasticity", dispatch}, + {"J2N", dispatch}, + {"J2L", dispatch}, + {"J2Thermal", dispatch}, + {"J2PlasticityThermal", dispatch}, + {"J2BeamFiber", dispatch}, + + {"SimplifiedJ2", dispatch}, + {"J2Simplified", dispatch}, + {"Simplified3DJ2", dispatch}, + {"3DJ2", dispatch}, + {"PlaneStressSimplifiedJ2", dispatch}, + {"DruckerPrager", dispatch}, + + {"UVCplanestress", dispatch }, + {"UVCmultiaxial", dispatch }, + {"J2PlateFibre", dispatch}, +// + {"ManzariDafalias", dispatch}, + {"ManzariDafaliasRO", dispatch}, + + + {"DruckerPragerThermal", dispatch }, + {"TruncatedDP", dispatch }, + {"FSAM", dispatch }, + {"AcousticMedium", dispatch }, + {"CycLiqCP", dispatch}, + {"CycLiqCPSP", dispatch}, + {"BoundingCamClay", dispatch}, +// +// Wrapper +// + {"InitStrainMaterial", dispatch}, + {"InitStrain", dispatch}, + {"InitialStrain", dispatch}, + {"InitStressMaterial", dispatch}, + {"OrthotropicMaterial", dispatch}, + {"Series3DMaterial", dispatch}, + {"Parallel3DMaterial", dispatch}, + {"Parallel3D", dispatch}, + // Beam fiber ( 22, 33, and 23 == 0) + {"BeamFiber", dispatch}, + {"BeamFiber2d", dispatch}, + {"BeamFiber2dPS", dispatch}, + // Plane + {"PlaneStressMaterial", dispatch}, + {"PlaneStress", dispatch}, + {"PlaneStrainMaterial", dispatch}, + {"PlaneStrain", dispatch}, + {"PlaneStressRebarMaterial", dispatch}, + // Plate (constrain stress 33 == 13 == 23 == 0) + {"PlateRebarMaterial", dispatch}, + {"PlateRebar", dispatch}, + {"PlateFiberMaterial", dispatch}, + {"PlateFiber", dispatch}, +// +// Other +// + {"ReinforcedConcretePlaneStress", dispatch}, + {"PlaneStressLayeredMaterial", dispatch}, + {"ASDConcrete3D", dispatch}, + {"PlasticDamageConcrete", dispatch}, + {"FariaPlasticDamage", dispatch}, + {"PlasticDamageConcretePlaneStress", dispatch}, +}; + +static std::unordered_map OldMaterialCommands = { +#ifdef OPS_USE_ASDPlasticMaterials + {"ASDPlasticMaterial", OPS_AllASDPlasticMaterials}, +#endif +#ifdef _HAVE_Faria1998 + {"Faria1998", OPS_NewFaria1998Material}, + {"Concrete", OPS_NewConcreteMaterial}, +#endif +#ifdef _HAVE_Damage2p + {"Damage2p", OPS_Damage2p}, +#endif + + {"FAReinforcedConcretePlaneStress", OPS_FAReinforcedConcretePlaneStressMaterial}, + {"RAFourSteelRCPlaneStress", OPS_RAFourSteelRCPlaneStressMaterial}, + {"FAFourSteelRCPlaneStress", OPS_FAFourSteelRCPlaneStressMaterial}, + + + {"PrestressedConcretePlaneStress", OPS_PrestressedConcretePlaneStressMaterial}, + {"FAPrestressedConcretePlaneStress", OPS_FAPrestressedConcretePlaneStressMaterial}, + {"RAFourSteetPCPlaneStress", OPS_RAFourSteelPCPlaneStressMaterial}, + {"FAFourSteelPCPlaneStress", OPS_FAFourSteelPCPlaneStressMaterial}, + +//{"MaterialCMM", OPS_MaterialCMM}, + + {"PM4Sand", OPS_PM4SandMaterial}, + {"J2CyclicBoundingSurface", OPS_J2CyclicBoundingSurfaceMaterial}, + {"PM4Silt", OPS_PM4SiltMaterial}, + {"LinearElasticGGmax", OPS_LinearElasticGGmaxMaterial}, + {"ContactMaterial2D", OPS_ContactMaterial2DMaterial}, + {"ContactMaterial3D", OPS_ContactMaterial3DMaterial}, + {"InitialStateAnalysisWrapper", OPS_InitialStateAnalysisWrapperMaterial}, + {"stressDensity", OPS_StressDensityMaterial}, + {"IncrementalElasticIsotropic3D", OPS_IncrementalElasticIsotropicThreeDimensional}, + {"OrthotropicRAConcrete", OPS_OrthotropicRotatingAngleConcreteT2DMaterial01}, + {"SmearedSteelDoubleLayer", OPS_SmearedSteelDoubleLayerT2DMaterial01}, + {"SAniSandMS", OPS_SAniSandMSMaterial}, +}; +} // namespace OpenSees diff --git a/SRC/runtime/commands/modeling/nDMaterial.cpp b/SRC/runtime/commands/modeling/material/nDMaterial.cpp similarity index 69% rename from SRC/runtime/commands/modeling/nDMaterial.cpp rename to SRC/runtime/commands/modeling/material/nDMaterial.cpp index 3045e8db86..cd81f65a59 100644 --- a/SRC/runtime/commands/modeling/nDMaterial.cpp +++ b/SRC/runtime/commands/modeling/material/nDMaterial.cpp @@ -1,8 +1,10 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// +// https://xara.so +//===----------------------------------------------------------------------===// // // Description: This file contains the function invoked when the user // invokes the nDMaterial command in the interpreter. @@ -17,6 +19,7 @@ // Zaohui Yang (zhyang@ucdavis.edu) // Zhao Cheng (zcheng@ucdavis.edu) // +//===----------------------------------------------------------------------===// #include "material.hpp" #include #include @@ -28,20 +31,15 @@ #include #include // Gang Wang -#include -#include // Antonios Vytiniotis: -#include // start Yuli Huang & Xinzheng Lu -#include #include #include #include // end Yuli Huang & Xinzheng Lu +#include #include // Quan Gu & ZhiJian Qiu 2013 -#include // Quan Gu & ZhiJian Qiu 2013-6-26 -#include // Quan Gu & ZhiJian Qiu 2013-6-26 #include #include @@ -53,20 +51,9 @@ #include #include -#include // added by L.Jiang [SIF] -#include // L.Jiang [SIF] -#include // Liming Jiang [SIF] -#include // Liming Jiang [SIF] #include -#if 0 -extern NDMaterial *Tcl_addWrapperNDMaterial(matObj *, ClientData, Tcl_Interp *, - int, TCL_Char **); -#endif -extern OPS_Routine OPS_J2Plasticity; -extern OPS_Routine OPS_J2BeamFiber2dMaterial; -extern OPS_Routine OPS_J2BeamFiber3dMaterial; #if defined(OPSDEF_Material_FEAP) NDMaterial *TclBasicBuilder_addFeapMaterial(ClientData clientData, @@ -75,9 +62,6 @@ NDMaterial *TclBasicBuilder_addFeapMaterial(ClientData clientData, #endif // _OPS_Material_FEAP -extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, Tcl_Interp *interp, int cArg, - int mArg, TCL_Char ** const argv, Domain *domain); - typedef struct ndMaterialPackageCommand { char *funcName; void *(*funcPtr)(); @@ -86,43 +70,46 @@ typedef struct ndMaterialPackageCommand { static NDMaterialPackageCommand *theNDMaterialPackageCommands = nullptr; + + int TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, - int argc, TCL_Char ** const argv) + Tcl_Size argc, TCL_Char ** const argv) { - G3_Runtime *rt = G3_getRuntime(interp); BasicModelBuilder *builder = static_cast(clientData); - // Make sure there is a minimum number of arguments - if (argc < 3) { - opserr << "WARNING insufficient number of ND material arguments\n"; - opserr << "Want: nDMaterial type? tag? " << "\n"; + + if (argc < 2) { + opserr << OpenSees::PromptValueError + << "missing argument type" + << "\n"; return TCL_ERROR; } + + { + auto tcl_cmd = OpenSees::MaterialLibrary.find(std::string(argv[1])); + if (tcl_cmd != OpenSees::MaterialLibrary.end()) { + return (*tcl_cmd->second)(clientData, interp, argc, &argv[0]); + } + } + + G3_Runtime *rt = G3_getRuntime(interp); OPS_ResetInputNoBuilder(clientData, interp, 2, argc, argv, 0); // Pointer to an ND material that will be added to the model builder NDMaterial *theMaterial = nullptr; - auto tcl_cmd = material_dispatch.find(std::string(argv[1])); - if (tcl_cmd != material_dispatch.end()) { - void* theMat = (*tcl_cmd->second)(rt, argc, &argv[0]); - if (theMat != 0) - theMaterial = (NDMaterial *)theMat; - else - return TCL_ERROR; + if (argc < 3) { + opserr << OpenSees::PromptValueError + << "missing argument tag" + << "\n"; + return TCL_ERROR; } - - // Check argv[1] for ND material type - else if (strcmp(argv[1], "J2BeamFiber") == 0) { - void *theMat = 0; - if (builder->getNDM() == 2) - theMat = OPS_J2BeamFiber2dMaterial(rt, argc, argv); - else - theMat = OPS_J2BeamFiber3dMaterial(rt, argc, argv); - - if (theMat != 0) + auto tcl_cmd = OpenSees::OldMaterialCommands.find(std::string(argv[1])); + if (tcl_cmd != OpenSees::OldMaterialCommands.end()) { + void* theMat = (*tcl_cmd->second)(rt, argc, &argv[0]); + if (theMat != nullptr) theMaterial = (NDMaterial *)theMat; else return TCL_ERROR; @@ -136,7 +123,7 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, return TCL_ERROR; } - int tag = 0; + int tag = 0; double E = 0.0; double v = 0.0; double rho = 0.0; @@ -151,164 +138,67 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { opserr << "WARNING invalid E\n"; - opserr << "nDMaterial PressureDependentElastic3D: E" << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &v) != TCL_OK) { opserr << "WARNING invalid v\n"; - opserr << "nDMaterial PressureDependentElastic3D: v" << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &rho) != TCL_OK) { - opserr << "WARNING invalid v\n"; - opserr << "nDMaterial PressureDependentElastic3D: rho" << tag << "\n"; + opserr << "WARNING invalid rho\n"; return TCL_ERROR; } - ////////////////////////////////////////////////////////////////////////////////// if (argc == 6) { theMaterial = new PressureDependentElastic3D(tag, E, v, rho); - // opserr << "nDMaterial PressureDependentElastic3D: expp =" << expp << - // "\n"; } - ////////////////////////////////////////////////////////////////////////////////// + else if (argc == 7) { // get the exponent of the pressure sensitive elastic material) if (Tcl_GetDouble(interp, argv[6], &expp) != TCL_OK) { - opserr << "WARNING invalid v\n"; - opserr << "nDMaterial PressureDependentElastic3D: " << tag << "\n"; + opserr << "WARNING invalid expp\n"; return TCL_ERROR; } theMaterial = new PressureDependentElastic3D(tag, E, v, rho, expp); - // opserr << "nDMaterial PressureDependentElastic3D: expp =" << expp << - // "\n"; } - ////////////////////////////////////////////////////////////////////////////////// + else if (argc == 8) { // get the exponent pressure of the pressure sensitive elastic material) if (Tcl_GetDouble(interp, argv[6], &expp) != TCL_OK) { - opserr << "WARNING invalid v\n"; - opserr << "nDMaterial PressureDependentElastic3D: expp" << tag << "\n"; + opserr << "WARNING invalid expp\n"; return TCL_ERROR; } // get the reference pressure of the pressure sensitive elastic material) if (Tcl_GetDouble(interp, argv[7], &prp) != TCL_OK) { - opserr << "WARNING invalid v\n"; - opserr << "nDMaterial PressureDependentElastic3D: prp " << tag << "\n"; + opserr << "WARNING invalid prp\n"; return TCL_ERROR; } - // opserr << "nDMaterial ElasticIsotropic3D: prp =" << prp << "\n"; theMaterial = new PressureDependentElastic3D(tag, E, v, rho, expp, prp); } - ////////////////////////////////////////////////////////////////////////////////// + else if (argc >= 9) { // get the exponent of the pressure sensitive elastic material) if (Tcl_GetDouble(interp, argv[6], &expp) != TCL_OK) { - opserr << "WARNING invalid v\n"; - opserr << "nDMaterial PressureDependentElastic3D: expp" << tag << "\n"; + opserr << "WARNING invalid expp\n"; return TCL_ERROR; } // get the reference pressure of the pressure sensitive elastic material) if (Tcl_GetDouble(interp, argv[7], &prp) != TCL_OK) { - opserr << "WARNING invalid v\n"; - opserr << "nDMaterial PressureDependentElastic3D: prp" << tag << "\n"; + opserr << "WARNING invalid prp\n"; return TCL_ERROR; } // get the cutoff pressure po of the pressure sensitive elastic material) if (Tcl_GetDouble(interp, argv[8], &pop) != TCL_OK) { - opserr << "WARNING invalid v\n"; - opserr << "nDMaterial PressureDependentElastic3D: pop" << tag << "\n"; + opserr << "WARNING invalid pop\n"; return TCL_ERROR; } - // opserr << "nDMaterial PressureDependentElastic3D: pop =" << pop << - // "\n"; theMaterial = new PressureDependentElastic3D(tag, E, v, rho, expp, prp, pop); } - } - // Check argv[1] for J2PlaneStrain material type - else if ((strcmp(argv[1], "J2Plasticity") == 0) || - (strcmp(argv[1], "J2") == 0)) { - - void *theMat = OPS_J2Plasticity(rt, argc, argv); - if (theMat != 0) - theMaterial = (NDMaterial *)theMat; - else - return TCL_ERROR; - - } - - ///////////////////////////////////////////////////////////////// - /* - nDmaterial PlaneStressJ2 $matTag $G $K $sig0 $H_kin $H_iso - - - PlaneStress (int tag, - int nd, - NDMaterial &the3DMaterial); - - */ - - else if ((strcmp(argv[1], "PlaneStressSimplifiedJ2") == 0)) { - if (argc < 8) { - opserr << "WARNING insufficient arguments\n"; - opserr << "Want: nDmaterial Simplified3DJ2 $matTag $G $K $sig0 " - "$H_kin $H_iso" - << "\n"; - return TCL_ERROR; - } - - int tag; - double K, G, sig0, H_kin, H_iso; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid SimplifiedJ2 tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[3], &G) != TCL_OK) { - opserr << "WARNING invalid G\n"; - opserr << "nDMaterial SimplifiedJ2: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[4], &K) != TCL_OK) { - opserr << "WARNING invalid K\n"; - opserr << "nDMaterial SimplifiedJ2: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[5], &sig0) != TCL_OK) { - opserr << "WARNING invalid sig0\n"; - opserr << "nDMaterial SimplifiedJ2: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[6], &H_kin) != TCL_OK) { - opserr << "WARNING invalid H_kin\n"; - opserr << "nDMaterial SimplifiedJ2: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[7], &H_iso) != TCL_OK) { - opserr << "WARNING invalid H_iso\n"; - opserr << "nDMaterial SimplifiedJ2: " << tag << "\n"; - return TCL_ERROR; - } - - NDMaterial *theMaterial2 = - new SimplifiedJ2(tag, 3, G, K, sig0, H_kin, H_iso); - - theMaterial = new PlaneStressSimplifiedJ2(tag, 2, *theMaterial2); - - // delete theMaterial2; - - } - ///////////////////////////////////////////////////////////////// // // MultiAxialCyclicPlasticity Model by Gang Wang @@ -337,60 +227,50 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, if (Tcl_GetDouble(interp, argv[3], &rho) != TCL_OK) { opserr << "WARNING invalid rho\n"; - opserr << "nDMaterial MultiaxialCyclicPlasticity: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &K) != TCL_OK) { opserr << "WARNING invalid K\n"; - opserr << "nDMaterial MultiaxialCyclicPlasticity: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &G) != TCL_OK) { opserr << "WARNING invalid G\n"; - opserr << "nDMaterial MultiaxialCyclicPlasticity: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6], &Su) != TCL_OK) { opserr << "WARNING invalid alpha1\n"; - opserr << "nDMaterial MultiaxialCyclicPlasticity: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[7], &Ho) != TCL_OK) { opserr << "WARNING invalid Ho\n"; - opserr << "nDMaterial MultiaxialCyclicPlasticity: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8], &h) != TCL_OK) { opserr << "WARNING invalid h\n"; - opserr << "nDMaterial MultiaxialCyclicPlasticity: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9], &m) != TCL_OK) { opserr << "WARNING invalid m\n"; - opserr << "nDMaterial MultiaxialCyclicPlasticity: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[10], &beta) != TCL_OK) { opserr << "WARNING invalid beta\n"; - opserr << "nDMaterial MultiaxialCyclicPlasticity: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[11], &Kcoeff) != TCL_OK) { opserr << "WARNING invalid Kcoeff\n"; - opserr << "nDMaterial MultiaxialCyclicPlasticity: " << tag << "\n"; return TCL_ERROR; } if (argc > 12 && Tcl_GetDouble(interp, argv[12], &eta) != TCL_OK) { opserr << "WARNING invalid eta\n"; - opserr << "nDMaterial MultiaxialCyclicPlasticity: " << tag << "\n"; return TCL_ERROR; } @@ -842,7 +722,6 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, for (int i = 3; (i < argc && i < in); ++i) if (Tcl_GetDouble(interp, argv[i], ¶m[i - 3]) != TCL_OK) { opserr << "WARNING invalid " << arg[i - 3] << "\n"; - opserr << "nDMaterial PressureDependMultiYield03: " << tag << "\n"; return TCL_ERROR; } @@ -856,7 +735,6 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, for (int i = 0; i < 2 * param[numParam]; ++i) if (Tcl_GetDouble(interp, argv[i + in], &gredu[i]) != TCL_OK) { opserr << "WARNING invalid " << arg[i - 3] << "\n"; - opserr << "nDMaterial PressureDependMultiYield03: " << tag << "\n"; return TCL_ERROR; } } @@ -939,63 +817,6 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, new FluidSolidPorousMaterial(tag, param[0], *soil, param[2], param[3]); } - else if (strcmp(argv[1], "PlaneStressMaterial") == 0 || - strcmp(argv[1], "PlaneStress") == 0) { - if (argc < 4) { - opserr << "WARNING insufficient arguments\n"; - opserr << "Want: nDMaterial PlaneStress tag? matTag?" << "\n"; - return TCL_ERROR; - } - - int tag, matTag; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid nDMaterial PlaneStress tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { - opserr << "WARNING invalid matTag" << "\n"; - opserr << "PlaneStress: " << matTag << "\n"; - return TCL_ERROR; - } - - NDMaterial *threeDMaterial = builder->getTypedObject(matTag); - if (threeDMaterial == nullptr) - return TCL_ERROR; - - theMaterial = new PlaneStressMaterial(tag, *threeDMaterial); - } - - // PlaneStrainMaterial - else if (strcmp(argv[1], "PlaneStrainMaterial") == 0 || - strcmp(argv[1], "PlaneStrain") == 0) { - if (argc < 4) { - opserr << "WARNING insufficient arguments\n"; - opserr << "Want: nDMaterial PlaneStrain tag? matTag?" << "\n"; - return TCL_ERROR; - } - - int tag, matTag; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid nDMaterial PlaneStrain tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { - opserr << "WARNING invalid matTag" << "\n"; - opserr << "PlaneStrain: " << matTag << "\n"; - return TCL_ERROR; - } - - NDMaterial *threeDMaterial = builder->getTypedObject(matTag); - if (threeDMaterial == nullptr) - return TCL_ERROR; - - theMaterial = new PlaneStrainMaterial(tag, *threeDMaterial); - } - // ----- Cap plasticity model ------ // Quan Gu & ZhiJian Qiu 2013 // format nDmaterial CapPlasticity $tag $ndm $rho $G $K $X $D $W $R $lambda @@ -1094,116 +915,13 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, opserr << "WARNING invalid CapPlasticity tol" << "\n"; return TCL_ERROR; } - - } // end if + } theMaterial = new CapPlasticity(tag, G, K, rho, X, D, W, R, lambda, theta, beta, alpha, T, ndm, tol); } - ///////////////////////////////////////////////////////////////// - /* - nDmaterial Simplified3DJ2 $matTag $G $K $sig0 $H_kin $H_iso - - - SimplifiedJ2 (int tag, - int nd, - double G, - double K, - double sigmaY0, - double H_kin, - double H_iso); - - */ - - // Check argv[1] for J2PlaneStrain material type - else if ((strcmp(argv[1], "Simplified3DJ2") == 0) || - (strcmp(argv[1], "3DJ2") == 0)) { - if (argc < 8) { - opserr << "WARNING insufficient arguments\n"; - opserr << "Want: nDmaterial Simplified3DJ2 $matTag $G $K $sig0 " - "$H_kin $H_iso" - << "\n"; - return TCL_ERROR; - } - - int tag; - double K, G, sig0, H_kin, H_iso; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid SimplifiedJ2 tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[3], &G) != TCL_OK) { - opserr << "WARNING invalid G\n"; - opserr << "nDMaterial SimplifiedJ2: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[4], &K) != TCL_OK) { - opserr << "WARNING invalid K\n"; - opserr << "nDMaterial SimplifiedJ2: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[5], &sig0) != TCL_OK) { - opserr << "WARNING invalid sig0\n"; - opserr << "nDMaterial SimplifiedJ2: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[6], &H_kin) != TCL_OK) { - opserr << "WARNING invalid H_kin\n"; - opserr << "nDMaterial SimplifiedJ2: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[7], &H_iso) != TCL_OK) { - opserr << "WARNING invalid H_iso\n"; - opserr << "nDMaterial SimplifiedJ2: " << tag << "\n"; - return TCL_ERROR; - } - - theMaterial = new SimplifiedJ2(tag, 3, G, K, sig0, H_kin, H_iso); - } - - else if (strcmp(argv[1], "PlateRebarMaterial") == 0 || - strcmp(argv[1], "PlateRebar") == 0) { - if (argc < 5) { - opserr << "WARNING insufficient arguments\n"; - opserr << "Want: nDMaterial PlateRebar tag? matTag? angle?" << "\n"; - return TCL_ERROR; - } - - int tag, matTag; - double angle; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid nDMaterial PlateRebar tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { - opserr << "WARNING invalid matTag" << "\n"; - opserr << "PlateRebar: " << tag << "\n"; - return TCL_ERROR; - } - - UniaxialMaterial *theMat = builder->getTypedObject(matTag); - if (theMat == nullptr) - return TCL_ERROR; - - if (Tcl_GetDouble(interp, argv[4], &angle) != TCL_OK) { - opserr << "WARNING invalid angle" << "\n"; - opserr << "PlateRebar: " << tag << "\n"; - return TCL_ERROR; - } - - theMaterial = new PlateRebarMaterial(tag, *theMat, angle); - } - // start Yuli Huang & Xinzheng Lu PlateFromPlaneStressMaterial else if (strcmp(argv[1], "PlateFromPlaneStressMaterial") == 0 || strcmp(argv[1], "PlateFromPlaneStress") == 0) { @@ -1372,51 +1090,41 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, if (Tcl_GetDouble(interp, argv[3], &fcu) != TCL_OK) { opserr << "WARNING invalid fcu\n"; - opserr << "nDMaterial ConcreteMcftNonLinearNonLinear5: fcu" << tag - << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &ecu) != TCL_OK) { opserr << "WARNING invalid ecu\n"; - opserr << "nDMaterial ConcreteMcftNonLinearNonLinear5: ecu" << tag - << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &Ec) != TCL_OK) { opserr << "WARNING invalid Ec\n"; - opserr << "nDMaterial ConcreteMcftNonlinear7: Ec" << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6], &fcr) != TCL_OK) { opserr << "WARNING invalid fcr\n"; - opserr << "nDMaterial ConcreteMcftNonlinear7: fcr" << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[7], &Esv) != TCL_OK) { opserr << "WARNING invalid Esv\n"; - opserr << "nDMaterial ConcreteMcftNonlinear7: Esv" << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8], &fyv) != TCL_OK) { opserr << "WARNING invalid fyv\n"; - opserr << "nDMaterial ConcreteMcftNonlinear7: fyv" << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9], &alphaV) != TCL_OK) { opserr << "WARNING invalid alphaV\n"; - opserr << "nDMaterial ConcreteMcftNonlinear7: alphaV" << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[10], &RoV) != TCL_OK) { opserr << "WARNING invalid RoV\n"; - opserr << "nDMaterial ConcreteMcftNonlinear7: RoV" << tag << "\n"; return TCL_ERROR; } @@ -1463,138 +1171,12 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, if (Tcl_GetDouble(interp, argv[4], &gmod) != TCL_OK) { opserr << "WARNING invalid gmod" << "\n"; - opserr << "PlateFromPlaneStress: " << tag << "\n"; return TCL_ERROR; } theMaterial = new PlateFromPlaneStressMaterialThermal(tag, *theMat, gmod); - } else if (strcmp(argv[1], "PlateRebarMaterialThermal") == 0 || - strcmp(argv[1], "PlateRebarThermal") == 0) { - if (argc < 5) { - opserr << "WARNING insufficient arguments\n"; - opserr << "Want: nDMaterial PlateRebar tag? matTag? angle?" << "\n"; - return TCL_ERROR; - } - - int tag, matTag; - double angle; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid nDMaterial PlateRebar tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { - opserr << "WARNING invalid matTag" << "\n"; - opserr << "PlateRebar: " << tag << "\n"; - return TCL_ERROR; - } - - UniaxialMaterial *theMat = builder->getTypedObject(matTag); - if (theMat == nullptr) - return TCL_ERROR; - - - if (Tcl_GetDouble(interp, argv[4], &angle) != TCL_OK) { - opserr << "WARNING invalid angle" << "\n"; - opserr << "PlateRebar: " << tag << "\n"; - return TCL_ERROR; - } - - theMaterial = new PlateRebarMaterialThermal(tag, *theMat, angle); -// - } else if ((strcmp(argv[1], "J2PlasticityThermal") == 0) || - (strcmp(argv[1], "J2Thermal") == 0)) { - if (argc < 9) { - opserr << "WARNING insufficient arguments\n"; - opserr << "Want: nDMaterial J2PlasticityThermal tag? K? G? sig0? sigInf? " - "delta? H? " - << "\n"; - return TCL_ERROR; - } - - int tag; - double K, G, sig0, sigInf, delta, H; - double eta = 0.0; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid J2PlasticityThermal tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[3], &K) != TCL_OK) { - opserr << "WARNING invalid K\n"; - opserr << "nDMaterial J2PlasticityThermal: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[4], &G) != TCL_OK) { - opserr << "WARNING invalid G\n"; - opserr << "nDMaterial J2PlasticityThermal: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[5], &sig0) != TCL_OK) { - opserr << "WARNING invalid sig0\n"; - opserr << "nDMaterial J2PlasticityThermal: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[6], &sigInf) != TCL_OK) { - opserr << "WARNING invalid sigInf\n"; - opserr << "nDMaterial J2PlasticityThermal: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[7], &delta) != TCL_OK) { - opserr << "WARNING invalid delta\n"; - opserr << "nDMaterial J2PlasticityThermal: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[8], &H) != TCL_OK) { - opserr << "WARNING invalid H\n"; - opserr << "nDMaterial J2PlasticityThermal: " << tag << "\n"; - return TCL_ERROR; - } - if (argc > 9 && Tcl_GetDouble(interp, argv[9], &eta) != TCL_OK) { - opserr << "WARNING invalid eta\n"; - opserr << "nDMaterial J2PlasticityThermal: " << tag << "\n"; - return TCL_ERROR; - } - - theMaterial = - new J2PlasticityThermal(tag, 0, K, G, sig0, sigInf, delta, H, eta); - - } else if (strcmp(argv[1], "PlateFiberMaterialThermal") == 0 || - strcmp(argv[1], "PlateFiberThermal") == 0) { - if (argc < 4) { - opserr << "WARNING insufficient arguments\n"; - opserr << "Want: nDMaterial PlateFiberThermal tag? matTag?" << "\n"; - return TCL_ERROR; - } - - int tag, matTag; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid nDMaterial PlateFiberThermal tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { - opserr << "WARNING invalid matTag" << "\n"; - opserr << "PlateFiberThermal: " << matTag << "\n"; - return TCL_ERROR; - } - - NDMaterial *threeDMaterial = builder->getTypedObject(matTag); - if (threeDMaterial == nullptr) - return TCL_ERROR; - - theMaterial = new PlateFiberMaterialThermal(tag, *threeDMaterial); } - //--------End of adding PlateFiberMaterialThermal - // end of adding thermo-mechanical nd materials-L.Jiang[SIF] #if defined(OPSDEF_Material_FEAP) else { @@ -1626,33 +1208,12 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, // the proc may already have been loaded from a package or may exist in a // package yet to be loaded // - if (theMaterial == nullptr) { -#if 0 - // maybe material in a routine - // - - char *matType = new char[strlen(argv[1]) + 1]; - strcpy(matType, argv[1]); - matObj *matObject = OPS_GetMaterialType(matType, strlen(matType)); - - delete[] matType; - - if (matObject != 0) { - - theMaterial = Tcl_addWrapperNDMaterial(matObject, clientData, interp, - argc, argv); - - if (theMaterial == 0) - delete matObject; - } -#endif - } // // maybe material class exists in a package yet to be loaded // - if (theMaterial == 0) { + if (theMaterial == nullptr) { void *libHandle; void *(*funcPtr)(); @@ -1683,7 +1244,7 @@ TclCommand_addNDMaterial(ClientData clientData, Tcl_Interp *interp, } if (theMaterial == nullptr) { - opserr << "WARNING could not create nDMaterial: " << argv[1]; + opserr << "WARNING could not create nDMaterial " << argv[1]; return TCL_ERROR; } diff --git a/SRC/runtime/commands/modeling/material/plastic.cpp b/SRC/runtime/commands/modeling/material/plastic.cpp new file mode 100644 index 0000000000..da5574c931 --- /dev/null +++ b/SRC/runtime/commands/modeling/material/plastic.cpp @@ -0,0 +1,873 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Description: This file implements a unified parser for plasticity materials. +// +// Written: cmp +// April 2025 +// +#include +#include +#include +#include +#include +#include +#include + +#include "isotropy.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +template +static inline int +TclCommand_newPlasticParser(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + + assert(clientData != nullptr); + + ArgumentTracker tracker; + std::set positional; + + + // Count the number of required isotropic parameters. + // This is needed to accommodate uniaxial materials, which generally + // only require one isotropic parameter (ie, E). + int niso = ( + (Position::E < Position::EndRequired) + + (Position::G < Position::EndRequired) + + (Position::Nu < Position::EndRequired) + + (Position::K < Position::EndRequired) + + (Position::Lambda < Position::EndRequired) + ); + + // + // Values we're parsing for + // + int tag; + double density = 0.0; + // Isotropy + IsotropicConstants consts {}; + // Plasticity + double Fy, Fsat = 0, Fo = 0; + // Hardening + double Hiso=0, + Hkin=0; + struct { + double theta = 1.0; + double Hsat = 0; + double Hmix = 0; + } hard{}; + bool mix = Position::Theta < Position::End; + // Viscosity + double eta=0; + // Drucker-Prager + double rho = 0, rho_bar = 0; + double atm = 101.0; + double delta2 = 0.0; + + // + // 1. Keyword arguments + // + + // Isotropy + IsotropicParse iso {consts, niso}; + if (TclCommand_setIsotropicParameters((ClientData)&iso, interp, argc, argv) == TCL_OK) { + tracker.consume(Position::E); + tracker.consume(Position::G); + tracker.consume(Position::Nu); + tracker.consume(Position::K); + tracker.consume(Position::Lambda); + } + + // Other arguments + for (int i=2; i= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &density) != TCL_OK) { + opserr << "Invalid density value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + } + // Yielding + else if (strcmp(argv[i], "-Fy") == 0 || + strcmp(argv[i], "-fy") == 0 || + strcmp(argv[i], "-yield-stress") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Fy) != TCL_OK) { + opserr << "Invalid yield stress value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::YieldStress); + } + else if ((strcmp(argv[i], "-Fo") == 0) || + (strcmp(argv[i], "-Ko") == 0)) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Fo) != TCL_OK) { + opserr << "Invalid initial saturation stress value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::SatStress0); + } + else if ((strcmp(argv[i], "-Fs") == 0) || + (strcmp(argv[i], "-Fsat") == 0) || + (strcmp(argv[i], "-fsat") == 0)) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Fsat) != TCL_OK) { + opserr << "Invalid saturation stress value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::SatStress); + } + // + // Hardening + // + else if (strcmp(argv[i], "-Hiso") == 0 || strcmp(argv[i], "-isotropic-hardening") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Hiso) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + mix = false; + tracker.consume(Position::Hiso); + } + else if (strcmp(argv[i], "-Hkin") == 0 || strcmp(argv[i], "-kinematic-hardening") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &Hkin) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + mix = false; + tracker.consume(Position::Hkin); + } + else if (strcmp(argv[i], "-H") == 0 || strcmp(argv[i], "-Hmix") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &hard.Hmix) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + mix = true; + tracker.consume(Position::Hmix); + tracker.consume(Position::Hiso); + tracker.consume(Position::Hkin); + } + + else if (strcmp(argv[i], "-theta") == 0 || strcmp(argv[i], "-mix") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &hard.theta) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Theta); + } + else if (strcmp(argv[i], "-Hsat") == 0 || + strcmp(argv[i], "-delta") == 0 || + strcmp(argv[i], "-delta1") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &hard.Hsat) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Hsat); + } + // Drucker-Prager + else if (strcmp(argv[i], "-delta2") == 0 || + strcmp(argv[i], "-Hten") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &delta2) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Delta2); + } + else if (strcmp(argv[i], "-atm") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &atm) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Atm); + } + else if (strcmp(argv[i], "-Rvol") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &rho) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Rho); + } + else if (strcmp(argv[i], "-Rbar") == 0 || + strcmp(argv[i], "-rhoBar") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &rho_bar) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::RhoBar); + } + // Viscosity + else if (strcmp(argv[i], "-eta") == 0 || strcmp(argv[i], "-viscosity") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &eta) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Position::Eta); + } + else + positional.insert(i); + } + + // + // 2) Positional arguments + // + for (int i : positional) { + + if (tracker.current() == Position::EndRequired) + tracker.increment(); + + switch (tracker.current()) { + // General + case Position::Tag : + if (Tcl_GetInt(interp, argv[i], &tag) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid section Elastic tag.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Density: + if (Tcl_GetDouble (interp, argv[i], &density) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid density.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + // Isotropy + case Position::E: + if (Tcl_GetDouble (interp, argv[i], &consts.E) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid E.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::G: + if (Tcl_GetDouble (interp, argv[i], &consts.G) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid G.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::K: + if (Tcl_GetDouble (interp, argv[i], &consts.K) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid K.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::Nu: + if (Tcl_GetDouble (interp, argv[i], &consts.nu) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid nu.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::Lambda: + if (Tcl_GetDouble (interp, argv[i], &consts.lambda) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Lame lambda.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + // Yielding + case Position::YieldStress: + if (Tcl_GetDouble(interp, argv[i], &Fy) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid yield stress.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::SatStress: + if (Tcl_GetDouble (interp, argv[i], &Fsat) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid saturation stress.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::SatStress0: + if (Tcl_GetDouble (interp, argv[i], &Fo) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid initial saturation stress.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + // Hardening + case Position::Hiso: + if (Tcl_GetDouble (interp, argv[i], &Hiso) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Hiso.\n"; + return TCL_ERROR; + } else { + tracker.consume(Position::Hiso); + tracker.consume(Position::Theta); + break; + } + case Position::Hkin: + if (Tcl_GetDouble (interp, argv[i], &Hkin) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Hkin.\n"; + return TCL_ERROR; + } else { + tracker.consume(Position::Hkin); + tracker.consume(Position::Theta); + break; + } + case Position::Hsat: + if (Tcl_GetDouble (interp, argv[i], &hard.Hsat) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Hsat.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Hmix: + if (Tcl_GetDouble (interp, argv[i], &hard.Hmix) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Hmix.\n"; + return TCL_ERROR; + } else { + mix = true; + tracker.consume(Position::Hmix); + tracker.consume(Position::Hiso); + tracker.consume(Position::Hkin); + break; + } + case Position::Theta: + if (Tcl_GetDouble (interp, argv[i], &hard.theta) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid hardening theta.\n"; + return TCL_ERROR; + } else { + tracker.consume(Position::Theta); + break; + } + + // Drucker + case Position::Delta2: + if (Tcl_GetDouble (interp, argv[i], &delta2) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid delta2.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Rho: + if (Tcl_GetDouble (interp, argv[i], &rho) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Rvol.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::Atm: + if (Tcl_GetDouble (interp, argv[i], &atm) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid atm.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + case Position::RhoBar: + if (Tcl_GetDouble (interp, argv[i], &rho_bar) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid Rbar.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + // Viscosity + case Position::Eta: + if (Tcl_GetDouble (interp, argv[i], &eta) != TCL_OK) { + opserr << OpenSees::PromptParseError << "invalid eta.\n"; + return TCL_ERROR; + } else { + tracker.increment(); + break; + } + + case Position::EndRequired: + // This will not be reached + break; + + case Position::End: + opserr << OpenSees::PromptParseError << "unexpected argument " << argv[i] << ".\n"; + return TCL_ERROR; + } + } + + if (mix) { + Hiso = hard.theta * hard.Hmix; + Hkin = (1.0 - hard.theta) * hard.Hmix; + } + + // + // 3. Check for required arguments + // + if (tracker.current() < Position::EndRequired) { + opserr << OpenSees::PromptParseError + << "missing required arguments: "; + while (tracker.current() != Position::EndRequired) { + switch (tracker.current()) { + case Position::Tag : + opserr << "tag "; + break; + // Isotropy + case Position::E: + opserr << "E "; + break; + case Position::G: + opserr << "G "; + break; + case Position::K: + opserr << "K "; + break; + case Position::Nu: + opserr << "nu "; + break; + case Position::Lambda: + opserr << "lambda "; + break; + // Yielding + case Position::YieldStress: + opserr << "Fy "; + break; + case Position::SatStress: + opserr << "Fsat "; + break; + case Position::SatStress0: + opserr << "Fo "; + break; + // Hardening + case Position::Hiso: + opserr << "Hiso "; + break; + case Position::Hkin: + opserr << "Hkin "; + break; + case Position::Hmix: + opserr << "Hmix "; + break; + case Position::Theta: + opserr << "theta "; + break; + + // Drucker-Prager + case Position::Delta2: + opserr << "Hten "; + break; + case Position::Rho: + opserr << "Rvol "; + break; + case Position::RhoBar: + opserr << "Rbar "; + break; + + // Viscosity + case Position::Eta: + opserr << "eta "; + break; + + case Position::EndRequired: + case Position::End: + default: + break; + } + + if (tracker.current() == Position::EndRequired) + break; + + tracker.consume(tracker.current()); + } + + opserr << "\n"; + + return TCL_ERROR; + } + + // + // Create the material (TODO) + // + BasicModelBuilder *builder = static_cast(clientData); + if ((strcmp(argv[1], "Hardening") == 0) || + (strcmp(argv[1], "Steel") == 0)) { + + UniaxialMaterial* theMaterial = new HardeningMaterial(tag, consts.E, Fy, Hiso, Hkin, eta); + if (builder->addTaggedObject(*theMaterial) != TCL_OK ) { + delete theMaterial; + return TCL_ERROR; + } + return TCL_OK; + } + + else if (strcmp(argv[1], "J2BeamFiber") == 0) { + NDMaterial* theMaterial = nullptr; + if (builder->getNDM() == 2) + theMaterial = new J2BeamFiber2d(tag, consts.E, consts.G, Fy, Hkin, Hiso); + else + theMaterial = new J2BeamFiber3d(tag, consts.E, consts.G, Fy, Hkin, Hiso); + + if (builder->addTaggedObject(*theMaterial) != TCL_OK ) { + delete theMaterial; + return TCL_ERROR; + } + return TCL_OK; + } + + else if ((strcmp(argv[1], "Simplified3DJ2") == 0) || + (strcmp(argv[1], "SimplifiedJ2") == 0) || + (strcmp(argv[1], "J2Simplified") == 0) || + (strcmp(argv[1], "J2L") == 0) || + (strcmp(argv[1], "PlaneStressSimplifiedJ2") == 0) || + (strcmp(argv[1], "3DJ2") == 0)) { + + NDMaterial* theMaterial = new SimplifiedJ2(tag, 3, consts.G, consts.K, Fy, Hkin, Hiso, density); + if (strcmp(argv[1], "PlaneStressSimplifiedJ2") == 0) { + theMaterial = new PlaneStressSimplifiedJ2(tag, 2, *theMaterial); + } + if (builder->addTaggedObject(*theMaterial) != TCL_OK ) { + delete theMaterial; + return TCL_ERROR; + } + return TCL_OK; + } + + else if ((strcmp(argv[1], "J2") == 0) || + (strcmp(argv[1], "J2N") == 0) || + (strcmp(argv[1], "J2Plasticity") == 0)) { + + NDMaterial* theMaterial = new J2Plasticity(tag, 0, consts.K, consts.G, + Fy, Fsat, hard.Hsat, Hiso, eta, density); + if (builder->addTaggedObject(*theMaterial) != TCL_OK ) { + delete theMaterial; + return TCL_ERROR; + } + return TCL_OK; + } + + else if ((strcmp(argv[1], "J2PlasticityThermal") == 0) || + (strcmp(argv[1], "J2Thermal") == 0)) { + NDMaterial* theMaterial = new J2PlasticityThermal(tag, 0, consts.K, consts.G, + Fy, Fsat, hard.Hsat, Hiso, eta, density); + if (builder->addTaggedObject(*theMaterial) != TCL_OK ) { + delete theMaterial; + return TCL_ERROR; + } + return TCL_OK; + } + else if (strcmp(argv[1], "DruckerPrager") == 0 || + strcmp(argv[1], "DP") == 0) { + + NDMaterial* theMaterial = new DruckerPrager(tag, 0, consts.K, consts.G, + Fy, rho, rho_bar, Fsat, Fo, + hard.Hsat, delta2, hard.Hmix, hard.theta, density, atm); + if (builder->addTaggedObject(*theMaterial) != TCL_OK ) { + delete theMaterial; + return TCL_ERROR; + } + return TCL_OK; + } + return TCL_ERROR; +} + + +int +TclCommand_newPlasticMaterial(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + // + if (strcmp(argv[1], "Simplified3DJ2") == 0 || + strcmp(argv[1], "SimplifiedJ2") == 0 || + strcmp(argv[1], "J2Simplified") == 0 || + strcmp(argv[1], "J2L") == 0 || + strcmp(argv[1], "3DJ2") == 0 || + strcmp(argv[1], "PlaneStressSimplifiedJ2") == 0) { + + // "SimplifiedJ2" tag? G? K? Fy? Hkin? Hiso? + enum class Position : int { + Tag, G, K, YieldStress, EndRequired, + Hkin, Hiso, + End, + E, Nu, Lambda, Eta, Theta, Hmix, Hsat, + SatStress, SatStress0, + Delta2, Rho, RhoBar, Atm, + Density + }; + return TclCommand_newPlasticParser(clientData, interp, argc, argv); + } + else if (strcmp(argv[1], "J2BeamFiber") == 0) { + // J2BeamFiber $tag $E $v $sigmaY $Hiso $Hkin <$rho> + enum class Position : int { + Tag, E, G, YieldStress, EndRequired, + Hkin, Hiso, + Density, + End, + Nu, K, Eta, Lambda, Theta, Hmix, Hsat, + SatStress, SatStress0, + Delta2, Rho, RhoBar, Atm + }; + return TclCommand_newPlasticParser(clientData, interp, argc, argv); + } + + // "UniaxialJ2Plasticity" tag? E? sigmaY? Hkin? + else if (strcmp(argv[1], "UniaxialJ2Plasticity") == 0) { + } + + else if (strcmp(argv[1], "HardeningMaterial") == 0 || + strcmp(argv[1], "Hardening") == 0 || + strcmp(argv[1], "Hardening2") == 0 || + strcmp(argv[1], "Steel") == 0) { + + // "Hardening" tag? E? Y? Hiso? Hkin? + enum class Position : int { + Tag, E, YieldStress, Hiso, EndRequired, + Hkin, + End, + // Keyword-only arguments + Density, + // Unused + Eta, G, K, Nu, Lambda, Theta, Hmix, Hsat, + SatStress, SatStress0, + Delta2, Rho, RhoBar, Atm, + }; + return TclCommand_newPlasticParser(clientData, interp, argc, argv); + } + + else if (strcmp(argv[1], "J2") == 0 || + strcmp(argv[1], "J2N") == 0 || + strcmp(argv[1], "J2Plasticity") == 0) { + + // "J2Plasticity" tag? K? G? sig0? sigInf? delta? Hiso? + enum class Position : int { + Tag, K, G, YieldStress, SatStress, Hsat, Hiso, EndRequired, + Eta, End, + E, Nu, Lambda, Hkin, Theta, Hmix, SatStress0, + Delta2, Rho, RhoBar, Atm, + Density + }; + return TclCommand_newPlasticParser(clientData, interp, argc, argv); + } + else if (strcmp(argv[1], "DP") == 0 || + strcmp(argv[1], "DruckerPrager") == 0) { + + // DruckerPrager tag? K? G? sigma_y? rho? rho_bar? Kinf? Ko? delta1? delta2? H? theta? + enum class Position : int { + Tag, K, G, YieldStress, Rho, RhoBar, + SatStress, SatStress0, Hsat, Delta2, Hmix, Theta, EndRequired, + Density, Atm, End, + Eta, E, Nu, Lambda, Hiso, Hkin + }; + return TclCommand_newPlasticParser(clientData, interp, argc, argv); + } + return TCL_ERROR; +} + + +#include +int +TclCommand_newUniaxialJ2Plasticity(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char** const argv) +{ + // ----- 1D J2 Plasticity ---- + if (argc < 7) { + opserr << "WARNING invalid number of arguments\n"; + opserr << "Want: uniaxialMaterial UniaxialJ2Plasticity tag? E? sigmaY? Hkin? " + << "\n"; + return TCL_ERROR; + } + + int tag; + double E, sigmaY, Hkin, Hiso; + Hiso = 0.0; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid uniaxialMaterial UniaxialJ2Plasticity tag" + << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { + opserr << "WARNING invalid E\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[4], &sigmaY) != TCL_OK) { + opserr << "WARNING invalid sigmaY\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[5], &Hkin) != TCL_OK) { + opserr << "WARNING invalid Hkin\n"; + return TCL_ERROR; + } + + if (argc >= 7) + if (Tcl_GetDouble(interp, argv[6], &Hiso) != TCL_OK) { + opserr << "WARNING invalid Hiso\n"; + return TCL_ERROR; + } + + // Parsing was successful, allocate the material + UniaxialMaterial* theMaterial = new UniaxialJ2Plasticity(tag, E, sigmaY, Hkin, Hiso); + + assert(clientData != nullptr); + BasicModelBuilder *builder = static_cast(clientData); + builder->addTaggedObject(*theMaterial); + return TCL_OK; +} + + +int +TclCommand_newJ2Simplified(ClientData clientData, Tcl_Interp* interp, int argc, const char** const argv) +{ + + BasicModelBuilder* builder = static_cast(clientData); + + if (argc < 8) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: nDmaterial Simplified3DJ2 $matTag $G $K $sig0 $Hkin $Hiso" + << "\n"; + return TCL_ERROR; + } + + int tag; + double K, G, sig0, H_kin, H_iso; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid tag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[3], &G) != TCL_OK) { + opserr << "WARNING invalid G\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[4], &K) != TCL_OK) { + opserr << "WARNING invalid K\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[5], &sig0) != TCL_OK) { + opserr << "WARNING invalid sig0\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[6], &H_kin) != TCL_OK) { + opserr << "WARNING invalid Hkin\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[7], &H_iso) != TCL_OK) { + opserr << "WARNING invalid Hiso\n"; + return TCL_ERROR; + } + + NDMaterial* theMaterial = nullptr; + + if ((strcmp(argv[1], "Simplified3DJ2") == 0) || + (strcmp(argv[1], "3DJ2") == 0) || + (strcmp(argv[1], "SimplifiedJ2") == 0) || + (strcmp(argv[1], "PlaneStressSimplifiedJ2") == 0)) { + double density = 0.0; + theMaterial = new SimplifiedJ2(tag, 3, G, K, sig0, H_kin, H_iso, density); + + if (strcmp(argv[1], "PlaneStressSimplifiedJ2") == 0) { + theMaterial = new PlaneStressSimplifiedJ2(tag, 2, *theMaterial); + } + } + + // + if (builder->addTaggedObject(*theMaterial) != TCL_OK ) { + delete theMaterial; + return TCL_ERROR; + } + return TCL_OK; +} diff --git a/SRC/runtime/commands/modeling/material/shell.cpp b/SRC/runtime/commands/modeling/material/shell.cpp new file mode 100644 index 0000000000..a70e1f5f3b --- /dev/null +++ b/SRC/runtime/commands/modeling/material/shell.cpp @@ -0,0 +1,252 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Written: rms, MHS, cmp +// Created: 07/99 +// +// Description: This file contains the function invoked when the user invokes +// the section command in the interpreter. +// +// +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +typedef SectionForceDeformation ShellSection; + + +int +TclCommand_addElasticShellSection(ClientData clientData, Tcl_Interp* interp, + int argc, TCL_Char** const argv) +{ + + BasicModelBuilder* builder = static_cast(clientData); + + if (argc < 5) { + opserr << OpenSees::PromptValueError + << "insufficient arguments\n"; + opserr << "Want: section ElasticMembranePlateSection tag? E? nu? h? " + " " + << "\n"; + return TCL_ERROR; + } + + int tag; + double E, nu, h; + double rho = 0.0; + double Ep_mod = 1.0; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid section ElasticMembranePlateSection tag" + << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid E" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[4], &nu) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid nu" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[5], &h) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid h" << "\n"; + return TCL_ERROR; + } + + if (argc > 6 && Tcl_GetDouble(interp, argv[6], &rho) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid rho" << "\n"; + return TCL_ERROR; + } + + if (argc > 7 && Tcl_GetDouble(interp, argv[7], &Ep_mod) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid Ep_mod" << "\n"; + return TCL_ERROR; + } + + builder->addTaggedObject(*new ElasticMembranePlateSection(tag, E, nu, h, rho, Ep_mod)); + return TCL_OK; +} + + +int +TclCommand_ShellSection(ClientData clientData, Tcl_Interp* interp, + Tcl_Size argc, TCL_Char** const argv) +{ + // Pointer to a section that will be added to the model builder + SectionForceDeformation* theSection = nullptr; + BasicModelBuilder *builder = static_cast(clientData); + + if ((strcmp(argv[1], "PlateFiber") == 0) || + (strcmp(argv[1], "PlateFiberThermal") == 0)) { // TODO: add thermal + + if (argc < 5) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: section PlateFiber tag? matTag? h? \n"; + return TCL_ERROR; + } + + int tag; + double h; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid section PlateFiber tag\n"; + return TCL_ERROR; + } + + int matTag; + if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { + opserr << "WARNING invalid material tag " << argv[3] << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[4], &h) != TCL_OK) { + opserr << "WARNING invalid h\n"; + return TCL_ERROR; + } + + NDMaterial* theMaterial = builder->getTypedObject(matTag); + if (theMaterial == nullptr) + return TCL_ERROR; + + theSection = new MembranePlateFiberSection(tag, h, *theMaterial); + } + + else if ((strcmp(argv[1], "LayeredShell") == 0) || + (strcmp(argv[1], "LayeredShellThermal") == 0)) { // TODO: add thermal + + // section LayeredShell tag? nLayers? -or- + + int status = TCL_ERROR; + if (argc < 6) { + opserr << OpenSees::PromptValueError + << "insufficient arguments " << "\n"; + opserr << "Want: section LayeredShell tag? nLayers? mat1? h1? ... matn? hn? " + << "\n"; + return TCL_ERROR; + } + + int tag, nLayers; // , matTag; + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid section tag" << "\n"; + return TCL_ERROR; + } + + double h, *thickness; + NDMaterial **theMats; + if (Tcl_GetInt(interp, argv[3], &nLayers) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid nLayers" << "\n"; + opserr << "LayeredShell section: " << tag << "\n"; + return TCL_ERROR; + } + + if (nLayers < 3) { + opserr << "ERROR number of layers must be larger than 2" << "\n"; + return TCL_ERROR; + } + + if (argc < 3+2*nLayers) { + opserr << OpenSees::PromptValueError << "Must provide " << 2*nLayers << " layers\n"; + return TCL_ERROR; + } + + theMats = new NDMaterial *[nLayers]; + thickness = new double[nLayers]; + + for (int iLayer = 0; iLayer < nLayers; iLayer++) { + int mat; + if (Tcl_GetInt(interp, argv[4 + 2 * iLayer], &mat) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid material tag" << "\n"; + status = TCL_ERROR; + goto cleanup; + } + + NDMaterial* material = builder->getTypedObject(mat); + if (material == nullptr) { + status = TCL_ERROR; + goto cleanup; + } + + theMats[iLayer] = material->getCopy("PlateFiber"); + if (theMats[iLayer] == nullptr) { + theMats[iLayer] = new PlateFiberMaterial(mat, *material); + } + + if (Tcl_GetDouble(interp, argv[5 + 2 * iLayer], &h) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid h at layer " << iLayer << "\n"; + status = TCL_ERROR; + goto cleanup; + } + + if (h <= 0) { + opserr << OpenSees::PromptValueError + << "invalid h at layer " << iLayer << "\n"; + status = TCL_ERROR; + goto cleanup; + } + + thickness[iLayer] = h; + } + + theSection = new LayeredShellFiberSection(tag, nLayers, thickness, theMats); + + + if (builder->addTaggedObject(*theSection) == TCL_OK) { + status = TCL_OK; + } + +cleanup: + if (thickness != nullptr) + delete[] thickness; + + if (theMats != 0) { + for (int iLayer = 0; iLayer < nLayers; iLayer++) { + if (theMats[iLayer] != nullptr) + delete theMats[iLayer]; + } + delete[] theMats; + } + return status; + } + + + // Now add the material to the modelBuilder + if (builder->addTaggedObject(*theSection) < 0) { + opserr << "WARNING could not add section to the domain\n"; + opserr << *theSection << "\n"; + delete theSection; + return TCL_ERROR; + } + + return TCL_OK; +} + diff --git a/SRC/runtime/commands/modeling/material/wrapper.cpp b/SRC/runtime/commands/modeling/material/wrapper.cpp new file mode 100644 index 0000000000..ba3d0de33d --- /dev/null +++ b/SRC/runtime/commands/modeling/material/wrapper.cpp @@ -0,0 +1,484 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +int +TclCommand_addWrappingMaterial(ClientData clientData, Tcl_Interp* interp, + int argc, TCL_Char** const argv) +{ + // + // + // + BasicModelBuilder *builder = static_cast(clientData); + + if (argc < 4) { + opserr << OpenSees::PromptValueError << " insufficient arguments\n"; + return TCL_ERROR; + } + + int tago, tagi; + if (Tcl_GetInt(interp, argv[2], &tago) != TCL_OK) { + opserr << OpenSees::PromptValueError << "failed to read tag\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[3], &tagi) != TCL_OK) { + opserr << OpenSees::PromptValueError << "failed to read tag\n"; + return TCL_ERROR; + } + + if (strcmp(argv[1], "ContinuumWrapper") == 0 || strcmp(argv[1], "Continuum") == 0) { + NDMaterial* inside = builder->getTypedObject(tagi); + if (inside == nullptr) + return TCL_ERROR; + + return builder->addTypedObject(tago, new ContinuumUniaxial(tago, *inside)); + } + + else if (strcmp(argv[0], "uniaxialMaterial") == 0 && ( + strstr(argv[1], "InitStress") != 0 || + strstr(argv[1], "InitialStress") != 0 || + strstr(argv[1], "InitialStrain") != 0 || + strstr(argv[1], "InitStrain") != 0)) { + + double initial; + if (Tcl_GetDouble(interp, argv[4], &initial) != TCL_OK) { + opserr << OpenSees::PromptValueError << "failed to read initial value\n"; + return TCL_ERROR; + } + UniaxialMaterial* inside = builder->getTypedObject(tagi); + if (inside == nullptr) + return TCL_ERROR; + + if (strstr(argv[1], "Stress") != 0) + return builder->addTypedObject(tago, new InitStressMaterial(tago, *inside, initial)); + else if (strstr(argv[1], "Strain") != 0) + return builder->addTypedObject(tago, new InitStrainMaterial(tago, *inside, initial)); + } + + else if (strcmp(argv[0], "nDMaterial") == 0 && ( + strstr(argv[1], "InitStress") != 0 || + strstr(argv[1], "InitialStress") != 0 || + strstr(argv[1], "InitialStrain") != 0 || + strstr(argv[1], "InitStrain") != 0)) { + + Vector initial(6); + NDMaterial* inside = builder->getTypedObject(tagi); + if (inside == nullptr) + return TCL_ERROR; + + inside = inside->getCopy("ThreeDimensional"); + if (!inside || strcmp(inside->getType(), "ThreeDimensional") != 0) { + opserr << OpenSees::PromptValueError << "InitStressNDMaterial only works with 3D materials\n"; + return TCL_ERROR; + } + + if (argc == 5) { + double evol; + if (Tcl_GetDouble(interp, argv[4], &evol) != TCL_OK) { + opserr << OpenSees::PromptValueError << "failed to read initial value\n"; + return TCL_ERROR; + } + for (int i = 0; i < 3; ++i) + initial(i) = evol; + + } else { + for (int i=0; i<6; ++i) { + if (Tcl_GetDouble(interp, argv[4+i], &initial(i)) != TCL_OK) { + opserr << OpenSees::PromptValueError << "failed to read initial value\n"; + return TCL_ERROR; + } + } + } + + if (strstr(argv[1], "Strain") != 0) + return builder->addTypedObject(tago, new InitStrainNDMaterial(tago, *inside, initial)); + } + + + return TCL_ERROR; +} + + +int +TclCommand_newParallelMaterial(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char ** const argv) +{ + if (argc < 4) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: uniaxialMaterial Parallel tag? tag1? tag2? ..."; + opserr << " <-min min?> <-max max?>" << "\n"; + return TCL_ERROR; + } + + int tag; + UniaxialMaterial* theMaterial = nullptr; + BasicModelBuilder* builder = static_cast(clientData); + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid uniaxialMaterial Parallel tag" << "\n"; + return TCL_ERROR; + } + + int numMaterials = argc-3; + + if (numMaterials == 0) { + opserr << "WARNING no component material(s) provided\n"; + return TCL_ERROR; + } + + // Create an array to hold pointers to component materials + UniaxialMaterial **theMats = new UniaxialMaterial *[numMaterials]; + + // For each material get the tag and ensure it exists in model already + for (int i=0; igetTypedObject(tagI); + + if (theMat == nullptr) { + delete [] theMats; + return TCL_ERROR; + } else + theMats[i] = theMat; + } + + // Parsing was successful, allocate the material + theMaterial = new ParallelMaterial(tag, numMaterials, theMats); + builder->addTaggedObject(*theMaterial); + + delete [] theMats; + return TCL_OK; +} + +// material type? tag? nd_tag? +int +TclCommand_newPlateFiber(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char ** const argv) +{ + BasicModelBuilder *builder = static_cast(clientData); + + if (argc < 4) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: nDMaterial " << argv[1] << " tag? matTag?" << "\n"; + return TCL_ERROR; + } + + int tag, matTag; + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid nDMaterial tag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { + opserr << "WARNING invalid matTag " << argv[3] << "\n"; + return TCL_ERROR; + } + + NDMaterial *threeDMaterial = builder->getTypedObject(matTag); + if (threeDMaterial == nullptr) + return TCL_ERROR; + + // Check if the material is a 3D material + threeDMaterial = threeDMaterial->getCopy("ThreeDimensional"); + if (threeDMaterial == nullptr) { + opserr << "a ThreeDimensional material was expected\n"; + return TCL_ERROR; + } + + NDMaterial *theMaterial = nullptr; + if (strcmp(argv[1], "PlateFiberMaterial") == 0 || + strcmp(argv[1], "PlateFiber") == 0) { + theMaterial = new PlateFiberMaterial(tag, *threeDMaterial); + } + // else if (strcmp(argv[1], "PlateFiberMaterialThermal") == 0 || + // strcmp(argv[1], "PlateFiberThermal") == 0) { + // theMaterial = new PlateFiberMaterialThermal(tag, *threeDMaterial); + // } + else if (strcmp(argv[1], "BeamFiberMaterial") == 0 || + strcmp(argv[1], "BeamFiber") == 0) { + theMaterial = new BeamFiberMaterial(tag, *threeDMaterial); + } + else if (strcmp(argv[1], "BeamFiberMaterial2d") == 0 || + strcmp(argv[1], "BeamFiber2d") == 0) { + theMaterial = new BeamFiberMaterial2d(tag, *threeDMaterial); + } + else if (strcmp(argv[1], "BeamFiberMaterial2dPS") == 0 || + strcmp(argv[1], "BeamFiber2dPS") == 0) { + theMaterial = new BeamFiberMaterial2dPS(tag, *threeDMaterial); + } + + else { + opserr << "WARNING invalid material type " << "\n"; + return TCL_ERROR; + } + + if (builder->addTaggedObject(*theMaterial) != TCL_OK) { + delete theMaterial; + return TCL_ERROR; + } + + delete threeDMaterial; + return TCL_OK; +} + +// nDMaterial type? tag? uni_tag? angle? +int +TclCommand_newPlateRebar(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char ** const argv) +{ + // + // nDMaterial type? tag? uni_tag? angle? + // + BasicModelBuilder *builder = static_cast(clientData); + if (argc < 5) { + opserr << "WARNING insufficient arguments\n"; + return TCL_ERROR; + } + + int tag, matTag; + double angle; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid nDMaterial PlateRebar tag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { + opserr << "WARNING invalid matTag " << argv[3] << "\n"; + return TCL_ERROR; + } + + UniaxialMaterial *theMat = builder->getTypedObject(matTag); + if (theMat == nullptr) + return TCL_ERROR; + + if (Tcl_GetDouble(interp, argv[4], &angle) != TCL_OK) { + opserr << "WARNING invalid angle" << "\n"; + return TCL_ERROR; + } + + if (strcmp(argv[1], "PlateRebarMaterial") == 0 || + strcmp(argv[1], "PlateRebar") == 0) { + if (builder->addTaggedObject(*new PlateRebarMaterial(tag, *theMat, angle)) != TCL_OK) { + return TCL_ERROR; + } + } + + else if (strcmp(argv[1], "PlaneStressRebarMaterial") == 0 || + strcmp(argv[1], "PlaneStressRebar") == 0) { + if (builder->addTaggedObject(*new PlaneStressRebarMaterial(tag, *theMat, angle)) != TCL_OK) { + return TCL_ERROR; + } + } + + else { + opserr << "WARNING invalid material type " << "\n"; + return TCL_ERROR; + } + return TCL_OK; +} + + + +int +TclCommand_newFatigueMaterial(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char ** const argv) +{ + assert(clientData != nullptr); + BasicModelBuilder *builder = static_cast(clientData); + + if (argc < 4) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: uniaxialMaterial Fatigue tag? matTag?"; + opserr << " <-D_max dmax?> <-e0 e0?> <-m m?>" << "\n"; + opserr << " <-min min?> <-max max?>" << "\n"; + return TCL_ERROR; + } + + int tag, matTag; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid uniaxialMaterial Fatigue tag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid component tag\n"; + return TCL_ERROR; + } + + double Dmax = 1.0; + double E0 = 0.191; + double m = -0.458; + double epsmin = NEG_INF_STRAIN; + double epsmax = POS_INF_STRAIN; + + for (int j = 4; j < argc; j++) { + if (strcmp(argv[j], "-Dmax") == 0) { + if ((j + 1 >= argc) || + (Tcl_GetDouble(interp, argv[++j], &Dmax) != TCL_OK)) { + opserr << OpenSees::PromptValueError << "invalid -Dmax"; + return TCL_ERROR; + } + } else if (strcmp(argv[j], "-E0") == 0) { + if ((j + 1 >= argc) || (Tcl_GetDouble(interp, argv[++j], &E0) != TCL_OK)) { + opserr << OpenSees::PromptValueError << "invalid -E0"; + return TCL_ERROR; + } + } else if (strcmp(argv[j], "-m") == 0) { + if ((j + 1 >= argc) || + (Tcl_GetDouble(interp, argv[++j], &m) != TCL_OK)) { + opserr << OpenSees::PromptValueError << "invalid -m"; + return TCL_ERROR; + } + } else if (strcmp(argv[j], "-min") == 0) { + if ((j + 1 >= argc) || + (Tcl_GetDouble(interp, argv[++j], &epsmin) != TCL_OK)) { + opserr << OpenSees::PromptValueError << "invalid -min "; + return TCL_ERROR; + } + } else if (strcmp(argv[j], "-max") == 0) { + if ((j + 1 >= argc) || + (Tcl_GetDouble(interp, argv[++j], &epsmax) != TCL_OK)) { + opserr << OpenSees::PromptValueError << "invalid -max"; + return TCL_ERROR; + } + } + } + + UniaxialMaterial *theMat = builder->getTypedObject(matTag); + + if (theMat == nullptr) { + opserr << OpenSees::PromptValueError << "component material does not exist\n"; + return TCL_ERROR; + } + + // Parsing was successful, allocate the material + UniaxialMaterial *theMaterial = + new FatigueMaterial(tag, *theMat, Dmax, E0, m, epsmin, epsmax); + + if (builder->addTaggedObject(*theMaterial) != TCL_OK) { + delete theMaterial; + return TCL_ERROR; + } + return TCL_OK; + +} + + +int +TclCommand_addPlaneWrapper(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char** const argv) +{ + + BasicModelBuilder *builder = static_cast(clientData); + + NDMaterial * theMaterial = nullptr; + + if (strcmp(argv[1], "PlaneStressMaterial") == 0 || + strcmp(argv[1], "PlaneStress") == 0) { + if (argc < 4) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: nDMaterial PlaneStress tag? matTag?" << "\n"; + return TCL_ERROR; + } + + int tag, matTag; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid nDMaterial PlaneStress tag" << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { + opserr << "WARNING invalid matTag" << "\n"; + opserr << "PlaneStress: " << matTag << "\n"; + return TCL_ERROR; + } + + NDMaterial *threeDMaterial = builder->getTypedObject(matTag); + if (threeDMaterial == nullptr) + return TCL_ERROR; + + theMaterial = new PlaneStressMaterial(tag, *threeDMaterial); + } + + // PlaneStrainMaterial + else if (strcmp(argv[1], "PlaneStrainMaterial") == 0 || + strcmp(argv[1], "PlaneStrain") == 0) { + if (argc < 4) { + opserr << "WARNING insufficient arguments\n"; + opserr << "Want: nDMaterial PlaneStrain tag? matTag?" << "\n"; + return TCL_ERROR; + } + + int tag, matTag; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid nDMaterial tag " << argv[2] << "\n"; + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { + opserr << "WARNING invalid matTag " << argv[3] << "\n"; + return TCL_ERROR; + } + + NDMaterial *threeDMaterial = builder->getTypedObject(matTag); + if (threeDMaterial == nullptr) + return TCL_ERROR; + + theMaterial = new PlaneStrainMaterial(tag, *threeDMaterial); + } + + // Done parsing + if (builder->addTaggedObject(*theMaterial) != TCL_OK ) { + delete theMaterial; + return TCL_ERROR; + } + + return TCL_OK; + +} diff --git a/SRC/runtime/commands/modeling/mesh.cpp b/SRC/runtime/commands/modeling/mesh.cpp deleted file mode 100644 index 207d1d1475..0000000000 --- a/SRC/runtime/commands/modeling/mesh.cpp +++ /dev/null @@ -1,84 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// OpenSees - Open System for Earthquake Engineering Simulation -// -//===----------------------------------------------------------------------===// -// -// -extern int OPS_LineMesh(Domain& domain, int ndm); -extern int OPS_TriMesh(Domain& domain); -extern int OPS_TriReMesh(Domain& domain, int ndf); - -int -TclCommand_mesh(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ - // ensure the destructor has not been called - - assert(clientData != nullptr); - - // make sure corect number of arguments on command line - if (argc < 2) { - opserr << "WARNING insufficient arguments\n"; - opserr << "Want: mesh type? ...>\n"; - return TCL_ERROR; - } - - OPS_ResetInput(clientData, interp, 2, argc, argv, theTclDomain, - theTclBuilder); - - // mesh type - int res = 0; - // if (strcmp(argv[1], "line") == 0) { - // res = OPS_LineMesh(*theTclDomain,ndm); - // } else if (strcmp(argv[1], "tri") == 0) { - // res = OPS_TriMesh(*theTclDomain); - // } else { - // opserr<<"WARNING: mesh type "<\n"; - return TCL_ERROR; - } - - OPS_ResetInput(clientData, interp, 2, argc, argv, theTclDomain, - theTclBuilder); - - // mesh type - int res = 0; - if (strcmp(argv[1], "line") == 0) { - //res = OPS_LineMesh(*theTclDomain,ndm); - } else if (strcmp(argv[1], "tri") == 0) { - res = OPS_TriReMesh(*theTclDomain,ndf); - } else { - opserr<<"WARNING: remesh type "< #include +#include #include #include #include @@ -31,16 +41,22 @@ bool builtModel = false; FE_Datastore *theDatabase = nullptr; -extern int G3_AddTclAnalysisAPI(Tcl_Interp *, Domain*); +extern int G3_AddTclAnalysisAPI(Tcl_Interp *, BasicModelBuilder&); extern int G3_AddTclDomainCommands(Tcl_Interp *, Domain*); + +// int TclCommand_specifyModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char *argv[]) { G3_Runtime *rt = G3_getRuntime(interp); - BasicModelBuilder *theNewBuilder = nullptr; Domain *theNewDomain = (Domain*)clientData; + BasicModelBuilder *theNewBuilder = nullptr; + + // + // + // if (clientData == nullptr) { theNewDomain = new Domain(); @@ -50,17 +66,12 @@ TclCommand_specifyModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL Tcl_CreateCommand(interp, "model", &TclCommand_specifyModel, theNewDomain, nullptr); G3_AddTclDomainCommands(interp, theNewDomain); - - const char* analysis_option; - if (!(analysis_option = Tcl_GetVar(interp,"opensees::pragma::analysis",TCL_GLOBAL_ONLY)) || - (strcmp(analysis_option, "off") != 0)) { - G3_AddTclAnalysisAPI(interp, theNewDomain); - } } + // make sure at least one other argument to contain model builder type given if (argc < 2) { - opserr << G3_ERROR_PROMPT << "need to specify a model type, valid types:\n"; + opserr << OpenSees::PromptValueError << "need to specify a model type, valid types:\n"; opserr << "\tBasicBuilder\n"; return TCL_ERROR; } @@ -73,8 +84,8 @@ TclCommand_specifyModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL (strcmp(argv[1], "basicBuilder") == 0)) { if (argc < 3) { - opserr << G3_ERROR_PROMPT << "incorrect number of command arguments, expected:\n"; - opserr << "\tmodel modelBuilderType -ndm ndm? <-ndf ndf?> \n"; + opserr << OpenSees::PromptValueError + << "incorrect number of arguments\n"; return TCL_ERROR; } int ndm = 0; @@ -88,8 +99,8 @@ TclCommand_specifyModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL argPos++; if (argPos < argc) { if (Tcl_GetInt(interp, argv[argPos], &ndm) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "error reading ndm, got '" << argv[argPos]; - opserr << "' but expected:\n\tmodel modelBuilderType -ndm ndm? <-ndf ndf?>\n"; + opserr << OpenSees::PromptValueError + << "error reading ndm, got '" << argv[argPos] << "'\n"; return TCL_ERROR; } } @@ -101,8 +112,7 @@ TclCommand_specifyModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL argPos++; if (argPos < argc) if (Tcl_GetInt(interp, argv[argPos], &ndf) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid parameter ndf, expected:"; - opserr << "\n\tmodel modelBuilderType -ndm ndm? <-ndf ndf?>\n"; + opserr << OpenSees::PromptValueError << "invalid parameter ndf"; return TCL_ERROR; } argPos++; @@ -110,8 +120,7 @@ TclCommand_specifyModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL } else if (posArg == 1) { if (Tcl_GetInt(interp, argv[argPos], &ndm) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid parameter ndm, expected:"; - opserr << "\n\tmodel modelBuilderType -ndm ndm? <-ndf ndf?>\n"; + opserr << OpenSees::PromptValueError << "invalid parameter ndm"; return TCL_ERROR; } argPos++; @@ -119,8 +128,7 @@ TclCommand_specifyModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL } else if (posArg == 2) { if (Tcl_GetInt(interp, argv[argPos], &ndf) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "error reading ndf: " << argv[argPos]; - opserr << "\nmodel modelBuilderType -ndm ndm? <-ndf ndf?>\n"; + opserr << OpenSees::PromptValueError << "error reading ndf: " << argv[argPos] << "\n"; return TCL_ERROR; } argPos++; @@ -134,8 +142,7 @@ TclCommand_specifyModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL // check that ndm was specified if (ndm == 0) { - opserr << G3_ERROR_PROMPT << "need to specify ndm\n"; - opserr << " model modelBuilderType -ndm ndm? <-ndf ndf?>\n"; + opserr << OpenSees::PromptValueError << "missing required argument ndm\n"; return TCL_ERROR; } @@ -148,7 +155,7 @@ TclCommand_specifyModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL else if (ndm == 3) ndf = 6; else { - opserr << G3_ERROR_PROMPT << "specified ndm, " << ndm << ", will not work\n"; + opserr << OpenSees::PromptValueError << "specified ndm, " << ndm << ", will not work\n"; opserr << " with any elements in BasicBuilder\n"; return TCL_ERROR; } @@ -160,70 +167,17 @@ TclCommand_specifyModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL // create the model builder theNewBuilder = new BasicModelBuilder(*theNewDomain, interp, ndm, ndf); G3_setModelBuilder(rt, theNewBuilder); - } -#if 0 - else if ((strcmp(argv[1], "test") == 0) || - (strcmp(argv[1], "uniaxial") == 0) || - (strcmp(argv[1], "TestUniaxial") == 0) || - (strcmp(argv[1], "testUniaxial") == 0) || - (strcmp(argv[1], "UniaxialMaterialTest") == 0)) { - int count = 1; - if (argc == 3) { - if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) { - return TCL_ERROR; - } - } - theNewBuilder = new TclUniaxialMaterialTester(*theNewDomain, interp, count); - if (theNewBuilder == 0) { - opserr << G3_ERROR_PROMPT << "ran out of memory in creating " - "TclUniaxialMaterialTester model\n"; - return TCL_ERROR; - } else { - G3_setModelBuilder(rt, theNewBuilder); - } - } - - - else if ((strcmp(argv[1], "testPlaneStress") == 0) || - (strcmp(argv[1], "StressPatch") == 0) || - (strcmp(argv[1], "PlaneStressMaterialTest") == 0)) { - int count = 1; - if (argc == 3) { - if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) { - return TCL_ERROR; - } - } - - theNewBuilder = new TclPlaneStressMaterialTester(theDomain, interp, count); - if (theNewBuilder == 0) { - opserr << G3_ERROR_PROMPT << "ran out of memory in creating " - "TclUniaxialMaterialTester model\n"; - return TCL_ERROR; - } - } - - else if ((strcmp(argv[1], "sectionTest") == 0) || - (strcmp(argv[1], "TestSection") == 0) || - (strcmp(argv[1], "testSection") == 0) || - (strcmp(argv[1], "SectionForceDeformationTest") == 0)) { - int count = 1; - if (argc == 3) { - if (Tcl_GetInt(interp, argv[2], &count) != TCL_OK) { - return TCL_ERROR; - } + const char* analysis_option; + if (!(analysis_option = Tcl_GetVar(interp,"opensees::pragma::analysis",TCL_GLOBAL_ONLY)) || + (strcmp(analysis_option, "off") != 0)) { + G3_AddTclAnalysisAPI(interp, *theNewBuilder); } - theNewBuilder = new TclSectionTestBuilder(theDomain, interp, count); - if (theNewBuilder == 0) { - opserr << G3_ERROR_PROMPT << "ran out of memory in creating " - "TclUniaxialMAterialTester model\n"; - return TCL_ERROR; - } } -#endif - else { - opserr << G3_ERROR_PROMPT << "unknown model builder type '" << argv[1] << "' not supported\n"; + opserr << OpenSees::PromptValueError + << "unknown model builder type '" << argv[1] << "' not supported" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } @@ -267,7 +221,7 @@ TclCommand_wipeModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Ch // command invoked to build the model, i.e. to invoke buildFE_Model() // on the ModelBuilder int -buildModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char *argv[]) +buildModel(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, TCL_Char *argv[]) { G3_Runtime *rt = G3_getRuntime(interp); BasicModelBuilder* builder = (BasicModelBuilder*)G3_getModelBuilder(rt); @@ -279,12 +233,12 @@ buildModel(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char *argv[] builtModel = true; return builder->buildFE_Model(); - } else if (builder != 0 && builtModel == true) { - opserr << G3_ERROR_PROMPT << "Model has already been built - not built again \n"; + } else if (builder != nullptr && builtModel == true) { + opserr << OpenSees::PromptValueError << "Model has already been built - not built again \n"; return TCL_ERROR; } else { - opserr << G3_ERROR_PROMPT << "No ModelBuilder type has been specified \n"; + opserr << OpenSees::PromptValueError << "No ModelBuilder type has been specified \n"; return TCL_ERROR; } } diff --git a/SRC/runtime/commands/modeling/nodes.cpp b/SRC/runtime/commands/modeling/nodes.cpp index c8f3be9360..cb1ae409d1 100644 --- a/SRC/runtime/commands/modeling/nodes.cpp +++ b/SRC/runtime/commands/modeling/nodes.cpp @@ -1,14 +1,25 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// -// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// // Description: This file implements commands that configure Node objects // for an analysis. // // Author: cmp // +#include #include #include #include @@ -18,9 +29,11 @@ #include #include #include +#include #include -#define G3_MAX_NUM_DOFS 1000000000000 +#define HeapNode Node + #define G3_NUM_DOF_BUFFER 20 int @@ -37,71 +50,62 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, int ndf = builder->getNDF(); // make sure corect number of arguments on command line - if (argc < 2 + ndm) { - opserr << G3_ERROR_PROMPT << "insufficient arguments, expected:\n"; - opserr << " node nodeTag? [ndm coordinates?] <-mass [ndf values?]>\n"; + if (argc < 2 + 1) { // ndm) { + opserr << OpenSees::PromptValueError + << "insufficient arguments" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } - Node *theNode = 0; + Node *theNode = nullptr; // read the node id int nodeId; if (Tcl_GetInt(interp, argv[1], &nodeId) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nodeTag\n"; + opserr << OpenSees::PromptValueError << "invalid nodeTag\n"; opserr << " Want: node nodeTag? [ndm coordinates?] <-mass [ndf values?]>\n"; return TCL_ERROR; } + + Parameter* coord_params[3] = {nullptr, nullptr, nullptr}; + using namespace OpenSees::Parsing; + // read in the coordinates and create the node - double xLoc, yLoc, zLoc; - if (ndm == 1) { + double xLoc=0, yLoc=0, zLoc=0; + if (ndm >= 1 && argc >= 3) { // create a node in 1d space - if (Tcl_GetDouble(interp, argv[2], &xLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid coordinate\n"; + if (GetDoubleParam(interp, *theTclDomain, argv[2], &xLoc, coord_params[0]) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "invalid coordinate " << argv[2] + << OpenSees::SignalMessageEnd; return TCL_ERROR; } } - else if (ndm == 2) { - // create a node in 2d space - if (Tcl_GetDouble(interp, argv[2], &xLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid 1st coordinate\n"; - opserr << "node: " << nodeId << "\n"; - return TCL_ERROR; - } + if (ndm >= 2 && argc >= 4) { if (Tcl_GetDouble(interp, argv[3], &yLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid 2nd coordinate\n"; - opserr << "node: " << nodeId << "\n"; + opserr << OpenSees::PromptValueError + << "invalid 2nd coordinate " << argv[3] + << OpenSees::SignalMessageEnd; return TCL_ERROR; } } - else if (ndm == 3) { - // create a node in 3d space - if (Tcl_GetDouble(interp, argv[2], &xLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid 1st coordinate\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[3], &yLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid 2nd coordinate\n"; - return TCL_ERROR; - } + if (ndm >= 3 && argc >= 5) { if (Tcl_GetDouble(interp, argv[4], &zLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid 3rd coordinate\n"; + opserr << OpenSees::PromptValueError + << "invalid 3rd coordinate " << argv[4] + << OpenSees::SignalMessageEnd; return TCL_ERROR; } - - } else { - opserr << G3_ERROR_PROMPT << "unsupported model dimension\n"; - return TCL_ERROR; } // check for -ndf override option int currentArg = 2 + ndm; if (currentArg < argc && strcmp(argv[currentArg], "-ndf") == 0) { if (Tcl_GetInt(interp, argv[currentArg + 1], &ndf) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nodal ndf given for node " << nodeId << "\n"; + opserr << OpenSees::PromptValueError << "invalid nodal ndf given for node " << nodeId << "\n"; return TCL_ERROR; } currentArg += 2; @@ -112,26 +116,13 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, // switch (ndm) { case 1: - theNode = new Node(nodeId, ndf, xLoc); + theNode = new HeapNode(nodeId, ndf, xLoc); break; case 2: - theNode = new Node(nodeId, ndf, xLoc, yLoc); + theNode = new HeapNode(nodeId, ndf, xLoc, yLoc); break; case 3: - if (getenv("NODE")) { - switch (ndf) { - case 3: - theNode = new NodeND<3, 3>(nodeId, xLoc, yLoc, zLoc); - break; - case 6: - theNode = new NodeND<3, 6>(nodeId, xLoc, yLoc, zLoc); - break; - default: - theNode = new Node(nodeId, ndf, xLoc, yLoc, zLoc); - break; - } - } else - theNode = new Node(nodeId, ndf, xLoc, yLoc, zLoc); + theNode = new HeapNode(nodeId, ndf, xLoc, yLoc, zLoc); break; } @@ -139,7 +130,7 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, if (strcmp(argv[currentArg], "-mass") == 0) { currentArg++; if (argc < currentArg + ndf) { - opserr << G3_ERROR_PROMPT << "incorrect number of nodal mass terms\n"; + opserr << OpenSees::PromptValueError << "incorrect number of nodal mass terms\n"; opserr << "node: " << nodeId << "\n"; return TCL_ERROR; } @@ -148,7 +139,7 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, Matrix mass(ndf, ndf); for (int i = 0; i < ndf; ++i) { if (Tcl_GetDouble(interp, argv[currentArg++], &theMass) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nodal mass term"; + opserr << OpenSees::PromptValueError << "invalid nodal mass term"; opserr << " at dof " << i + 1 << "\n"; return TCL_ERROR; } @@ -159,7 +150,7 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, } else if (strcmp(argv[currentArg], "-dispLoc") == 0) { currentArg++; if (argc < currentArg + ndm) { - opserr << G3_ERROR_PROMPT << "incorrect number of nodal display location terms, " + opserr << OpenSees::PromptValueError << "incorrect number of nodal display location terms, " "need ndm\n"; return TCL_ERROR; } @@ -167,7 +158,7 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, double theCrd; for (int i = 0; i < ndm; ++i) { if (Tcl_GetDouble(interp, argv[currentArg++], &theCrd) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nodal mass term\n"; + opserr << OpenSees::PromptValueError << "invalid nodal mass term\n"; opserr << "node: " << nodeId << ", dof: " << i + 1 << "\n"; return TCL_ERROR; } @@ -178,7 +169,7 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, } else if (strcmp(argv[currentArg], "-disp") == 0) { currentArg++; if (argc < currentArg + ndf) { - opserr << G3_ERROR_PROMPT << "incorrect number of nodal disp terms\n"; + opserr << OpenSees::PromptValueError << "incorrect number of nodal disp terms\n"; opserr << "node: " << nodeId << "\n"; return TCL_ERROR; } @@ -186,7 +177,7 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, double theDisp; for (int i = 0; i < ndf; ++i) { if (Tcl_GetDouble(interp, argv[currentArg++], &theDisp) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nodal disp term\n"; + opserr << OpenSees::PromptValueError << "invalid nodal disp term\n"; opserr << "node: " << nodeId << ", dof: " << i + 1 << "\n"; return TCL_ERROR; } @@ -198,7 +189,7 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, } else if (strcmp(argv[currentArg], "-vel") == 0) { currentArg++; if (argc < currentArg + ndf) { - opserr << G3_ERROR_PROMPT << "incorrect number of nodal vel terms, "; + opserr << OpenSees::PromptValueError << "incorrect number of nodal vel terms, "; opserr << "expected " << ndf << "\n"; return TCL_ERROR; } @@ -207,7 +198,7 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, Vector disp(ndf); for (int i = 0; i < ndf; ++i) { if (Tcl_GetDouble(interp, argv[currentArg++], &theDisp) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nodal vel term at "; + opserr << OpenSees::PromptValueError << "invalid nodal vel term at "; opserr << " dof " << i + 1 << "\n"; return TCL_ERROR; } @@ -220,11 +211,25 @@ TclCommand_addNode(ClientData clientData, Tcl_Interp *interp, int argc, currentArg++; } + + // + // Setup parameters for coordinates + // + for (int i=0; i<3; ++i) { + if (coord_params[i] == nullptr) + continue; + char index[20]; + snprintf(index, sizeof(index), "%d", i + 1); + std::string idx = std::to_string(i + 1); + const char* args[2] = { "coord", index }; + coord_params[i]->addComponent(theNode, args, 2); + } + // // add the node to the domain // if (theTclDomain->addNode(theNode) == false) { - opserr << G3_ERROR_PROMPT << "failed to add node to the domain\n"; + opserr << OpenSees::PromptValueError << "failed to add node to the domain\n"; delete theNode; return TCL_ERROR; } @@ -244,7 +249,7 @@ TclCommand_addNodalMass(ClientData clientData, Tcl_Interp *interp, int argc, // make sure at least one other argument if (argc < (1 + ndf)) { - opserr << G3_ERROR_PROMPT << "insufficient arguments, expected:\n" + opserr << OpenSees::PromptValueError << "insufficient arguments, expected:\n" " mass nodeId <" << ndf << " mass values>\n"; return TCL_ERROR; } @@ -252,7 +257,7 @@ TclCommand_addNodalMass(ClientData clientData, Tcl_Interp *interp, int argc, // get the id of the node int nodeId; if (Tcl_GetInt(interp, argv[1], &nodeId) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nodeId: " << argv[1]; + opserr << OpenSees::PromptValueError << "invalid nodeId: " << argv[1]; opserr << " - mass nodeId " << ndf << " forces\n"; return TCL_ERROR; } @@ -262,7 +267,7 @@ TclCommand_addNodalMass(ClientData clientData, Tcl_Interp *interp, int argc, for (int i=0; isetMass(mass, nodeId) != 0) { - opserr << G3_ERROR_PROMPT << "failed to set mass at node " << nodeId << "\n"; + opserr << OpenSees::PromptValueError << "failed to set mass at node " << nodeId << "\n"; return TCL_ERROR; } @@ -292,13 +297,13 @@ TclCommand_getNDM(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char if (argc > 1) { int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "ndm nodeTag? \n"; + opserr << OpenSees::PromptValueError << "ndm nodeTag? \n"; return TCL_ERROR; } Node *theNode = the_domain->getNode(tag); if (theNode == nullptr) { - opserr << G3_ERROR_PROMPT << "nodeTag " << tag << " does not exist \n"; + opserr << OpenSees::PromptValueError << "nodeTag " << tag << " does not exist \n"; return TCL_ERROR; } const Vector &coords = theNode->getCrds(); @@ -323,12 +328,12 @@ TclCommand_getNDF(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char if (argc > 1) { int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "ndf nodeTag? \n"; + opserr << OpenSees::PromptValueError << "ndf nodeTag? \n"; return TCL_ERROR; } Node *theNode = the_domain->getNode(tag); if (theNode == nullptr) { - opserr << G3_ERROR_PROMPT << "nodeTag " << tag << " does not exist \n"; + opserr << OpenSees::PromptValueError << "nodeTag " << tag << " does not exist \n"; return TCL_ERROR; } ndf = theNode->getNumberDOF(); diff --git a/SRC/runtime/commands/modeling/printing.cpp b/SRC/runtime/commands/modeling/printing.cpp index 4176425a54..e9c9b06ab8 100644 --- a/SRC/runtime/commands/modeling/printing.cpp +++ b/SRC/runtime/commands/modeling/printing.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -17,7 +26,7 @@ #endif #include #include -#include +#include #include #include @@ -32,6 +41,9 @@ #include #include +#include +#include + #include #include #include @@ -47,7 +59,10 @@ #include #include -#include +#include +#include + +#include int printElement(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv, OPS_Stream &output); @@ -62,7 +77,8 @@ int printAlgorithm(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv, OPS_Stream &output); -int TclCommand_classType(ClientData clientData, Tcl_Interp *interp, int argc, +int +TclCommand_classType(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char** const argv) { @@ -78,7 +94,7 @@ int TclCommand_classType(ClientData clientData, Tcl_Interp *interp, int argc, MovableObject* theObject = nullptr; int tag; if (Tcl_GetInt(interp, argv[2], &tag) < 0) { - opserr << G3_ERROR_PROMPT << "classType objectType tag? - unable to read tag" << "\n"; + opserr << OpenSees::PromptValueError << "classType objectType tag? - unable to read tag" << "\n"; return TCL_ERROR; } @@ -92,7 +108,7 @@ int TclCommand_classType(ClientData clientData, Tcl_Interp *interp, int argc, theObject = builder->getTypedObject(tag); #endif else { - opserr << G3_ERROR_PROMPT << "classType - " << type.c_str() << " not yet supported" << "\n"; + opserr << OpenSees::PromptValueError << "classType - " << type.c_str() << " not yet supported" << "\n"; return TCL_ERROR; } @@ -103,6 +119,15 @@ int TclCommand_classType(ClientData clientData, Tcl_Interp *interp, int argc, return TCL_OK; } +template +static int +printRegistryObject(const BasicModelBuilder& builder, int tag, int flag, OPS_Stream *output) +{ + TaggedObject* object = builder.getTypedObject(tag); + object->Print(*output, flag); + return TCL_OK; +} + static int printRegistry(const BasicModelBuilder& builder, TCL_Char* type, int flag, OPS_Stream *output) { @@ -118,7 +143,7 @@ printDomain(OPS_Stream &s, BasicModelBuilder* builder, int flag) Domain* theDomain = builder->getDomain(); - const char* tab = " "; + const char* tab = " "; // TODO: maybe add a method called countRegistry<> // to BasicModelBuilder @@ -139,46 +164,79 @@ printDomain(OPS_Stream &s, BasicModelBuilder* builder, int flag) builder->printRegistry(s, flag); } s << "\n" << tab << tab << "]"; - s << ",\n"; } // - s << tab << tab << "\"nDMaterials\": [\n"; - builder->printRegistry(s, flag); - s << "\n" << tab << tab << "]"; s << ",\n"; // - s << tab << tab << "\"uniaxialMaterials\": [\n"; - builder->printRegistry(s, flag); - s << "\n" << tab << tab << "]"; + { + s << tab << tab << "\"nDMaterials\": [\n"; + builder->printRegistry(s, flag); + s << "\n" << tab << tab << "]"; + } + // + s << ",\n"; + // + { + s << tab << tab << "\"uniaxialMaterials\": [\n"; + builder->printRegistry(s, flag); + s << "\n" << tab << tab << "]"; + } s << ",\n"; // s << tab << tab << "\"crdTransformations\": [\n"; { - int n = builder->printRegistry(s, flag); + int n = builder->printRegistry(s, flag); DummyStream dummy; - if (builder->printRegistry(dummy, flag) > 0) { + if (builder->printRegistry(dummy, flag) > 0) { if (n > 0) s << ",\n"; - builder->printRegistry(s, flag); + builder->printRegistry(s, flag); } + s << "\n" << tab << tab << "]"; } - s << "\n" << tab << tab << "]"; -// builder->printRegistry(s, flag); + // + s << ",\n"; + // + { + s << tab << tab << "\"patterns\": [\n"; + LoadPatternIter &patterns = theDomain->getLoadPatterns(); + LoadPattern *p; + bool first_mp = true; + while ((p = patterns()) != nullptr) { + if (!first_mp) + s << ",\n"; + + p->Print(s, flag); + first_mp = false; + } + s << "\n" << tab << tab << "]"; + } + // + s << ",\n"; + // + { + s << tab << tab << "\"parameters\": [\n"; + ParameterIter ¶ms = theDomain->getParameters(); + Parameter *param; + bool first_mp = true; + while ((param = params()) != nullptr) { + if (!first_mp) + s << ",\n"; - // s << ",\n"; - // // - // s << tab << tab << "\"constraints\": [\n"; - // theDomain->Print(s, flag); - // s << "\n" << tab << tab << "]"; + param->Print(s, flag); + first_mp = false; + } + s << "\n" << tab << tab << "]\n"; + } + // s << "\n"; // + // s << tab << "},\n"; - // // s << tab << "\"geometry\": {\n"; - int numPrinted = 0; int numToPrint = theDomain->getNumNodes(); NodeIter &theNodess = theDomain->getNodes(); @@ -190,22 +248,53 @@ printDomain(OPS_Stream &s, BasicModelBuilder* builder, int flag) if (numPrinted < numToPrint) s << ",\n"; } - s << "\n" << tab << tab << "],\n"; - + s << "\n" << tab << tab << "]"; + // + s << ",\n"; + // + { + s << tab << tab << "\"elements\": [\n"; + Element *theEle; + ElementIter &theElementss = theDomain->getElements(); + numToPrint = theDomain->getNumElements(); + numPrinted = 0; + while ((theEle = theElementss()) != nullptr) { + theEle->Print(s, flag); + numPrinted += 1; + if (numPrinted < numToPrint) + s << ",\n"; + } + s << "\n" << tab << tab << "]"; + } + // + s << ",\n"; + // + { + s << tab << tab << "\"constraints\": [\n"; + MP_ConstraintIter &theMPs = theDomain->getMPs(); + MP_Constraint *theMP; + bool first_mp = true; + while ((theMP = theMPs()) != nullptr) { + if (!first_mp) + s << ",\n"; + theMP->Print(s, flag); + first_mp = false; + } - Element *theEle; - ElementIter &theElementss = theDomain->getElements(); - numToPrint = theDomain->getNumElements(); - numPrinted = 0; - s << tab << tab << "\"elements\": [\n"; - while ((theEle = theElementss()) != nullptr) { - theEle->Print(s, flag); - numPrinted += 1; - if (numPrinted < numToPrint) - s << ",\n"; + SP_ConstraintIter &theSPs = theDomain->getSPs(); + SP_Constraint *theSP; + bool first_sp = true; + while ((theSP = theSPs()) != nullptr) { + if (!first_sp || !first_mp) + s << ",\n"; + theSP->Print(s, flag); + first_sp = false; + } + s << "\n" << tab << tab << "]"; } - s << "\n" << tab << tab << "]\n"; + // END + s << "\n"; s << tab << "}\n"; s << "}\n"; @@ -213,32 +302,6 @@ printDomain(OPS_Stream &s, BasicModelBuilder* builder, int flag) return; } - -#if 0 - s << "Current Domain Information\n"; - s << "\tCurrent Time: " << theDomain->getCurrentTime(); - // s << "\ntCommitted Time: " << committedTime << endln; - s << "NODE DATA: NumNodes: " << theDomain->getNumNodes() << "\n"; - theNodes->Print(s, flag); - - s << "ELEMENT DATA: NumEle: " << theElements->getNumComponents() << "\n"; - theElements->Print(s, flag); - - s << "\nSP_Constraints: numConstraints: " << theSPs->getNumComponents() << "\n"; - theSPs->Print(s, flag); - - s << "\nPressure_Constraints: numConstraints: " << thePCs->getNumComponents() << "\n"; - thePCs->Print(s, flag); - - s << "\nMP_Constraints: numConstraints: " << theMPs->getNumComponents() << "\n"; - theMPs->Print(s, flag); - - s << "\nLOAD PATTERNS: numPatterns: " << theLoadPatterns->getNumComponents() << "\n\n"; - theLoadPatterns->Print(s, flag); - - s << "\nPARAMETERS: numParameters: " << theParameters->getNumComponents() << "\n\n"; - theParameters->Print(s, flag); -#endif } int @@ -292,6 +355,26 @@ TclCommand_print(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char * done = true; } + // if 'print material i j k ..' print out some nodes + else if ((strcmp(argv[currentArg], "-material") == 0)) { + currentArg++; + if (currentArg == argc) { + opserr << OpenSees::PromptValueError << "print -material .. - no tag specified\n"; + return TCL_ERROR; + } + for (int i = currentArg; i < argc; i++) { + int tag; + if (Tcl_GetInt(interp, argv[i], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "print -material failed to get integer tag: " << argv[i] + << "\n"; + return TCL_ERROR; + } + res += printRegistryObject(*((BasicModelBuilder*)clientData), tag, OPS_PRINT_PRINTMODEL_JSON, output); + } + done = true; + } + + else if ((strcmp(argv[currentArg], "-registry") == 0)) { currentArg++; if (currentArg == argc) @@ -320,7 +403,7 @@ TclCommand_print(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char * res = printAlgorithm(info.clientData, interp, argc - currentArg, argv + currentArg, *output); } else { - opserr << G3_ERROR_PROMPT << "Cannot print algorithm\n"; + opserr << OpenSees::PromptValueError << "Cannot print algorithm\n"; } done = true; } @@ -400,12 +483,12 @@ printElement(ClientData clientData, Tcl_Interp *interp, int argc, if ((strcmp(argv[0], "flag") == 0) || (strcmp(argv[0], "-flag")) == 0) { // get the specified flag if (argc < 2) { - opserr << G3_ERROR_PROMPT << "print ele no int specified \n"; + opserr << OpenSees::PromptValueError << "print ele no int specified \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[1], &flag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "print ele failed to get integer flag: \n"; - opserr << argv[eleArg] << endln; + opserr << OpenSees::PromptValueError << "print ele failed to get integer flag: \n"; + opserr << argv[eleArg] << "\n"; return TCL_ERROR; } eleArg += 2; @@ -427,8 +510,8 @@ printElement(ClientData clientData, Tcl_Interp *interp, int argc, for (int i = 0; i < numEle; ++i) { int eleTag; if (Tcl_GetInt(interp, argv[i + eleArg], &eleTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "print -ele failed to get integer: " << argv[i] - << endln; + opserr << OpenSees::PromptValueError << "print -ele failed to get integer: " << argv[i] + << "\n"; return TCL_ERROR; } (*theEle)(i) = eleTag; @@ -470,12 +553,12 @@ printNode(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const if ((strcmp(argv[0], "flag") == 0) || (strcmp(argv[0], "-flag") == 0)) { // get the specified flag if (argc <= nodeArg) { - opserr << G3_ERROR_PROMPT << "print node no int specified \n"; + opserr << OpenSees::PromptValueError << "print node no int specified \n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[1], &flag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "print node failed to get integer flag: \n"; - opserr << argv[nodeArg] << endln; + opserr << OpenSees::PromptValueError << "print node failed to get integer flag: \n"; + opserr << argv[nodeArg] << "\n"; return TCL_ERROR; } nodeArg += 2; @@ -498,7 +581,7 @@ printNode(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const for (int i = 0; i < numNodes; ++i) { int nodeTag; if (Tcl_GetInt(interp, argv[nodeArg], &nodeTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "print node failed to get integer: " << argv[nodeArg] + opserr << OpenSees::PromptValueError << "print node failed to get integer: " << argv[nodeArg] << "\n"; return TCL_ERROR; } @@ -537,7 +620,7 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, bool hasLinear = false; bool hasTri3 = false; bool hasQuad4 = false; - bool hasQuad8 = false; +//bool hasQuad8 = false; bool hasQuad9 = false; bool hasBrick = false; int startEle = 1; @@ -548,7 +631,7 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, FileStream outputFile; if (argc < 2) { - opserr << G3_ERROR_PROMPT << "printGID fileName? - no filename supplied\n"; + opserr << OpenSees::PromptValueError << "printGID fileName? - no filename supplied\n"; return TCL_ERROR; } openMode mode = openMode::OVERWRITE; @@ -561,12 +644,12 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, eleRange = 1; if (Tcl_GetInt(interp, argv[i + 1], &startEle) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "print node failed to get integer: " << argv[i + 1] + opserr << OpenSees::PromptValueError << "print node failed to get integer: " << argv[i + 1] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[i + 2], &endEle) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "print node failed to get integer: " << argv[i + 2] + opserr << OpenSees::PromptValueError << "print node failed to get integer: " << argv[i + 2] << "\n"; return TCL_ERROR; } @@ -575,7 +658,7 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, } if (outputFile.setFile(argv[1], mode) < 0) { - opserr << G3_ERROR_PROMPT << "printGID " << argv[1] << " failed to set the file\n"; + opserr << OpenSees::PromptValueError << "printGID " << argv[1] << " failed to set the file\n"; return TCL_ERROR; } @@ -603,7 +686,7 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, if (strcmp(theElement->getClassType(), "Brick") == 0) { hasBrick = true; } else { - hasQuad8 = true; + ;// hasQuad8 = true; } } } @@ -632,12 +715,12 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, for (int ii = l_tmp; ii < 3; ii++) { outputFile << 0.0 << "\t"; } - outputFile << endln; + outputFile << "\n"; } - outputFile << "End coordinates" << endln << endln; + outputFile << "End coordinates" << endln << "\n"; // Print elements connectivity - outputFile << "Elements" << endln; + outputFile << "Elements" << "\n"; ElementIter &theElements = the_domain->getElements(); Element *theElement; while ((theElement = theElements()) != 0) { @@ -658,11 +741,11 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, for (int i = 0; i < nNode; ++i) { outputFile << tagNodes(i) << "\t"; } - outputFile << endln; + outputFile << "\n"; } } } - outputFile << "End elements" << endln; + outputFile << "End elements" << "\n"; } // // **** Quadrilateral Elements - 4 Nodes @@ -670,18 +753,18 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, if (hasQuad4 == 1) { // Print HEADER outputFile << "MESH \"4NMESH\" dimension 3 ElemType Quadrilateral Nnode 4" - << endln; - outputFile << "#color 0 255 0" << endln << endln; + << "\n"; + outputFile << "#color 0 255 0" << endln << "\n"; // Print node coordinates - outputFile << "Coordinates" << endln; + outputFile << "Coordinates" << "\n"; NodeIter &theNodes = the_domain->getNodes(); Node *theNode; while ((theNode = theNodes()) != 0) { int tag = theNode->getTag(); const Vector &crds = theNode->getCrds(); // outputFile << tag << "\t\t" << crds(0) << "\t" << crds(1) << "\t" << - // crds(2) << endln; + // crds(2) << "\n"; int l_tmp = crds.Size(); outputFile << tag << "\t\t"; for (int ii = 0; ii < l_tmp; ii++) { @@ -690,12 +773,12 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, for (int ii = l_tmp; ii < 3; ii++) { outputFile << 0.0 << "\t"; } - outputFile << endln; + outputFile << "\n"; } - outputFile << "End coordinates" << endln << endln; + outputFile << "End coordinates" << endln << "\n"; // Print elements connectivity - outputFile << "Elements" << endln; + outputFile << "Elements" << "\n"; ElementIter &theElements = the_domain->getElements(); Element *theElement; while ((theElement = theElements()) != 0) { @@ -717,11 +800,11 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, for (int i = 0; i < nNode; ++i) { outputFile << tagNodes(i) << "\t"; } - outputFile << endln; + outputFile << "\n"; } } } - outputFile << "End elements" << endln; + outputFile << "End elements" << "\n"; } // // **** Triangular Elements - 3 Nodes @@ -729,18 +812,18 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, if (hasTri3 == 1) { // Print HEADER outputFile << "MESH \"3NMESH\" dimension 3 ElemType Triangle Nnode 3" - << endln; - outputFile << "#color 0 255 0" << endln << endln; + << "\n"; + outputFile << "#color 0 255 0" << endln << "\n"; // Print node coordinates - outputFile << "Coordinates" << endln; + outputFile << "Coordinates" << "\n"; NodeIter &theNodes = the_domain->getNodes(); Node *theNode; while ((theNode = theNodes()) != 0) { int tag = theNode->getTag(); const Vector &crds = theNode->getCrds(); // outputFile << tag << "\t\t" << crds(0) << "\t" << crds(1) << "\t" << - // crds(2) << endln; + // crds(2) << "\n"; int l_tmp = crds.Size(); outputFile << tag << "\t\t"; for (int ii = 0; ii < l_tmp; ii++) { @@ -749,12 +832,12 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, for (int ii = l_tmp; ii < 3; ii++) { outputFile << 0.0 << "\t"; } - outputFile << endln; + outputFile << "\n"; } - outputFile << "End coordinates" << endln << endln; + outputFile << "End coordinates" << endln << "\n"; // Print elements connectivity - outputFile << "Elements" << endln; + outputFile << "Elements" << "\n"; ElementIter &theElements = the_domain->getElements(); Element *theElement; while ((theElement = theElements()) != 0) { @@ -776,11 +859,11 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, for (int i = 0; i < nNode; ++i) { outputFile << tagNodes(i) << "\t"; } - outputFile << endln; + outputFile << "\n"; } } } - outputFile << "End elements" << endln; + outputFile << "End elements" << "\n"; } // // **** Quadrilateral Elements - 9 Nodes @@ -788,11 +871,11 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, if (hasQuad9 == 1) { // Print HEADER outputFile << "MESH \"9NMESH\" dimension 3 ElemType Linear Nnode 9" - << endln; - outputFile << "#color 0 255 0" << endln << endln; + << "\n"; + outputFile << "#color 0 255 0" << endln << "\n"; // Print node coordinates - outputFile << "Coordinates" << endln; + outputFile << "Coordinates" << "\n"; NodeIter &theNodes = the_domain->getNodes(); Node *theNode; while ((theNode = theNodes()) != 0) { @@ -807,12 +890,12 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, for (int ii = l_tmp; ii < 3; ii++) { outputFile << 0.0 << "\t"; } - outputFile << endln; + outputFile << "\n"; } - outputFile << "End coordinates" << endln << endln; + outputFile << "End coordinates" << endln << "\n"; // Print elements connectivity - outputFile << "Elements" << endln; + outputFile << "Elements" << "\n"; ElementIter &theElements = the_domain->getElements(); Element *theElement; while ((theElement = theElements()) != 0) { @@ -834,11 +917,11 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, for (int i = 0; i < nNode; ++i) { outputFile << tagNodes(i) << "\t"; } - outputFile << endln; + outputFile << "\n"; } } } - outputFile << "End elements" << endln; + outputFile << "End elements" << "\n"; } // // **** Hexahedra Elements - 8 Nodes @@ -846,11 +929,11 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, if (hasBrick == 1) { // Print HEADER outputFile << "MESH \"8NMESH\" dimension 3 ElemType Hexahedra Nnode 8" - << endln; - outputFile << "#color 255 0 0" << endln << endln; + << "\n"; + outputFile << "#color 255 0 0" << endln << "\n"; // Print node coordinates - outputFile << "Coordinates" << endln; + outputFile << "Coordinates" << "\n"; NodeIter &theNodes = the_domain->getNodes(); Node *theNode; @@ -858,7 +941,7 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, int tag = theNode->getTag(); const Vector &crds = theNode->getCrds(); // outputFile << tag << "\t\t" << crds(0) << "\t" << crds(1) << "\t" << - // crds(2) << endln; + // crds(2) << "\n"; int l_tmp = crds.Size(); outputFile << tag << "\t\t"; for (int ii = 0; ii < l_tmp; ii++) { @@ -867,12 +950,12 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, for (int ii = l_tmp; ii < 3; ii++) { outputFile << 0.0 << "\t"; } - outputFile << endln; + outputFile << "\n"; } - outputFile << "End coordinates" << endln << endln; + outputFile << "End coordinates" << endln << "\n"; // Print elements connectivity - outputFile << "Elements" << endln; + outputFile << "Elements" << "\n"; ElementIter &theElements = the_domain->getElements(); Element *theElement; while ((theElement = theElements()) != 0) { @@ -894,11 +977,11 @@ printModelGID(ClientData clientData, Tcl_Interp *interp, int argc, for (int i = 0; i < nNode; ++i) { outputFile << tagNodes(i) << "\t"; } - outputFile << endln; + outputFile << "\n"; } } } - outputFile << "End elements" << endln; + outputFile << "End elements" << "\n"; } outputFile.close(); diff --git a/SRC/runtime/commands/modeling/section.cpp b/SRC/runtime/commands/modeling/section.cpp index be7247a63b..8e83cfca3f 100644 --- a/SRC/runtime/commands/modeling/section.cpp +++ b/SRC/runtime/commands/modeling/section.cpp @@ -1,40 +1,53 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// // Description: This file contains the function invoked when the user invokes // the section command in the interpreter. +//===----------------------------------------------------------------------===// +// +// Membrane nxx nyy nxy +// MembranePlate nxx nyy nxy mxx myy mxy vxz vyz // // Written: rms, mhs, cmp // Created: 07/99 // +#include #include -#include -#include -#include -#include -#include - #include #include #include +#include +#include +#include +#include +#include +#include + #include +#include + +using namespace OpenSees; extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, Tcl_Interp *interp, int cArg, int mArg, TCL_Char ** const argv, Domain *domain); +#include +#include #include #include -#include -#include -#include -#include -#include -// #include #include #include #include @@ -43,41 +56,26 @@ extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, #include #include #include +#include #include -//#include - - -#include // Yuli Huang & Xinzheng Lu - -#include -#include -#include // SectionBuilder #include #include -#include #include #include -#include -#include +#include // #include #include #include -//--- Adding Thermo-mechanical Sections:[BEGIN] by UoE OpenSees Group ---// #include #include //Added by L.Jiang [SIF] 2017 -#include //Added by Liming, [SIF] 2017 -#include //Added by Liming, [SIF] 2017 -//--- Adding Thermo-mechanical Sections: [END] by UoE OpenSees Group ---// //#include -extern OPS_Routine OPS_ElasticSection; -extern OPS_Routine OPS_ElasticWarpingShearSection2d; // extern OPS_Routine OPS_ElasticTubeSection3d; extern OPS_Routine OPS_UniaxialSection; extern OPS_Routine OPS_ParallelSection; @@ -94,6 +92,10 @@ Tcl_CmdProc TclCommand_addFiberSection; Tcl_CmdProc TclCommand_addFiberIntSection; Tcl_CmdProc TclCommand_addUCFiberSection; Tcl_CmdProc TclCommand_addSectionAggregator; +Tcl_CmdProc TclCommand_addPlaneSection; +Tcl_CmdProc TclCommand_addElasticShellSection; +Tcl_CmdProc TclCommand_addUniaxialSection; +Tcl_CmdProc TclCommand_ShellSection; // extern OPS_Routine OPS_WFSection2d; // extern OPS_Routine OPS_RCCircularSection; @@ -105,6 +107,116 @@ Tcl_CmdProc TclCommand_addSectionAggregator; SectionForceDeformation * TclBasicBuilderYS_SectionCommand(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv); + +#include +#include +#include +int +TclCommand_addTrussSection(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + + enum class Positions { + Tag, MaterialTag, Area, + EndRequired, End + }; + + ArgumentTracker tracker; + std::set positional; + int tag; + int matTag; + double area; + + for (int i=2; i= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetInt(interp, argv[i], &matTag) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::MaterialTag); + } + else if (strcmp(argv[i], "-area") == 0) { + if (++i >= argc) { + opserr << "Missing value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + if (Tcl_GetDouble(interp, argv[i], &area) != TCL_OK) { + opserr << "Invalid value for option " << argv[i-1] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Area); + } + else + positional.insert(i); + } + + // + // Positional arguments + // + for (int i: positional) { + if (tracker.current() == Positions::EndRequired) + tracker.increment(); + + switch (tracker.current()) { + case Positions::Tag : + if (Tcl_GetInt(interp, argv[i], &tag) != TCL_OK) { + opserr << "Invalid tag " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Tag); + break; + + case Positions::MaterialTag: + if (Tcl_GetInt(interp, argv[i], &matTag) != TCL_OK) { + opserr << "Invalid value for material tag " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::MaterialTag); + break; + + case Positions::Area: + if (Tcl_GetDouble(interp, argv[i], &area) != TCL_OK) { + opserr << "Invalid value for area " << argv[i] << "\n"; + return TCL_ERROR; + } + tracker.consume(Positions::Area); + break; + + case Positions::EndRequired: + case Positions::End: + break; + } + } + + // + if (tracker.current() < Positions::EndRequired) { + opserr << "Missing required arguments: "; + if (tracker.contains(Positions::Tag)) + opserr << "tag "; + if (tracker.contains(Positions::MaterialTag)) + opserr << "material "; + if (tracker.contains(Positions::Area)) + opserr << "area "; + opserr << "\n"; + return TCL_ERROR; + } + + BasicModelBuilder *builder = static_cast(clientData); + + UniaxialMaterial *material = builder->getTypedObject(matTag); + if (material == nullptr) { + return TCL_ERROR; + } + auto fiber_section = new FrameFiberSection3d(tag, 1, nullptr, true, 0.0, 0); + fiber_section->addFiber(*material, area, 0.0, 0.0); + return builder->addTaggedObject(*fiber_section); +} + + int TclCommand_addSection(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) @@ -116,8 +228,7 @@ TclCommand_addSection(ClientData clientData, Tcl_Interp *interp, // Make sure there is a minimum number of arguments if (argc < 3) { - opserr << G3_ERROR_PROMPT << "insufficient number of section arguments\n"; - opserr << "Want: section type? tag? " << endln; + opserr << OpenSees::PromptValueError << "insufficient number of arguments\n"; return TCL_ERROR; } @@ -130,9 +241,13 @@ TclCommand_addSection(ClientData clientData, Tcl_Interp *interp, if (strcmp(argv[1], "Fiber") == 0 || strcmp(argv[1], "fiberSec") == 0 || + strcmp(argv[1], "FiberSec") == 0 || strcmp(argv[1], "FiberFrame") == 0 || strcmp(argv[1], "FrameFiber") == 0 || + strcmp(argv[1], "AxialFiber") == 0 || strcmp(argv[1], "FiberSection") == 0 || + // + strcmp(argv[1], "ShearFiber") == 0 || // Shear strcmp(argv[1], "NDFiber") == 0 || strcmp(argv[1], "NDFiberWarping") == 0 || @@ -145,66 +260,49 @@ TclCommand_addSection(ClientData clientData, Tcl_Interp *interp, return TclCommand_addFiberSection(clientData, interp, argc, argv); + + else if (strcmp(argv[1], "Truss") == 0 || + strcmp(argv[1], "TrussSection") == 0 || + strcmp(argv[1], "TrussSection2d") == 0 || + strcmp(argv[1], "TrussSection3d") == 0) { + return TclCommand_addTrussSection(clientData, interp, argc, argv); + } + + + else if (strcmp(argv[1], "FiberInt") == 0) { // TODO + // return TclCommand_addFiberIntSection(clientData, interp, argc, argv); opserr << "FiberInt is currently broken\n"; return TCL_ERROR; - // return TclCommand_addFiberIntSection(clientData, interp, argc, argv); } + else if ((strcmp(argv[1], "PlaneStrain") == 0) || + (strcmp(argv[1], "PlaneStress") == 0)) + return TclCommand_addPlaneSection(clientData, interp, argc, argv); + else if (strcmp(argv[1], "UCFiber") == 0) return TclCommand_addUCFiberSection(clientData, interp, argc, argv); - else if (strcmp(argv[1], "Parallel") == 0) { - SectionForceDeformation *theSection = - (SectionForceDeformation*)OPS_ParallelSection(rt, argc, argv); - - if (theSection == nullptr || builder->addTaggedObject(*theSection) < 0) { - if (theSection != nullptr) - delete theSection; - return TCL_ERROR; - } else - return TCL_OK; - } - - else if ((strcmp(argv[1], "FrameElastic") == 0) || - (strcmp(argv[1], "ElasticFrame") == 0)) { + else if ((strcmp(argv[1], "Elastic") == 0) || + (strcmp(argv[1], "ElasticShear") == 0) || + (strcmp(argv[1], "ElasticWarpingShear") == 0) || + (strcmp(argv[1], "FrameElastic") == 0) || + (strcmp(argv[1], "ElasticFrame") == 0)) { return TclCommand_newElasticSection(clientData, interp, argc, argv); } - else if (strcmp(argv[1], "Elastic") == 0) { - if (getenv("SEC")) - return TclCommand_newElasticSection(clientData, interp, argc, argv); - - else { - FrameSection *theSection = (FrameSection *)OPS_ElasticSection(rt, argc, argv); - // Now add the section to the modelBuilder - if (theSection == nullptr || builder->addTaggedObject(*theSection) < 0) { - if (theSection != nullptr) - delete theSection; - return TCL_ERROR; - } else - return TCL_OK; - } + else if (strcmp(argv[1], "Generic1D") == 0 || + strcmp(argv[1], "Generic1d") == 0 || + strcmp(argv[1], "Uniaxial") == 0) { + return TclCommand_addUniaxialSection(clientData, interp, argc, argv); } - else if (strcmp(argv[1], "ElasticWarpingShear") == 0) { - FrameSection *theSection = (FrameSection *)OPS_ElasticWarpingShearSection2d(rt, argc, argv); - // Now add the section to the modelBuilder - if (theSection == nullptr || builder->addTaggedObject(*theSection) < 0) { - if (theSection != nullptr) - delete theSection; - return TCL_ERROR; - } else - return TCL_OK; - } + else if (strcmp(argv[1], "Parallel") == 0) { + SectionForceDeformation *theSection = + (SectionForceDeformation*)OPS_ParallelSection(rt, argc, argv); - else if (strcmp(argv[1], "Generic1D") == 0 || - strcmp(argv[1], "Generic1d") == 0 || - strcmp(argv[1], "Uniaxial") == 0) { - FrameSection *theSection = (FrameSection *)OPS_UniaxialSection(rt, argc, argv); - // Now add the section to the modelBuilder - if (theSection == nullptr || builder->addTaggedObject(*theSection) < 0) { + if (theSection == nullptr || builder->addTaggedObject(*theSection) < 0) { if (theSection != nullptr) delete theSection; return TCL_ERROR; @@ -235,43 +333,6 @@ TclCommand_addSection(ClientData clientData, Tcl_Interp *interp, opserr << "WFSection2d has been removed; use the from_aisc utility to " << "generate AISC sections from Python.\n"; return TCL_ERROR; -#if 0 - void *theMat = OPS_WFSection2d(rt, argc, argv); - if (theMat != 0) - theSection = (SectionForceDeformation *)theMat; - else - return TCL_ERROR; -#endif - } - - - // - // Membrane - // - else if ((strcmp(argv[1], "ReinforcedConcreteLayeredMembraneSection") == 0) || - (strcmp(argv[1], "RCLayeredMembraneSection") == 0) || - (strcmp(argv[1], "RCLMS") == 0)) { - void* theMat = OPS_ReinforcedConcreteLayeredMembraneSection(rt, argc, argv); - if (theMat != 0) - theSection = (SectionForceDeformation*)theMat; - else - return TCL_ERROR; - } - - else if ((strcmp(argv[1], "LayeredMembraneSection") == 0) || (strcmp(argv[1], "LMS") == 0)) { - void* theMat = OPS_LayeredMembraneSection(rt, argc, argv); - if (theMat != 0) - theSection = (SectionForceDeformation*)theMat; - else - return TCL_ERROR; - } - - else if (strcmp(argv[1], "ElasticMembraneSection") == 0) { - void* theMat = OPS_ElasticMembraneSection(); - if (theMat != 0) - theSection = (SectionForceDeformation*)theMat; - else - return TCL_ERROR; } else if (strcmp(argv[1], "AddDeformation") == 0 || @@ -280,361 +341,53 @@ TclCommand_addSection(ClientData clientData, Tcl_Interp *interp, return TclCommand_addSectionAggregator(clientData, interp, argc, argv); - else if (strcmp(argv[1], "ElasticPlateSection") == 0) { - - if (argc < 5) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; - opserr << "Want: section ElasticPlateSection tag? E? nu? h? " << endln; - return TCL_ERROR; - } - - int tag; - double E, nu, h; - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid section ElasticPlateSection tag" << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid E" << endln; - opserr << "ElasticPlateSection section: " << tag << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[4], &nu) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nu" << endln; - opserr << "ElasticPlateSection section: " << tag << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[5], &h) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid h" << endln; - opserr << "ElasticPlateSection section: " << tag << endln; - return TCL_ERROR; - } - - theSection = new ElasticPlateSection(tag, E, nu, h); - // Now add the material to the modelBuilder - if (builder->addTaggedObject(*theSection) < 0) { - delete theSection; // invoke the material objects destructor, otherwise mem leak - return TCL_ERROR; - } else - return TCL_OK; - } - - else if (strcmp(argv[1], "ElasticMembranePlateSection") == 0) { - if (argc < 5) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; - opserr << "Want: section ElasticMembranePlateSection tag? E? nu? h? " - " " - << endln; - return TCL_ERROR; - } - - int tag; - double E, nu, h; - double rho = 0.0; - double Ep_mod = 1.0; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid section ElasticMembranePlateSection tag" - << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid E" << endln; - opserr << "ElasticMembranePlateSection section: " << tag << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[4], &nu) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nu" << endln; - opserr << "ElasticMembranePlateSection section: " << tag << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[5], &h) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid h" << endln; - opserr << "ElasticMembranePlateSection section: " << tag << endln; - return TCL_ERROR; - } - - if (argc > 6 && Tcl_GetDouble(interp, argv[6], &rho) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid rho" << endln; - opserr << "ElasticMembranePlateSection section: " << tag << endln; - return TCL_ERROR; - } - - if (argc > 7 && Tcl_GetDouble(interp, argv[7], &Ep_mod) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Ep_mod" << endln; - opserr << "ElasticMembranePlateSection section: " << tag << endln; - return TCL_ERROR; - } - - theSection = new ElasticMembranePlateSection(tag, E, nu, h, rho, Ep_mod); - } - - else if (strcmp(argv[1], "PlateFiber") == 0) { - if (argc < 5) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; - opserr << "Want: section PlateFiber tag? matTag? h? " << endln; - return TCL_ERROR; - } - - double h; - int tag, matTag; - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid section PlateFiber tag" << endln; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag" << endln; - opserr << "PlateFiber section: " << matTag << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[4], &h) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid h" << endln; - opserr << "PlateFiber section: " << tag << endln; - return TCL_ERROR; - } - - NDMaterial *theMaterial = builder->getTypedObject(matTag); - if (theMaterial == nullptr) { - opserr << G3_ERROR_PROMPT << "nD material does not exist\n"; - opserr << "nD material: " << matTag; - opserr << "\nPlateFiber section: " << tag << endln; - return TCL_ERROR; - } - - theSection = new MembranePlateFiberSection(tag, h, *theMaterial); - // Now add the material to the modelBuilder - if (builder->addTaggedObject(*theSection) < 0) { - delete theSection; - return TCL_ERROR; - } else - return TCL_OK; - } - - // start Yuli Huang & Xinzheng Lu LayeredShellFiberSection - else if (strcmp(argv[1], "LayeredShell") == 0) { - if (argc < 6) { - opserr << G3_ERROR_PROMPT << "insufficient arguments" << endln; - opserr << "Want: section LayeredShell tag? nLayers? matTag1? h1? ... " - "matTagn? hn? " - << endln; - return TCL_ERROR; - } - - int tag, nLayers, matTag; - double h, *thickness; - NDMaterial **theMats; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid section LayeredShell tag" << endln; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &nLayers) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nLayers" << endln; - opserr << "LayeredShell section: " << tag << endln; - return TCL_ERROR; - } - - if (nLayers < 3) { - opserr << "ERROR number of layers must be larger than 2" << endln; - opserr << "LayeredShell section: " << tag << endln; - return TCL_ERROR; - } - - theMats = new NDMaterial *[nLayers]; - thickness = new double[nLayers]; - - if (argc < 3+2*nLayers) { - opserr << G3_ERROR_PROMPT << "Must provide " << 2*nLayers << " layers\n"; - return TCL_ERROR; - } - - for (int iLayer = 0; iLayer < nLayers; iLayer++) { - - if (Tcl_GetInt(interp, argv[4 + 2 * iLayer], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag" << endln; - opserr << "LayeredShell section: " << tag << endln; - return TCL_ERROR; - } - - theMats[iLayer] = builder->getTypedObject(matTag); - if (theMats[iLayer] == 0) { - opserr << G3_ERROR_PROMPT << "nD material does not exist" << endln; - opserr << "nD material: " << matTag; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[5 + 2 * iLayer], &h) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid h" << endln; - opserr << "LayeredShell section: " << tag << endln; - return TCL_ERROR; - } - - if (h < 0) { - opserr << G3_ERROR_PROMPT << "invalid h" << endln; - opserr << "PlateFiber section: " << tag << endln; - return TCL_ERROR; - } - - thickness[iLayer] = h; - } - - theSection = new LayeredShellFiberSection(tag, nLayers, thickness, theMats); - if (thickness != nullptr) - delete[] thickness; - if (theMats != 0) - delete[] theMats; - - // Now add the material to the modelBuilder - if (builder->addTaggedObject(*theSection) < 0) { - delete theSection; - return TCL_ERROR; - } else - return TCL_OK; + // + // Shell + // + else if ((strcmp(argv[1], "ElasticMembranePlateSection") == 0) || + (strcmp(argv[1], "ElasticShell") == 0) || + (strcmp(argv[1], "ElasticPlateSection") == 0) || + (strcmp(argv[1], "ElasticMembraneSection") == 0)) { + return TclCommand_addElasticShellSection(clientData, interp, argc, argv); } - // end Yuli Huang & Xinzheng Lu LayeredShellFiberSection - //-----Thermo-mechanical shell sections added by L.Jiang [SIF] - else if (strcmp(argv[1], "PlateFiberThermal") == 0) { - if (argc < 5) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; - opserr << "Want: section PlateFiberThermal tag? matTag? h? " << endln; - return TCL_ERROR; - } - - int tag, matTag; - double h; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid section PlateFiberThermal tag" << endln; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag" << endln; - opserr << "PlateFiberThermal section: " << matTag << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[4], &h) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid h" << endln; - opserr << "PlateFiberThermal section: " << tag << endln; - return TCL_ERROR; - } - - NDMaterial *theMaterial = builder->getTypedObject(matTag); - if (theMaterial == nullptr) { - opserr << G3_ERROR_PROMPT << "nD material does not exist\n"; - opserr << "nD material: " << matTag; - opserr << "\nPlateFiberThermal section: " << tag << endln; - return TCL_ERROR; - } - - theSection = new MembranePlateFiberSectionThermal(tag, h, *theMaterial); - // Now add the material to the modelBuilder - if (builder->addTaggedObject(*theSection) < 0) { - delete theSection; // invoke the material objects destructor, otherwise mem leak - return TCL_ERROR; - } else - return TCL_OK; + else if ((strcmp(argv[1], "LayeredShell") == 0) || + (strcmp(argv[1], "LayeredShellThermal") == 0) || + (strcmp(argv[1], "PlateFiber") == 0) || + (strcmp(argv[1], "PlateFiberThermal") == 0)) { + return TclCommand_ShellSection(clientData, interp, argc, argv); } - // LayeredShellFiberSectionThermal based on the - // LayeredShellFiberSectionThermal by Yuli Huang & Xinzheng Lu - else if (strcmp(argv[1], "LayeredShellThermal") == 0) { - if (argc < 6) { - opserr << G3_ERROR_PROMPT << "insufficient arguments" << endln; - opserr << "Want: section LayeredShellThermal tag? nLayers? matTag1? h1? " - "... matTagn? hn? " - << endln; - return TCL_ERROR; - } - - int tag, nLayers, matTag; - double h, *thickness; - NDMaterial **theMats; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid section LayeredShellThermal tag" << endln; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &nLayers) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nLayers" << endln; - opserr << "LayeredShellThermal section: " << tag << endln; - return TCL_ERROR; - } - - if (nLayers < 3) { - opserr << "ERROR number of layers must be larger than 2" << endln; - opserr << "LayeredShellThermal section: " << tag << endln; - return TCL_ERROR; - } - - theMats = new NDMaterial *[nLayers]; - thickness = new double[nLayers]; - - for (int iLayer = 0; iLayer < nLayers; iLayer++) { - if (Tcl_GetInt(interp, argv[4 + 2 * iLayer], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag" << endln; - opserr << "LayeredShellThermal section: " << tag << endln; - return TCL_ERROR; - } - - theMats[iLayer] = builder->getTypedObject(matTag); - if (theMats[iLayer] == 0) { - opserr << G3_ERROR_PROMPT << "nD material does not exist" << endln; - ; - opserr << "nD material: " << matTag; - opserr << "LayeredShellThermal section: " << tag << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[5 + 2 * iLayer], &h) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid h" << endln; - opserr << "LayeredShellThermal section: " << tag << endln; - return TCL_ERROR; - } - - if (h < 0) { - opserr << G3_ERROR_PROMPT << "invalid h" << endln; - opserr << "LayeredShellThermal section: " << tag << endln; - return TCL_ERROR; - } - - thickness[iLayer] = h; - } - - theSection = - new LayeredShellFiberSectionThermal(tag, nLayers, thickness, theMats); - if (thickness != 0) - delete[] thickness; - if (theMats != 0) - delete[] theMats; + // + // Membrane + // + else if ((strcmp(argv[1], "ReinforcedConcreteLayeredMembraneSection") == 0) || + (strcmp(argv[1], "RCLayeredMembraneSection") == 0) || + (strcmp(argv[1], "RCLMS") == 0)) { + void* theMat = OPS_ReinforcedConcreteLayeredMembraneSection(rt, argc, argv); + if (theMat != 0) + theSection = (SectionForceDeformation*)theMat; + else + return TCL_ERROR; + } - // Now add the material to the modelBuilder - if (builder->addTaggedObject(*theSection) < 0) { - delete theSection; // invoke the material objects destructor, otherwise mem leak - return TCL_ERROR; - } else - return TCL_OK; + else if ((strcmp(argv[1], "LayeredMembraneSection") == 0) || (strcmp(argv[1], "LMS") == 0)) { + void* theMat = OPS_LayeredMembraneSection(rt, argc, argv); + if (theMat != 0) + theSection = (SectionForceDeformation*)theMat; + else + return TCL_ERROR; } - // end L.Jiang [SIF] added based on LayeredShellFiberSectionThermal section + + // + // // else if (strcmp(argv[1], "Iso2spring") == 0) { if (argc < 10) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; opserr << "Want: section Iso2spring tag? tol? k1? Fy? k2? kv? hb? Pe? " - << endln; + << "\n"; return TCL_ERROR; } @@ -643,54 +396,47 @@ TclCommand_addSection(ClientData clientData, Tcl_Interp *interp, double Po = 0.0; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Iso2spring tag" << endln; + opserr << OpenSees::PromptValueError << "invalid Iso2spring tag" << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[3], &tol) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid tol\n"; - opserr << "section Iso2spring: " << tag << endln; + opserr << OpenSees::PromptValueError << "invalid tol\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &k1) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid k1\n"; - opserr << "section Iso2spring: " << tag << endln; + opserr << OpenSees::PromptValueError << "invalid k1\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &Fy) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Fy\n"; - opserr << "section Iso2spring: " << tag << endln; + opserr << OpenSees::PromptValueError << "invalid Fy\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6], &kb) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid k2\n"; - opserr << "section Iso2spring: " << tag << endln; + opserr << OpenSees::PromptValueError << "invalid k2\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[7], &kvo) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid kv\n"; - opserr << "section Iso2spring: " << tag << endln; + opserr << OpenSees::PromptValueError << "invalid kv\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8], &hb) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid hb\n"; - opserr << "section Iso2spring: " << tag << endln; + opserr << OpenSees::PromptValueError << "invalid hb\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9], &Pe) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Pe\n"; - opserr << "section Iso2spring: " << tag << endln; + opserr << OpenSees::PromptValueError << "invalid Pe\n"; return TCL_ERROR; } if (argc > 10) { if (Tcl_GetDouble(interp, argv[10], &Po) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Po\n"; - opserr << "section Iso2spring: " << tag << endln; + opserr << OpenSees::PromptValueError << "invalid Po\n"; + opserr << "section Iso2spring: " << tag << "\n"; return TCL_ERROR; } } @@ -712,13 +458,13 @@ TclCommand_addSection(ClientData clientData, Tcl_Interp *interp, // Ensure we have created the Material, out of memory if got here and no // section if (theSection == nullptr) { - opserr << G3_ERROR_PROMPT << "could not create section " << argv[1] << endln; + opserr << OpenSees::PromptValueError << "could not create section " << argv[1] << "\n"; return TCL_ERROR; } // Now add the material to the modelBuilder if (builder->addTaggedObject(*theSection) < 0) { - opserr << *theSection << endln; + opserr << *theSection << "\n"; delete theSection; // invoke the material objects destructor, otherwise mem leak return TCL_ERROR; } else @@ -747,7 +493,7 @@ findSectionBuilder(BasicModelBuilder* builder, Tcl_Interp *interp, int argc, con for (int i = 0; i(clientData); - // dimension of the structure (1d, 2d, or 3d) + // Dimension of the structure int ndm = builder->getNDM(); SectionBuilder *sbuilder = nullptr; FrameSection *section = nullptr; - // create 2d section + // Create 2d section if (ndm == 2) { if (options.isND) { - if (options.isWarping) { + if (options.isNew) { + auto sec = new FrameSolidSection3d(secTag, 30); + sbuilder = new FiberSectionBuilder<2, NDMaterial, FrameSolidSection3d>(*builder, *sec); + section = sec; + } + else if (options.isWarping) { auto sec = new NDFiberSectionWarping2d(secTag, 30, alpha); sbuilder = new FiberSectionBuilder<2, NDMaterial, NDFiberSectionWarping2d>(*builder, *sec); section = sec; - } else { + } + else { auto sec = new NDFiberSection2d(secTag, options.computeCentroid); sbuilder = new FiberSectionBuilder<2, NDMaterial, NDFiberSection2d>(*builder, *sec); section = sec; @@ -807,33 +562,55 @@ initSectionCommands(ClientData clientData, Tcl_Interp *interp, section = sec; } } - } else if (ndm == 3) { - // This function is not called when torsion is NULL and num==3 - assert(theTorsion != nullptr); + } - if (options.isND) { - auto sec = new NDFiberSection3d(secTag, - options.computeCentroid); - sbuilder = new FiberSectionBuilder<3, NDMaterial, NDFiberSection3d>(*builder, *sec); - section = sec; + else if (ndm == 3) { + if (options.isND) { + if (options.isNew) { + auto sec = new FrameSolidSection3d(secTag, 30); + sbuilder = new FiberSectionBuilder<3, NDMaterial, FrameSolidSection3d>(*builder, *sec); + section = sec; + } + else { + auto sec = new NDFiberSection3d(secTag, + options.computeCentroid); + sbuilder = new FiberSectionBuilder<3, NDMaterial, NDFiberSection3d>(*builder, *sec); + section = sec; + } } else { + + if (options.isThermal) { - auto sec = new FiberSection3dThermal(secTag, /* TODO: torsion */ - options.computeCentroid); + if (theTorsion == nullptr) { + opserr << OpenSees::PromptValueError + << "FiberThermal section requires torsion\n"; + return TCL_ERROR; + } + auto sec = new FiberSection3dThermal(secTag, 30, *theTorsion, + options.computeCentroid); sbuilder = new FiberSectionBuilder<3, UniaxialMaterial, FiberSection3dThermal>(*builder, *sec); section = sec; - } else if (options.isAsym) { + + } + else if (options.isAsym) { auto sec = new FiberSectionAsym3d(secTag, 30, theTorsion, Ys, Zs); sbuilder = new FiberSectionBuilder<3, UniaxialMaterial, FiberSectionAsym3d>(*builder, *sec); section = sec; - } else { + + } + else { if (options.isNew) { - auto sec = new FrameFiberSection3d(secTag, 30, *theTorsion, options.computeCentroid, + auto sec = new FrameFiberSection3d(secTag, 30, theTorsion, options.computeCentroid, options.density, options.use_density); sbuilder = new FiberSectionBuilder<3, UniaxialMaterial, FrameFiberSection3d>(*builder, *sec); section = sec; } else { + if (theTorsion == nullptr) { + opserr << OpenSees::PromptValueError + << "FiberThermal section requires torsion\n"; + return TCL_ERROR; + } auto sec = new FiberSection3d(secTag, 30, *theTorsion, options.computeCentroid); sbuilder = new FiberSectionBuilder<3, UniaxialMaterial, FiberSection3d>(*builder, *sec); section = sec; @@ -842,16 +619,24 @@ initSectionCommands(ClientData clientData, Tcl_Interp *interp, } } else { - opserr << G3_ERROR_PROMPT << "Model dimension (ndm = " << ndm + opserr << OpenSees::PromptValueError << "Model dimension (ndm = " << ndm << ") is incompatible with available frame elements\n"; return TCL_ERROR; } + + // In 2D truss elements still look for FrameSections if (builder->addTaggedObject(*section) < 0) { return TCL_ERROR; } + // if (ndm == 2) { + // if (builder->addTaggedObject(*section->getCopy()) < 0) { + // return TCL_ERROR; + // } + // } + if (builder->addTypedObject(secTag, sbuilder) < 0) { - opserr << G3_ERROR_PROMPT << "cannot add section\n"; + opserr << OpenSees::PromptValueError << "Faled to add section\n"; return TCL_ERROR; } @@ -887,15 +672,17 @@ TclCommand_addFiberSection(ClientData clientData, Tcl_Interp *interp, int argc, int secTag; if (Tcl_GetInt(interp, argv[2], &secTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "bad command - want: \nsection fiberSec secTag { " - "\n\tpatch \n\tlayer \n}\n"; + opserr << OpenSees::PromptValueError + << "failed to parse section tag \"" << argv[2] << "\"" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } builder->setCurrentSectionBuilder(secTag); FiberSectionConfig options; - if (strcmp(argv[1], "NDFiber") == 0) + if (strcmp(argv[1], "NDFiber") == 0 || + strcmp(argv[1], "ShearFiber") == 0) options.isND = true; if (strcmp(argv[1], "NDFiberWarping") == 0) { @@ -903,7 +690,10 @@ TclCommand_addFiberSection(ClientData clientData, Tcl_Interp *interp, int argc, options.isWarping = true; } else if (strcmp(argv[1], "FrameFiber") == 0 || - strcmp(argv[1], "FiberFrame") == 0) + strcmp(argv[1], "FiberFrame") == 0 || + strcmp(argv[1], "AxialFiber") == 0 || + strcmp(argv[1], "ShearFiber") == 0 + ) options.isNew = true; else if (strcmp(argv[1], "FiberThermal") == 0 || @@ -935,11 +725,11 @@ TclCommand_addFiberSection(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(argv[iarg], "-mass") == 0 && iarg + 1 < argc) { if (argc < iarg + 2) { - opserr << G3_ERROR_PROMPT << "not enough -mass args need -mass mass?\n"; + opserr << OpenSees::PromptValueError << "not enough -mass args need -mass mass?\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[iarg + 1], &options.density) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid density"; + opserr << OpenSees::PromptValueError << "invalid density"; return TCL_ERROR; } options.use_density = true; @@ -949,7 +739,7 @@ TclCommand_addFiberSection(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(argv[iarg], "-GJ") == 0 && iarg + 1 < argc) { if (Tcl_GetDouble(interp, argv[iarg + 1], &GJ) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid GJ"; + opserr << OpenSees::PromptValueError << "invalid GJ"; return TCL_ERROR; } deleteTorsion = true; @@ -961,15 +751,15 @@ TclCommand_addFiberSection(ClientData clientData, Tcl_Interp *interp, int argc, else if (strcmp(argv[iarg], "-torsion") == 0 && iarg + 1 < argc) { int torsionTag = 0; if (Tcl_GetInt(interp, argv[iarg + 1], &torsionTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid torsionTag"; + opserr << OpenSees::PromptValueError << "invalid torsionTag"; return TCL_ERROR; } torsion = builder->getTypedObject(torsionTag); if (torsion == nullptr) { - opserr << G3_ERROR_PROMPT << "uniaxial material does not exist\n"; + opserr << OpenSees::PromptValueError << "uniaxial material does not exist\n"; opserr << "uniaxial material: " << torsionTag; - opserr << "\nFiberSection3d: " << secTag << endln; + opserr << "\nFiberSection3d: " << secTag << "\n"; return TCL_ERROR; } @@ -978,15 +768,15 @@ TclCommand_addFiberSection(ClientData clientData, Tcl_Interp *interp, int argc, else if (strstr(argv[1], "Asym") != nullptr && !shearParsed) { if (iarg + 1 >= argc) { - opserr << G3_ERROR_PROMPT << "Asym sections require shear center before fiber block.\n"; + opserr << OpenSees::PromptValueError << "Asym sections require shear center before fiber block.\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[iarg], &Ys) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Ys"; + opserr << OpenSees::PromptValueError << "invalid Ys"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[iarg+1], &Zs) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Zs"; + opserr << OpenSees::PromptValueError << "invalid Zs"; return TCL_ERROR; } shearParsed = true; @@ -995,21 +785,20 @@ TclCommand_addFiberSection(ClientData clientData, Tcl_Interp *interp, int argc, else { // braces; skip and handle later -// iarg += 1; break; } } - if (torsion == nullptr && ndm == 3) { - opserr << G3_ERROR_PROMPT << "- no torsion specified for 3D fiber section, use -GJ or " + if (torsion == nullptr && ndm == 3 && !options.isNew) { + opserr << OpenSees::PromptValueError + << "missing required torsion for 3D fiber section, use -GJ or " "-torsion\n"; - opserr << "\nFiberSection3d: " << secTag << endln; return TCL_ERROR; } - // initialize the fiber section (for building) // TODO, alpha + // initialize the fiber section (for building) // TODO, pass alpha if (initSectionCommands(clientData, interp, secTag, torsion, Ys, Zs, 1.0, options) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "error constructing the section\n"; + opserr << OpenSees::PromptValueError << "error constructing the section\n"; return TCL_ERROR; } @@ -1040,21 +829,21 @@ TclCommand_addFiberIntSection(ClientData clientData, Tcl_Interp *interp, int secTag; if (Tcl_GetInt(interp, argv[2], &secTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "bad command - want: \nsection fiberInt secTag -GJ { " + opserr << OpenSees::PromptValueError << "bad command - want: \nsection fiberInt secTag -GJ { " "\n\tpatch \n\tlayer \n}\n"; return TCL_ERROR; } builder->setCurrentSectionBuilder(secTag); - - int brace = 3; // Start of recursive parse + // + int brace = 3; double GJ = 1.0; bool deleteTorsion = false; - UniaxialMaterial *torsion = 0; + UniaxialMaterial *torsion = nullptr; if (strcmp(argv[3], "-GJ") == 0) { if (Tcl_GetDouble(interp, argv[4], &GJ) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid GJ"; + opserr << OpenSees::PromptValueError << "invalid GJ\n"; return TCL_ERROR; } torsion = new ElasticMaterial(0, GJ); // Is this gonna be a memory leak? MHS @@ -1064,17 +853,13 @@ TclCommand_addFiberIntSection(ClientData clientData, Tcl_Interp *interp, int torsionTag = 0; if (strcmp(argv[3], "-torsion") == 0) { if (Tcl_GetInt(interp, argv[4], &torsionTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid torsionTag"; + opserr << OpenSees::PromptValueError << "invalid torsionTag\n"; return TCL_ERROR; } torsion = builder->getTypedObject(torsionTag); - if (torsion == 0) { - opserr << G3_ERROR_PROMPT << "uniaxial material does not exist\n"; - opserr << "uniaxial material: " << torsionTag; - opserr << "\nFiberSection3d: " << secTag << endln; + if (torsion == 0) return TCL_ERROR; - } brace = 5; } @@ -1085,68 +870,51 @@ TclCommand_addFiberIntSection(ClientData clientData, Tcl_Interp *interp, if (strcmp(argv[3], "-NStrip") == 0) { if (Tcl_GetInt(interp, argv[4], &NStrip1) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid NStrip1"; + opserr << OpenSees::PromptValueError << "invalid NStrip1\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &t1) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid t1"; + opserr << OpenSees::PromptValueError << "invalid t1"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[6], &NStrip2) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid NStrip2"; + opserr << OpenSees::PromptValueError << "invalid NStrip2"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[7], &t2) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid t2"; + opserr << OpenSees::PromptValueError << "invalid t2"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[8], &NStrip3) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid NStrip3"; + opserr << OpenSees::PromptValueError << "invalid NStrip3"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9], &t3) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid t3"; + opserr << OpenSees::PromptValueError << "invalid t3"; return TCL_ERROR; } brace = 10; // may be 5 } -#if 0 - // init the fiber section (for building) // TODO, alpha - if (initSectionCommands(clientData, interp, secTag, *torsion, Ys, Zs, 1.0) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "- error constructing the section\n"; - return TCL_ERROR; - } -#endif - // parse the information inside the braces (patches and reinforcing layers) if (Tcl_Eval(interp, argv[brace]) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "- error reading information in { } \n"; + opserr << OpenSees::PromptValueError << "- error reading information in { } \n"; return TCL_ERROR; } - if (NDM == 3 && torsion == 0) { - opserr << G3_ERROR_PROMPT << "- no torsion specified for 3D fiber section, use -GJ or " + if (NDM == 3 && torsion == nullptr) { + opserr << OpenSees::PromptValueError << "- no torsion specified for 3D fiber section, use -GJ or " "-torsion\n"; - opserr << "\nFiberSectionInt3d: " << secTag << endln; - return TCL_ERROR; - } - -#if 0 // TODO !!! - // build the fiber section (for analysis) - if (buildSectionInt(clientData, interp, secTag, *torsion, NStrip1, t1, - NStrip2, t2, NStrip3, t3) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "- error constructing the section\n"; + opserr << "\nFiberSectionInt3d: " << secTag << "\n"; return TCL_ERROR; } -#endif if (deleteTorsion) delete torsion; @@ -1168,14 +936,14 @@ TclCommand_addPatch(ClientData clientData, SectionBuilder* fiberSectionRepr = findSectionBuilder(builder, interp, argc, argv); if (fiberSectionRepr == nullptr) { - opserr << G3_ERROR_PROMPT << "cannot retrieve section\n"; + opserr << OpenSees::PromptValueError << "cannot retrieve section\n"; return TCL_ERROR; } // make sure at least one other argument to contain patch type if (argc < 2) { - opserr << G3_ERROR_PROMPT << "need to specify a patch type \n"; + opserr << OpenSees::PromptValueError << "need to specify a patch type \n"; return TCL_ERROR; } @@ -1183,10 +951,10 @@ TclCommand_addPatch(ClientData clientData, if (strcmp(argv[1], "quad") == 0 || strcmp(argv[1], "quadr") == 0) { int numSubdivIJ, numSubdivJK, matTag; double vertexCoordY, vertexCoordZ; - Matrix vertexCoords(4, 2); + MatrixND<4,2> vertexCoords{}; if (argc < 13) { - opserr << G3_ERROR_PROMPT << "invalid number of parameters: patch quad matTag " + opserr << OpenSees::PromptValueError << "invalid number of parameters: patch quad matTag " "numSubdivIJ numSubdivJK yVertI zVertI yVertJ zVertJ yVertK " "zVertK yVertL zVertL\n"; return TCL_ERROR; @@ -1195,21 +963,21 @@ TclCommand_addPatch(ClientData clientData, int argi = 2; if (Tcl_GetInt(interp, argv[argi++], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag: patch quad matTag numSubdivIJ " + opserr << OpenSees::PromptValueError << "invalid matTag: patch quad matTag numSubdivIJ " "numSubdivJK yVertI zVertI yVertJ zVertJ yVertK zVertK yVertL " "zVertL\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[argi++], &numSubdivIJ) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid numSubdivIJ: patch quad matTag numSubdivIJ " + opserr << OpenSees::PromptValueError << "invalid numSubdivIJ: patch quad matTag numSubdivIJ " "numSubdivJK yVertI zVertI yVertJ zVertJ yVertK zVertK yVertL " "zVertL\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[argi++], &numSubdivJK) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid numSubdivJK: patch quad matTag numSubdivIJ " + opserr << OpenSees::PromptValueError << "invalid numSubdivJK: patch quad matTag numSubdivIJ " "numSubdivJK yVertI zVertI yVertJ zVertJ yVertK zVertK yVertL " "zVertL\n"; return TCL_ERROR; @@ -1217,13 +985,13 @@ TclCommand_addPatch(ClientData clientData, for (int j = 0; j < 4; j++) { if (Tcl_GetDouble(interp, argv[argi++], &vertexCoordY) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Coordinate y: ...yVertI zVertI yVertJ " + opserr << OpenSees::PromptValueError << "invalid Coordinate y: ...yVertI zVertI yVertJ " "zVertJ yVertK zVertK yVertL zVertL\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &vertexCoordZ) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Coordinate z: ...yVertI zVertI yVertJ " + opserr << OpenSees::PromptValueError << "invalid Coordinate z: ...yVertI zVertI yVertJ " "zVertJ yVertK zVertK yVertL zVertL\n"; return TCL_ERROR; } @@ -1246,31 +1014,31 @@ TclCommand_addPatch(ClientData clientData, int numSubdivIJ, numSubdivJK, matTag; double vertexCoordY, vertexCoordZ; - Matrix vertexCoords(4, 2); + MatrixND<4,2> vertexCoords; if (argc < 9) { - opserr << G3_ERROR_PROMPT << "invalid number of parameters: patch quad matTag " + opserr << OpenSees::PromptValueError << "invalid number of parameters: patch quad matTag " "numSubdivIJ numSubdivJK yVertI zVertI yVertK zVertK\n"; return TCL_ERROR; } int argi = 2; if (Tcl_GetInt(interp, argv[argi++], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag: patch quad matTag numSubdivIJ " + opserr << OpenSees::PromptValueError << "invalid matTag: patch quad matTag numSubdivIJ " "numSubdivJK yVertI zVertI yVertJ zVertJ yVertK zVertK yVertL " "zVertL\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[argi++], &numSubdivIJ) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid numSubdivIJ: patch quad matTag numSubdivIJ " + opserr << OpenSees::PromptValueError << "invalid numSubdivIJ: patch quad matTag numSubdivIJ " "numSubdivJK yVertI zVertI yVertJ zVertJ yVertK zVertK yVertL " "zVertL\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[argi++], &numSubdivJK) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid numSubdivJK: patch quad matTag numSubdivIJ " + opserr << OpenSees::PromptValueError << "invalid numSubdivJK: patch quad matTag numSubdivIJ " "numSubdivJK yVertI zVertI yVertJ zVertJ yVertK zVertK yVertL " "zVertL\n"; return TCL_ERROR; @@ -1278,13 +1046,13 @@ TclCommand_addPatch(ClientData clientData, for (int j = 0; j < 2; j++) { if (Tcl_GetDouble(interp, argv[argi++], &vertexCoordY) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Coordinate y: ...yVertI zVertI yVertJ " + opserr << OpenSees::PromptValueError << "invalid Coordinate y: ...yVertI zVertI yVertJ " "zVertJ yVertK zVertK yVertL zVertL\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &vertexCoordZ) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Coordinate z: ...yVertI zVertI yVertJ " + opserr << OpenSees::PromptValueError << "invalid Coordinate z: ...yVertI zVertI yVertJ " "zVertJ yVertK zVertK yVertL zVertL\n"; return TCL_ERROR; } @@ -1317,63 +1085,63 @@ TclCommand_addPatch(ClientData clientData, int argi = 2; if (argc < 11) { - opserr << G3_ERROR_PROMPT << "invalid number of parameters: patch circ matTag " + opserr << OpenSees::PromptValueError << "invalid number of parameters: patch circ matTag " "numSubdivCirc numSubdivRad yCenter zCenter intRad extRad " "startAng endAng\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[argi++], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag: patch circ matTag numSubdivCirc " + opserr << OpenSees::PromptValueError << "invalid matTag: patch circ matTag numSubdivCirc " "numSubdivRad yCenter zCenter intRad extRad startAng endAng\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[argi++], &numSubdivCirc) != TCL_OK) { opserr - << G3_ERROR_PROMPT << "invalid numSubdivCirc: patch circ matTag numSubdivCirc " + << OpenSees::PromptValueError << "invalid numSubdivCirc: patch circ matTag numSubdivCirc " "numSubdivRad yCenter zCenter intRad extRad startAng endAng\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[argi++], &numSubdivRad) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid numSubdivRad: patch circ matTag numSubdivCirc " + opserr << OpenSees::PromptValueError << "invalid numSubdivRad: patch circ matTag numSubdivCirc " "numSubdivRad yCenter zCenter intRad extRad startAng endAng\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &yCenter) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid yCenter: patch circ matTag numSubdivCirc " + opserr << OpenSees::PromptValueError << "invalid yCenter: patch circ matTag numSubdivCirc " "numSubdivRad yCenter zCenter intRad extRad startAng endAng\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &zCenter) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid zCenter: patch circ matTag numSubdivCirc " + opserr << OpenSees::PromptValueError << "invalid zCenter: patch circ matTag numSubdivCirc " "numSubdivRad yCenter zCenter intRad extRad startAng endAng\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &intRad) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid intRad: patch circ matTag numSubdivCirc " + opserr << OpenSees::PromptValueError << "invalid intRad: patch circ matTag numSubdivCirc " "numSubdivRad yCenter zCenter intRad extRad startAng endAng\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &extRad) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid extRad: patch circ matTag numSubdivCirc " + opserr << OpenSees::PromptValueError << "invalid extRad: patch circ matTag numSubdivCirc " "numSubdivRad yCenter zCenter intRad extRad startAng endAng\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &startAng) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid startAng: patch circ matTag numSubdivCirc " + opserr << OpenSees::PromptValueError << "invalid startAng: patch circ matTag numSubdivCirc " "numSubdivRad yCenter zCenter intRad extRad startAng endAng\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &endAng) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid endAng: patch circ matTag numSubdivCirc " + opserr << OpenSees::PromptValueError << "invalid endAng: patch circ matTag numSubdivCirc " "numSubdivRad yCenter zCenter intRad extRad startAng endAng\n"; return TCL_ERROR; } @@ -1393,73 +1161,222 @@ TclCommand_addPatch(ClientData clientData, } else { - opserr << G3_ERROR_PROMPT << "patch type is not available\n"; + opserr << OpenSees::PromptValueError << "patch type is not available\n"; return TCL_ERROR; } return TCL_OK; } -// add fiber to fiber section +// Add a fiber to a fiber section int TclCommand_addFiber(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) { + enum class Position : int { + Y, Z, Area, Material, End + }; + ArgumentTracker tracker; + std::set positional; + assert(clientData != nullptr); BasicModelBuilder* builder = static_cast(clientData); - if (argc < 5) { - opserr << G3_ERROR_PROMPT << "invalid num args: fiber yLoc zLoc area matTag\n"; - return TCL_ERROR; - } - SectionBuilder* fiberSectionRepr = findSectionBuilder(builder, interp, argc, argv); if (fiberSectionRepr == nullptr) { - opserr << G3_ERROR_PROMPT << "cannot retrieve a section builder\n"; + opserr << OpenSees::PromptValueError << "cannot retrieve a section builder\n"; return TCL_ERROR; } -//int numFibers = fiberSectionRepr->getNumFibers(); - - - double yLoc, zLoc, area; - if (Tcl_GetDouble(interp, argv[1], &yLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid yLoc: fiber yLoc zLoc area matTag\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[2], &zLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid zLoc: fiber yLoc zLoc area matTag\n"; - return TCL_ERROR; + double yLoc, zLoc=0, area; + int matTag; + bool warn_2d_z = false; + static constexpr int WarpModeCount = 3; + double warp[WarpModeCount][3]{}; + int warp_arg = -1; + for (int i=1; i= argc) { + opserr << OpenSees::PromptValueError << "missing warp argument\n"; + return TCL_ERROR; + } + warp_arg = i+1; + i++; + } + else if (strcmp(argv[i], "-warn-2d-z") == 0) { + warn_2d_z = true; + i++; + } + else if (strcmp(argv[i], "-material") == 0) { + if (argc == ++i || Tcl_GetInt(interp, argv[i], &matTag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid material tag\n"; + return TCL_ERROR; + } + tracker.consume(Position::Material); + } + else if (strcmp(argv[i], "-area") == 0) { + if (argc == ++i || Tcl_GetDouble(interp, argv[i], &area) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid area\n"; + return TCL_ERROR; + } + tracker.consume(Position::Area); + } + else if (strcmp(argv[i], "-y") == 0) { + if (argc == ++i || Tcl_GetDouble(interp, argv[i], &yLoc) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid y coordinate\n"; + return TCL_ERROR; + } + tracker.consume(Position::Y); + } + else if (strcmp(argv[i], "-z") == 0) { + if (argc == ++i || Tcl_GetDouble(interp, argv[i], &zLoc) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid z coordinate\n"; + return TCL_ERROR; + } + tracker.consume(Position::Z); + } + else { + positional.insert(i); + } } - if (Tcl_GetDouble(interp, argv[3], &area) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid area: fiber yLoc zLoc area matTag\n"; - return TCL_ERROR; + + for (int i: positional) { + switch (tracker.current()) { + case Position::Y: + if (Tcl_GetDouble(interp, argv[i], &yLoc) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid y coordinate\n"; + return TCL_ERROR; + } + tracker.consume(Position::Y); + break; + case Position::Z: + if (Tcl_GetDouble(interp, argv[i], &zLoc) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid z coordinate\n"; + return TCL_ERROR; + } + tracker.consume(Position::Z); + break; + case Position::Area: + if (Tcl_GetDouble(interp, argv[i], &area) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid area\n"; + return TCL_ERROR; + } + tracker.consume(Position::Area); + break; + case Position::Material: + if (Tcl_GetInt(interp, argv[i], &matTag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid material tag\n"; + return TCL_ERROR; + } + tracker.consume(Position::Material); + break; + default: + opserr << OpenSees::PromptValueError << "unexpected argument at position " << i << "\n"; + return TCL_ERROR; + } } - int matTag; - if (Tcl_GetInt(interp, argv[4], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag: fiber yLoc zLoc area matTag\n"; + + if (builder->getNDM() == 2) { + if (warn_2d_z && zLoc != 0.0) { + opswrn << OpenSees::SignalWarning << "z coordinate ignored in 2D\n"; + } + } + if (tracker.current() != Position::End) { + opserr << OpenSees::PromptValueError << "missing required arguments: "; + while (tracker.current() != Position::End) { + switch (tracker.current()) { + case Position::Y: + opserr << "y "; + break; + case Position::Z: + opserr << "z "; + break; + case Position::Area: + opserr << "area "; + break; + case Position::Material: + opserr << "material "; + break; + case Position::End: + break; + } + if (tracker.current() == Position::End) + break; + tracker.consume(tracker.current()); + } + opserr << "\n"; return TCL_ERROR; } + // + // process warping + // + int i_warp = 0; + int split_1_argc; + const char **split_1_argv; + if (warp_arg >= 0 && Tcl_SplitList(interp, argv[warp_arg], &split_1_argc, &split_1_argv) == TCL_OK) { + int argi = 0; + for (; i_warp= split_1_argc) + break; + + // + int split_argc; + const char **split_argv; + if (Tcl_SplitList(interp, split_1_argv[argi], &split_argc, &split_argv) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid warp\n"; + return TCL_ERROR; + } + + if (split_argc != 3) { + opserr << "WARNING warp parameter expected list of 3 floats\n"; + Tcl_Free((char *) split_argv); + return TCL_ERROR; + } + + for (int j = 0; j < 3; j++) { + if (Tcl_GetDouble(interp, split_argv[j], &warp[i_warp][j]) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid warp\n"; + Tcl_Free((char *) split_argv); + return TCL_ERROR; + } + } + + // Free memory allocated by Tcl_SplitList. + Tcl_Free((char *) split_argv); + argi++; + } +} // // Add fiber to section builder // int ndm = builder->getNDM(); - int error = 0; + int id = 0; if (ndm == 2) { Vector pos(2); pos(0) = yLoc; pos(1) = zLoc; - error = fiberSectionRepr->addFiber(0, matTag, area, pos); + id = fiberSectionRepr->addFiber(0, matTag, area, pos); } else if (ndm == 3) { Vector pos(2); pos(0) = yLoc; pos(1) = zLoc; - error = fiberSectionRepr->addFiber(0, matTag, area, pos); + id = fiberSectionRepr->addFiber(0, matTag, area, pos); + } + // set warping + while (i_warp > 0) { + if (0 > fiberSectionRepr->setWarping(id, i_warp-1, warp[i_warp-1])) { + opserr << OpenSees::PromptValueError << "failed to set warping for fiber\n"; + return TCL_ERROR; + } + i_warp--; } - if (error) { - opserr << G3_ERROR_PROMPT << "cannot add patch to section\n"; + if (id < 0) { + opserr << OpenSees::PromptValueError << "Failed to add fiber to section\n"; return TCL_ERROR; } @@ -1477,13 +1394,13 @@ TclCommand_addHFiber(ClientData clientData, Tcl_Interp *interp, int argc, SectionBuilder* fiberSectionRepr = findSectionBuilder(builder, interp, argc, argv); if (fiberSectionRepr == nullptr) { - opserr << G3_ERROR_PROMPT << "cannot retrieve section\n"; + opserr << OpenSees::PromptValueError << "cannot retrieve section\n"; return TCL_ERROR; } // make sure at least one other argument to contain patch type if (argc < 5) { - opserr << G3_ERROR_PROMPT << "invalid num args: Hfiber yLoc zLoc area matTag\n"; + opserr << OpenSees::PromptValueError << "invalid num args: Hfiber yLoc zLoc area matTag\n"; return TCL_ERROR; } @@ -1492,20 +1409,20 @@ TclCommand_addHFiber(ClientData clientData, Tcl_Interp *interp, int argc, double yHLoc, zHLoc, Harea; if (Tcl_GetDouble(interp, argv[1], &yHLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid yLoc: Hfiber yLoc zLoc area matTag\n"; + opserr << OpenSees::PromptValueError << "invalid yLoc: Hfiber yLoc zLoc area matTag\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[2], &zHLoc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid zLoc: Hfiber yLoc zLoc area matTag\n"; + opserr << OpenSees::PromptValueError << "invalid zLoc: Hfiber yLoc zLoc area matTag\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[3], &Harea) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid area: Hfiber yLoc zLoc area matTag\n"; + opserr << OpenSees::PromptValueError << "invalid area: Hfiber yLoc zLoc area matTag\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[4], &matHTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag: Hfiber yLoc zLoc area matTag\n"; + opserr << OpenSees::PromptValueError << "invalid matTag: Hfiber yLoc zLoc area matTag\n"; return TCL_ERROR; } @@ -1533,13 +1450,13 @@ TclCommand_addReinfLayer(ClientData clientData, Tcl_Interp *interp, int argc, SectionBuilder* fiberSectionRepr = findSectionBuilder(builder, interp, argc, argv); if (fiberSectionRepr == nullptr) { - opserr << G3_ERROR_PROMPT << "cannot retrieve section\n"; + opserr << OpenSees::PromptValueError << "cannot retrieve section\n"; return TCL_ERROR; } // make sure at least one other argument to contain layer type if (argc < 2) { - opserr << G3_ERROR_PROMPT << "need to specify a layer type \n"; + opserr << OpenSees::PromptValueError << "need to specify a layer type \n"; return TCL_ERROR; } @@ -1547,7 +1464,7 @@ TclCommand_addReinfLayer(ClientData clientData, Tcl_Interp *interp, int argc, if (strcmp(argv[1], "straight") == 0 || strcmp(argv[1], "line") == 0) { if (argc < 9) { - opserr << G3_ERROR_PROMPT << "invalid number of parameters: layer straight matTag " + opserr << OpenSees::PromptValueError << "invalid number of parameters: layer straight matTag " "numReinfBars reinfBarArea yStartPt zStartPt yEndPt zEndPt\n"; return TCL_ERROR; } @@ -1559,43 +1476,43 @@ TclCommand_addReinfLayer(ClientData clientData, Tcl_Interp *interp, int argc, int argi = 2; if (Tcl_GetInt(interp, argv[argi++], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag: layer straight matTag numReinfBars " + opserr << OpenSees::PromptValueError << "invalid matTag: layer straight matTag numReinfBars " "reinfBarArea yStartPt zStartPt yEndPt zEndPt\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[argi++], &numReinfBars) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid numReinfBars: layer straight matTag " + opserr << OpenSees::PromptValueError << "invalid numReinfBars: layer straight matTag " "numReinfBars reinfBarArea yStartPt zStartPt yEndPt zEndPt\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &reinfBarArea) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid reinfBarArea: layer straight matTag " + opserr << OpenSees::PromptValueError << "invalid reinfBarArea: layer straight matTag " "numReinfBars reinfBarArea yStartPt zStartPt yEndPt zEndPt\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &yStartPt) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid yStartPt: layer straight matTag numReinfBars " + opserr << OpenSees::PromptValueError << "invalid yStartPt: layer straight matTag numReinfBars " "reinfBarArea yStartPt zStartPt yEndPt zEndPt\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &zStartPt) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid zStartPt: layer straight matTag numReinfBars " + opserr << OpenSees::PromptValueError << "invalid zStartPt: layer straight matTag numReinfBars " "reinfBarArea yStartPt zStartPt yEndPt zEndPt\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &yEndPt) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid yEndPt: layer straight matTag numReinfBars " + opserr << OpenSees::PromptValueError << "invalid yEndPt: layer straight matTag numReinfBars " "reinfBarArea yStartPt zStartPt yEndPt zEndPt\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &zEndPt) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid zEndPt: layer straight matTag numReinfBars " + opserr << OpenSees::PromptValueError << "invalid zEndPt: layer straight matTag numReinfBars " "reinfBarArea yStartPt zStartPt yEndPt zEndPt\n"; return TCL_ERROR; } @@ -1619,7 +1536,7 @@ TclCommand_addReinfLayer(ClientData clientData, Tcl_Interp *interp, int argc, } else if (strcmp(argv[1], "circ") == 0) { if (argc < 8) { - opserr << G3_ERROR_PROMPT << "invalid number of parameters: layer circ matTag " + opserr << OpenSees::PromptValueError << "invalid number of parameters: layer circ matTag " "numReinfBars reinfBarArea yCenter zCenter arcRadius \n"; return TCL_ERROR; @@ -1632,38 +1549,32 @@ TclCommand_addReinfLayer(ClientData clientData, Tcl_Interp *interp, int argc, int argi = 2; if (Tcl_GetInt(interp, argv[argi++], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid matTag: layer circ matTag numReinfBars " - "reinfBarArea yCenter zCenter radius startAng endAng\n"; + opserr << OpenSees::PromptValueError << "invalid matTag\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[argi++], &numReinfBars) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid numReinfBars: layer circ matTag numReinfBars " - "reinfBarArea yCenter zCenter radius startAng endAng\n"; + opserr << OpenSees::PromptValueError << "invalid numReinfBars\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &reinfBarArea) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid reinfBarArea: layer circ matTag numReinfBars " - "reinfBarArea yCenter zCenter radius startAng endAng\n"; + opserr << OpenSees::PromptValueError << "invalid reinfBarArea\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &yCenter) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid yCenter: layer circ matTag numReinfBars " - "reinfBarArea yCenter zCenter radius startAng endAng\n"; + opserr << OpenSees::PromptValueError << "invalid yCenter\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &zCenter) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid zCenter: layer circ matTag numReinfBars " - "reinfBarArea yCenter zCenter radius startAng endAng\n"; + opserr << OpenSees::PromptValueError << "invalid zCenter\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &radius) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid radius: layer circ matTag numReinfBars " - "reinfBarArea yCenter zCenter radius startAng endAng\n"; + opserr << OpenSees::PromptValueError << "invalid radius\n"; return TCL_ERROR; } @@ -1671,14 +1582,12 @@ TclCommand_addReinfLayer(ClientData clientData, Tcl_Interp *interp, int argc, if (argc > 9) { if (Tcl_GetDouble(interp, argv[argi++], &startAng) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid startAng: layer circ matTag numReinfBars " - "reinfBarArea yCenter zCenter radius startAng endAng\n"; + opserr << OpenSees::PromptValueError << "invalid startAng\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argi++], &endAng) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid endAng: layer circ matTag numReinfBars " - "reinfBarArea yCenter zCenter radius startAng endAng\n"; + opserr << OpenSees::PromptValueError << "invalid endAng\n"; return TCL_ERROR; } @@ -1692,24 +1601,25 @@ TclCommand_addReinfLayer(ClientData clientData, Tcl_Interp *interp, int argc, center(0) = yCenter; center(1) = zCenter; - CircReinfLayer *reinfLayer = nullptr; - if (anglesSpecified) + int error = -1; + // construct and add to section + if (anglesSpecified) { // Construct arc - reinfLayer = new CircReinfLayer(matTag, numReinfBars, reinfBarArea, - center, radius, startAng, endAng); - else + CircReinfLayer reinfLayer(matTag, numReinfBars, reinfBarArea, + center, radius, startAng, endAng); + error = fiberSectionRepr->addLayer(reinfLayer); + } else { // Construct circle - reinfLayer = new CircReinfLayer(matTag, numReinfBars, reinfBarArea, - center, radius); + CircReinfLayer reinfLayer(matTag, numReinfBars, reinfBarArea, + center, radius); + error = fiberSectionRepr->addLayer(reinfLayer); + } - // add reinfLayer to section - int error = fiberSectionRepr->addLayer(*reinfLayer); - delete reinfLayer; if (error) return TCL_ERROR; } else { - opserr << G3_ERROR_PROMPT << "reinforcing layer type is not available\n"; + opserr << OpenSees::PromptValueError << "reinforcing layer type is not available\n"; return TCL_ERROR; } @@ -1761,7 +1671,7 @@ TclCommand_addUCFiberSection(ClientData clientData, Tcl_Interp *interp, } // - // now parse the output file containing the fiber data, + // Now parse the output file containing the fiber data, // create fibers and add them to the section // @@ -1797,7 +1707,7 @@ TclCommand_addUCFiberSection(ClientData clientData, Tcl_Interp *interp, UniaxialMaterial *theMaterial = G3_getUniaxialMaterialInstance(rt,matTag); if (theMaterial == 0) { opserr << "section UCFiber - no material exists with tag << " << matTag - << endln; + << "\n"; return TCL_ERROR; } @@ -1818,323 +1728,3 @@ TclCommand_addUCFiberSection(ClientData clientData, Tcl_Interp *interp, return TCL_OK; } - -#if 0 -#include -#include -int -buildSectionInt(ClientData clientData, Tcl_Interp *interp, TclBasicBuilder *theTclBasicBuilder, - int secTag, UniaxialMaterial &theTorsion, int NStrip1, - double t1, int NStrip2, double t2, int NStrip3, double t3) -{ - assert(clientData != nullptr); - BasicModelBuilder* builder = static_cast(clientData); - SectionRepres *sectionRepres = theTclBasicBuilder->getSectionRepres(secTag); - - if (sectionRepres == nullptr) { - opserr << G3_ERROR_PROMPT << "cannot retrieve section\n"; - return TCL_ERROR; - } - - if (sectionRepres->getType() == SEC_TAG_FiberSection) { - // build the section - - FiberSectionRepr *fiberSectionRepr = (FiberSectionRepr *)sectionRepres; - - int i, j, k; - int numFibers; - int numHFibers; - - int numPatches; - Patch **patch; - - int numReinfLayers; - ReinfLayer **reinfLayer; - - numPatches = fiberSectionRepr->getNumPatches(); - patch = fiberSectionRepr->getPatches(); - numReinfLayers = fiberSectionRepr->getNumReinfLayers(); - reinfLayer = fiberSectionRepr->getReinfLayers(); - - int numSectionRepresFibers = fiberSectionRepr->getNumFibers(); - Fiber **sectionRepresFibers = fiberSectionRepr->getFibers(); - - int numSectionRepresHFibers = fiberSectionRepr->getNumHFibers(); - Fiber **sectionRepresHFibers = fiberSectionRepr->getHFibers(); - - numFibers = numSectionRepresFibers; - for (int i = 0; i < numPatches; ++i) - numFibers += patch[i]->getNumCells(); - - for (int i = 0; i < numReinfLayers; ++i) - numFibers += reinfLayer[i]->getNumReinfBars(); - - numHFibers = numSectionRepresHFibers; - - static Vector fiberPosition(2); - int matTag; - - ID fibersMaterial(numFibers - numSectionRepresFibers); - Matrix fibersPosition(2, numFibers - numSectionRepresFibers); - Vector fibersArea(numFibers - numSectionRepresFibers); - - int numCells; - Cell **cell; - - k = 0; - for (int i = 0; i < numPatches; ++i) { - numCells = patch[i]->getNumCells(); - matTag = patch[i]->getMaterialID(); - - cell = patch[i]->getCells(); - - for (int j = 0; j < numCells; j++) { - fibersMaterial(k) = matTag; - fibersArea(k) = cell[j]->getArea(); - fiberPosition = cell[j]->getCentroidPosition(); - fibersPosition(0, k) = fiberPosition(0); - fibersPosition(1, k) = fiberPosition(1); - k++; - } - - for (int j = 0; j < numCells; j++) - delete cell[j]; - - delete[] cell; - } - - ReinfBar *reinfBar; - int numReinfBars; - - for (int i = 0; i < numReinfLayers; ++i) { - numReinfBars = reinfLayer[i]->getNumReinfBars(); - reinfBar = reinfLayer[i]->getReinfBars(); - matTag = reinfLayer[i]->getMaterialID(); - - for (int j = 0; j < numReinfBars; j++) { - fibersMaterial(k) = matTag; - fibersArea(k) = reinfBar[j].getArea(); - fiberPosition = reinfBar[j].getPosition(); - - fibersPosition(0, k) = fiberPosition(0); - fibersPosition(1, k) = fiberPosition(1); - - k++; - } - delete[] reinfBar; - } - - UniaxialMaterial *material = nullptr; - - Fiber **fiber = new Fiber *[numFibers]; - - // copy the section repres fibers - for (i = 0; i < numSectionRepresFibers; ++i) - fiber[i] = sectionRepresFibers[i]; - - Fiber **Hfiber = new Fiber *[numHFibers]; - - // copy the section repres fibers - for (int i = 0; i < numSectionRepresHFibers; ++i) - Hfiber[i] = sectionRepresHFibers[i]; - - // creates 2d section - int NDM = builder->getNDM(); - if (NDM == 2) { - k = 0; - for (int i = numSectionRepresFibers; i < numFibers; ++i) { - material = builder->getUniaxialMaterial(fibersMaterial(k)); - if (material == nullptr) { - opserr << G3_ERROR_PROMPT << "invalid material ID for patch\n"; - return TCL_ERROR; - } - - fiber[i] = new UniaxialFiber2d(k, *material, fibersArea(k), - fibersPosition(0, k)); - - k++; - } - - SectionForceDeformation *section = - new FiberSection2dInt(secTag, numFibers, fiber, numHFibers, Hfiber, - NStrip1, t1, NStrip2, t2, NStrip3, t3); - - // Delete fibers - for (int i = 0; i < numFibers; ++i) - delete fiber[i]; - - for (int i = 0; i < numHFibers; ++i) - delete Hfiber[i]; - - if (section == nullptr) { - opserr << G3_ERROR_PROMPT << "cannot construct section\n"; - return TCL_ERROR; - } - - if (theTclBasicBuilder->addSection (*section) < 0) { - opserr << G3_ERROR_PROMPT << "- cannot add section\n"; - return TCL_ERROR; - } - - } else if (NDM == 3) { - - static Vector fiberPosition(2); - k = 0; - for (i = numSectionRepresFibers; i < numFibers; ++i) { - material = builder->getUniaxialMaterial(fibersMaterial(k)); - if (material == nullptr) { - opserr << G3_ERROR_PROMPT << "invalid material ID for patch\n"; - return TCL_ERROR; - } - - fiberPosition(0) = fibersPosition(0, k); - fiberPosition(1) = fibersPosition(1, k); - - fiber[i] = - new UniaxialFiber3d(k, *material, fibersArea(k), fiberPosition); - if (fibersArea(k) < 0) - opserr << "ERROR: " << fiberPosition(0) << " " << fiberPosition(1) - << endln; - k++; - } - - SectionForceDeformation *section = 0; - section = new FiberSection3d(secTag, numFibers, fiber, theTorsion, - options.computeCentroid); - - // Delete fibers - for (i = 0; i < numFibers; ++i) - delete fiber[i]; - - if (section == 0) { - opserr << G3_ERROR_PROMPT << "- cannot construct section\n"; - return TCL_ERROR; - } - - if (theTclBasicBuilder->addSection (*section) < 0) { - opserr << G3_ERROR_PROMPT << "- cannot add section\n"; - return TCL_ERROR; - } - - } else { - opserr << G3_ERROR_PROMPT << "NDM = " << NDM - << " is incompatible with available frame elements\n"; - return TCL_ERROR; - } - - // Delete fiber array - delete[] fiber; - // delete [] Hfiber; - - } else { - opserr << G3_ERROR_PROMPT << "section invalid: can only build fiber sections\n"; - return TCL_ERROR; - } - - return TCL_OK; -} -#endif - - -#if 0 -SectionForceDeformation* -G3Parse_newTubeSection(G3_Runtime* rt, int argc, G3_Char ** const argv) -{ - SectionForceDeformation *theSection = nullptr; - if (strcmp(argv[1], "Tube") == 0) { - if (argc < 8) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; - opserr << "Want: section Tube tag? matTag? D? t? nfw? nfr?" << endln; - return nullptr; - } - - int tag, matTag; - double D, t; - int nfw, nfr; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid section Tube tag" << endln; - return nullptr; - } - - if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid section Tube matTag" << endln; - return nullptr; - } - - if (Tcl_GetDouble(interp, argv[4], &D) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid D" << endln; - opserr << "Tube section: " << tag << endln; - return nullptr; - } - - if (Tcl_GetDouble(interp, argv[5], &t) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid t" << endln; - opserr << "Tube section: " << tag << endln; - return nullptr; - } - - if (Tcl_GetInt(interp, argv[6], &nfw) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nfw" << endln; - opserr << "Tube section: " << tag << endln; - return nullptr; - } - - if (Tcl_GetInt(interp, argv[7], &nfr) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nfr" << endln; - opserr << "Tube section: " << tag << endln; - return nullptr; - } - - TubeSectionIntegration tubesect(D, t, nfw, nfr); - - int numFibers = tubesect.getNumFibers(); - - if (argc > 8) { - - double shape = 1.0; - if (argc > 9) { - if (Tcl_GetDouble(interp, argv[9], &shape) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid shape" << endln; - opserr << "WFSection2d section: " << tag << endln; - return nullptr; - } - } - - NDMaterial *theSteel = builder->getTypedObject(matTag); - if (theSteel == 0) - return nullptr; - - - NDMaterial **theMats = new NDMaterial *[numFibers]; - - tubesect.arrangeFibers(theMats, theSteel); - - // Parsing was successful, allocate the section - theSection = 0; - if (strcmp(argv[8], "-nd") == 0) - theSection = - new NDFiberSection3d(tag, numFibers, theMats, tubesect, shape); - if (strcmp(argv[8], "-ndWarping") == 0) - theSection = new NDFiberSectionWarping2d(tag, numFibers, theMats, - tubesect, shape); - - delete[] theMats; - } else { - UniaxialMaterial *theSteel = builder->getTypedObject(matTag); - if (theSteel == 0) - return nullptr; - - UniaxialMaterial **theMats = new UniaxialMaterial *[numFibers]; - - tubesect.arrangeFibers(theMats, theSteel); - - // Parsing was successful, allocate the section - theSection = new FiberSection2d(tag, numFibers, theMats, tubesect); - - delete[] theMats; - } - } -} -#endif - diff --git a/SRC/runtime/commands/modeling/section/PlaneSection.h b/SRC/runtime/commands/modeling/section/PlaneSection.h new file mode 100644 index 0000000000..5011a4b8e1 --- /dev/null +++ b/SRC/runtime/commands/modeling/section/PlaneSection.h @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Written: cmp +// +#pragma once +#include + + +template +class PlaneSection: public TaggedObject { + + public: + + PlaneSection(int tag, MatT& material, double thickness) + : TaggedObject(tag) + , material(&material) + , thickness(thickness) + { + } + + double getThickness() const + { + return thickness; + } + + MatT* getMaterial() const + { + return material; + } + + private: + const double thickness; + MatT* material; +}; + diff --git a/SRC/runtime/commands/modeling/section/frame.cpp b/SRC/runtime/commands/modeling/section/frame.cpp new file mode 100644 index 0000000000..9f9b9e73eb --- /dev/null +++ b/SRC/runtime/commands/modeling/section/frame.cpp @@ -0,0 +1,653 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Written: cmp +// +#include +#include +#include +#include +#include +#include +#include +#include +// +#include +#include +#include +#include +#include +#include + + +// section ElasticFrame tag E? A? Iz? +// E A I +// E A I G J +// -E $E +// -G $G +// +// -A $A +// {$A $Ay} if ndm == 2 +// {$A $Ay $Az} +// -Ay $Ay +// -Az $Az +// -I/B $Iz +// {$Iy $Iz} +// {$Iy $Iz $Iyz} +// -J $J +// -Cw $Cw +// {$Cw $Ca} +// -Q {$Qy $Qz <$Qyx $Qyz>} +// -R {$Qy $Qz} +// +template +static inline int +TclCommand_newElasticSectionTemplate(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + + assert(clientData != nullptr); + BasicModelBuilder *builder = static_cast(clientData); + FrameSectionConstants consts {}; + + Domain& domain = *builder->getDomain(); + + ArgumentTracker tracker; + std::set positional; + + using namespace OpenSees::Parsing; + + Parameter* parameters[int(Position::Max)] = {}; + + bool construct_full = false; + + if (argc < 5) { + opserr << OpenSees::PromptParseError << "insufficient arguments\n"; + opserr << "Want: section Elastic tag? E? A? Iz? .\n"; + return TCL_ERROR; + } + + int tag; + double E, + G = 0, + J = 0; + + bool use_mass = false; + double mass=0.0; + + // All 3D elements have been refactored to select shear themselves, but + // in 2D the element may check the section for shear. + bool use_shear = false ; // NDM == 3; + + int i; + for (i=2; iaddTaggedObject(*theSection) < 0) { + if (theSection != nullptr) + delete theSection; + return TCL_ERROR; + } + + // For the elastic elements + // builder->addTaggedObject(*new ElasticLinearFrameSection3d(tag,E,G,consts,mass,use_mass)); + + return TCL_OK; + + } else { + + FrameSection* theSection = nullptr; + + consts.Ca = consts.Iy + consts.Iz - J; + consts.Sa = -(consts.Iy + consts.Iz - J); + if (construct_full) { + theSection = new ElasticLinearFrameSection3d(tag, + E, G, + consts, + mass, use_mass + ); + } + + else if (strcmp(argv[1], "Elastic") == 0) { + if (use_shear) + theSection = new ElasticShearSection3d(tag, E, consts.A, consts.Iz, consts.Iy, G, J, + consts.A/consts.Ay, consts.A/consts.Az); + else + theSection = new ElasticSection3d(tag, E, consts.A, consts.Iz, consts.Iy, G, J); + + } + else + theSection = new ElasticLinearFrameSection3d(tag, + E, G, + consts, + mass, use_mass + ); + + if (theSection == nullptr || builder->addTaggedObject(*theSection) < 0) { + if (theSection != nullptr) + delete theSection; + return TCL_ERROR; + } else + return TCL_OK; + } + +} + +int +TclCommand_newElasticSection(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + BasicModelBuilder *builder = static_cast(clientData); + + int ndm = builder->getNDM(); + + if (ndm==2) { + enum class Position : int { + Tag, E, A, Iz, EndRequired, G, ky, End, Iy, J, kz, Max + }; + return TclCommand_newElasticSectionTemplate(clientData, interp, argc, argv); + + } else { + enum class Position : int { + Tag, E, A, Iz, Iy, G, J, EndRequired, ky, kz, End, Max + }; + return TclCommand_newElasticSectionTemplate(clientData, interp, argc, argv); + } +} + +int +TclCommand_addSectionAggregator(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char**const argv) +{ + assert(clientData != nullptr); + BasicModelBuilder *builder = static_cast(clientData); + + if (argc < 5) { + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; + opserr << "Want: section Aggregator tag? uniTag1? code1? ... <-section " + "secTag?>" + << endln; + return TCL_ERROR; + } + + int status = TCL_ERROR; + + int tag; + int secTag; + FrameSection *theSec = nullptr; + + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid Aggregator tag" << endln; + return TCL_ERROR; + } + + int nArgs = argc - 3; + + for (int ii = 5; ii < argc; ii++) { + if (strcmp(argv[ii], "-section") == 0 && ++ii < argc) { + if (Tcl_GetInt(interp, argv[ii], &secTag) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid Aggregator tag" << endln; + return TCL_ERROR; + } + + theSec = builder->getTypedObject(secTag); + if (theSec == 0) + return TCL_ERROR; + + nArgs -= 2; + } + } + + int nMats = nArgs / 2; + + if (nArgs % 2 != 0) { + opserr << OpenSees::PromptValueError << "improper number of arguments for Aggregator" << endln; + return TCL_ERROR; + } + + ID codes(nMats); + UniaxialMaterial **theMats = new UniaxialMaterial *[nMats]; + + int i, j; + for (i = 3, j = 0; j < nMats; i++, j++) { + int tagI; + if (Tcl_GetInt(interp, argv[i], &tagI) != TCL_OK) { + opserr << OpenSees::PromptValueError << "invalid Aggregator matTag" << endln; + status = TCL_ERROR; + goto cleanup; + } + + theMats[j] = builder->getTypedObject(tagI); + if (theMats[j] == 0) { + status = TCL_ERROR; + goto cleanup; + } + + i++; + + if (strcmp(argv[i], "Mz") == 0) + codes(j) = SECTION_RESPONSE_MZ; + else if (strcmp(argv[i], "P") == 0) + codes(j) = SECTION_RESPONSE_P; + else if (strcmp(argv[i], "Vy") == 0) + codes(j) = SECTION_RESPONSE_VY; + else if (strcmp(argv[i], "My") == 0) + codes(j) = SECTION_RESPONSE_MY; + else if (strcmp(argv[i], "Vz") == 0) + codes(j) = SECTION_RESPONSE_VZ; + else if (strcmp(argv[i], "T") == 0) + codes(j) = SECTION_RESPONSE_T; + else { + opserr << OpenSees::PromptValueError << "invalid code" << endln; + opserr << "\nsection Aggregator: " << tag << endln; + status = TCL_ERROR; + goto cleanup; + } + } + + { + FrameSection* theSection = nullptr; + if (theSec) + theSection = new SectionAggregator(tag, *theSec, nMats, theMats, codes); + else + theSection = new SectionAggregator(tag, nMats, theMats, codes); + + // Now add the material to the modelBuilder + if (builder->addTaggedObject(*theSection) < 0) { + delete theSection; + status = TCL_ERROR; + } else + status = TCL_OK; + } + +cleanup: + delete[] theMats; + return status; +} diff --git a/SRC/runtime/commands/modeling/section/plane.cpp b/SRC/runtime/commands/modeling/section/plane.cpp new file mode 100644 index 0000000000..6ddd47405f --- /dev/null +++ b/SRC/runtime/commands/modeling/section/plane.cpp @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Written: cmp +// +#include +#include +#include +#include +#include +#include "PlaneSection.h" +#include +#include +#include + +int +TclCommand_addPlaneSection(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + BasicModelBuilder *builder = static_cast(clientData); + enum class Positions : int { + Material, Thickness, End + }; + ArgumentTracker tracker; + std::set positional; + + // section Plane[Strain|Stress] $tag $material $thickness + if (argc < 5) { + opserr << OpenSees::PromptValueError + << "incorrect number of arguments\n"; + return TCL_ERROR; + } + + int tag; + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << OpenSees::PromptValueError + << "failed to read integer tag\n"; + return TCL_ERROR; + } + int mtag; + double thickness; + for (int i=3; igetTypedObject(mtag); + if (mptr == nullptr) + return TCL_ERROR; + + NDMaterial* pptr = nullptr; + if (strcmp(argv[1], "PlaneStrain") == 0) { + if (!(pptr = mptr->getCopy("PlaneStrain"))) { + pptr = new PlaneStrainMaterial(tag, *mptr); + } + } + else if (strcmp(argv[1], "PlaneStress") == 0) { + if (!(pptr = mptr->getCopy("PlaneStress"))) { + pptr = new PlaneStressMaterial(tag, *mptr); + } + } + else { + opserr << OpenSees::PromptValueError + << "unknown plane section\n"; + return TCL_ERROR; + } + + builder->addTaggedObject>(*(new PlaneSection(tag, *pptr, thickness))); + + return TCL_OK; +} diff --git a/SRC/runtime/commands/modeling/section/truss.cpp b/SRC/runtime/commands/modeling/section/truss.cpp new file mode 100644 index 0000000000..ccab27a5c8 --- /dev/null +++ b/SRC/runtime/commands/modeling/section/truss.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Description: This file implements a command to add a uniaxial section. +// Written: cmp +// +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int +TclCommand_addUniaxialSection(ClientData clientData, Tcl_Interp *interp, + int argc, TCL_Char ** const argv) +{ + BasicModelBuilder *builder = static_cast(clientData); + + // section Uniaxial tag? material? code? + if (argc < 5) { + opserr << "WARNING insufficient arguments\n"; + return TCL_ERROR; + } + + int tag; + if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { + opserr << "WARNING invalid section tag\n"; + return TCL_ERROR; + } + + int mat; + if (Tcl_GetInt(interp, argv[3], &mat) != TCL_OK) { + opserr << "WARNING invalid uniaxial material tag\n"; + return TCL_ERROR; + } + + + UniaxialMaterial* material = builder->getTypedObject(mat); + if (material == nullptr) + return TCL_ERROR; + + UniaxialMaterial *theMats[1] = {material}; + + // + int code; + const char* type = argv[4]; + if (strcmp(type,"Mz") == 0) + code = SECTION_RESPONSE_MZ; + else if (strcmp(type,"P") == 0) + code = SECTION_RESPONSE_P; + else if (strcmp(type,"Vy") == 0) + code = SECTION_RESPONSE_VY; + else if (strcmp(type,"My") == 0) + code = SECTION_RESPONSE_MY; + else if (strcmp(type,"Vz") == 0) + code = SECTION_RESPONSE_VZ; + else if (strcmp(type,"T") == 0) + code = SECTION_RESPONSE_T; + else { + opserr << "WARNING invalid code " << type << "\n"; + return TCL_ERROR; + } + + ID codeID(1); + codeID(0) = code; + return builder->addTaggedObject(*new SectionAggregator(tag, 1, theMats, codeID)); +} + diff --git a/SRC/runtime/commands/modeling/transform/FrameTransformBuilder.hpp b/SRC/runtime/commands/modeling/transform/FrameTransformBuilder.hpp new file mode 100644 index 0000000000..8b8961e59d --- /dev/null +++ b/SRC/runtime/commands/modeling/transform/FrameTransformBuilder.hpp @@ -0,0 +1,128 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Written: Claudio M. Perez +// +#pragma once +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace OpenSees { + +class FrameTransformBuilder : public TaggedObject { +public: + FrameTransformBuilder(int ndm, int t, const char *n) + : ndm(ndm), + TaggedObject(t), + vz{{0, 0, 0}}, offsets{}, offset_flags(0) { + // strncpy(name, n, 128); + snprintf(name, sizeof(name), "%s", n); + // offset_flags |= LogIter; + } + + virtual ~FrameTransformBuilder() {} + + template + FrameTransform * + create() + { + std::array *offset_array = nullptr; + std::array offset_data{}; + + if (offsets.size() > 0) { + offset_array = &offset_data; + for (int i = 0; i < nn; ++i) { + auto it = offsets.find(i+1); + if (it != offsets.end()) + (*offset_array)[i] = it->second; + } + } + + int tag = this->getTag(); + if (strstr(name, "Linear") != nullptr) + return new LinearFrameTransf (tag, vz, offset_array, offset_flags); + + else if (strcmp(name, "Corotational") == 0) { + if constexpr (ndf == 6) + return new SouzaFrameTransf (tag, vz, offset_array, offset_flags); + else + return nullptr; + } + + else if (strstr(name, "PDelta") != nullptr) + return new PDeltaFrameTransf (tag, vz, offset_array, offset_flags); + + else if (strcmp(name, "Corotational02") == 0 || strcmp(name, "Isometric") == 0 || strstr(name, "Rigid") != nullptr) + { + if (getenv("Battini")) + return new EuclidFrameTransf> (tag, vz, offset_array, offset_flags); + else if (getenv("Crisfield")) + return new EuclidFrameTransf> (tag, vz, offset_array, offset_flags); + else if (getenv("Crisfield02")) + return new EuclidFrameTransf> (tag, vz, offset_array, offset_flags); + else + return new EuclidFrameTransf> (tag, vz, offset_array, offset_flags); + } + else if (strcmp(name, "Corotational03") == 0) + { + if (getenv("Crisfield02")) + return new EuclidFrameTransf> (tag, vz, offset_array, offset_flags); + + return new EuclidFrameTransf> (tag, vz, offset_array, offset_flags); + } + + return nullptr; + } + + virtual void + Print(OPS_Stream&s, int flag) { + if (flag == OPS_PRINT_PRINTMODEL_JSON) { + s << OPS_PRINT_JSON_MATE_INDENT << "{"; + s << "\"name\": " << this->getTag() << ", "; + s << "\"type\": \"" << name << "\""; + s << ", "; + s << "\"vz\": [" << vz[0] << ", " << vz[1] << ", " << vz[2] << "]"; + if (offsets.size() > 0) { + s << ", \"offsets\": {"; + for (auto it = offsets.begin(); it != offsets.end(); ++it) { + s << it->first << ": [" << it->second[0] << ", " << it->second[1] << ", " << it->second[2] << "]"; + if (std::next(it) != offsets.end()) + s << ", "; + } + } + s << "}"; + } + } + + int ndm; + int tag; + char name[128]; + Vector3D vz; + std::map offsets; + int offset_flags; +}; + +} // namespace OpenSees \ No newline at end of file diff --git a/SRC/runtime/commands/modeling/uniaxial.cpp b/SRC/runtime/commands/modeling/uniaxial.cpp index ca2b931324..af99e8eb41 100644 --- a/SRC/runtime/commands/modeling/uniaxial.cpp +++ b/SRC/runtime/commands/modeling/uniaxial.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -10,23 +19,17 @@ // Written: fmk, MHS, cmp // Created: 07/99 // - -#include +#include #include #include #include "uniaxial.hpp" #include #include // MHS -#include // Won Lee #include // Won Lee -#include // MHS #include // Mackie -#include // ZHY -#include // Patxi #include // MHS #include // MHS -#include // NM #include // KM #include //JAE @@ -38,7 +41,6 @@ #include #include -#include // Quan class G3_Runtime; @@ -46,21 +48,8 @@ extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, Tcl_Interp *interp, int cArg, int mArg, TCL_Char ** const argv, Domain *domain); -// extern void *OPS_PlateBearingConnectionThermal(G3_Runtime*); -// extern int TclCommand_ConfinedConcrete02(ClientData clientData, Tcl_Interp -// *interp, int argc, TCL_Char ** const argv, TclBasicBuilder -// *theTclBuilder); -// extern UniaxialMaterial *Tcl_AddLimitStateMaterial(ClientData clientData, -// Tcl_Interp *interp, int argc, -// TCL_Char **arg); - -#if 0 -extern UniaxialMaterial * -Tcl_addWrapperUniaxialMaterial(matObj *, ClientData clientData, - Tcl_Interp *interp, int argc, TCL_Char ** const argv); -#endif typedef struct uniaxialPackageCommand { char *funcName; void *(*funcPtr)(); @@ -69,25 +58,18 @@ typedef struct uniaxialPackageCommand { static UniaxialPackageCommand *theUniaxialPackageCommands = NULL; -static void printCommand(int argc, TCL_Char ** const argv) { - opserr << "Input command: "; - for (int i = 0; i < argc; ++i) - opserr << argv[i] << " "; - opserr << "\n"; -} - // // external functions // -UniaxialMaterial *TclBasicBuilder_addPyTzQzMaterial(ClientData clientData, - Tcl_Interp *interp, +UniaxialMaterial *TclBasicBuilder_addPyTzQzMaterial(ClientData, + Tcl_Interp *, int argc, TCL_Char ** const argv, - Domain *theDomain); + Domain *); -UniaxialMaterial *TclBasicBuilder_FRPCnfinedConcrete(ClientData clientData, - Tcl_Interp *interp, +UniaxialMaterial *TclBasicBuilder_FRPCnfinedConcrete(ClientData, + Tcl_Interp *, int argc, TCL_Char ** const argv, - Domain *theDomain); + Domain *); UniaxialMaterial *TclBasicBuilder_addDegradingMaterial(ClientData, Tcl_Interp *, int, TCL_Char **); @@ -103,7 +85,7 @@ TclCommand_addUniaxialMaterial(ClientData clientData, Tcl_Interp *interp, // Make sure there is a minimum number of arguments if (argc < 3) { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << "insufficient number of uniaxial material arguments\n" << "Want: uniaxialMaterial type? tag? \n"; return TCL_ERROR; @@ -182,24 +164,6 @@ TclCommand_addUniaxialMaterial(ClientData clientData, Tcl_Interp *interp, // package yet to be loaded // if (theMaterial == nullptr) { -#if 0 - // - // maybe material in a routine - // - char *matType = new char[strlen(argv[1]) + 1]; - strcpy(matType, argv[1]); - matObj *matObject = OPS_GetMaterialType(matType, strlen(matType)); - - delete[] matType; - - if (matObject != 0) { - - theMaterial = Tcl_addWrapperUniaxialMaterial(matObject, clientData, interp, argc, argv); - - if (theMaterial == 0) - delete matObject; - } -#endif } // @@ -240,717 +204,13 @@ TclCommand_addUniaxialMaterial(ClientData clientData, Tcl_Interp *interp, // if still here the element command does not exist // if (theMaterial == nullptr) { - opserr << G3_ERROR_PROMPT << "Could not create uniaxialMaterial " << argv[1] << "\n"; + opserr << OpenSees::PromptValueError << "Could not create uniaxialMaterial " << argv[1] << "\n"; return TCL_ERROR; } // Now add the material to the modelBuilder if (builder->addTaggedObject(*theMaterial) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "Could not add uniaxialMaterial to the model builder.\n"; - delete theMaterial; - return TCL_ERROR; - } - - return TCL_OK; -} - - -int -TclCommand_newFatigueMaterial(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char ** const argv) -{ - assert(clientData != nullptr); - BasicModelBuilder *builder = static_cast(clientData); - - if (argc < 4) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial Fatigue tag? matTag?"; - opserr << " <-D_max dmax?> <-e0 e0?> <-m m?>" << "\n"; - opserr << " <-min min?> <-max max?>" << "\n"; - return TCL_ERROR; - } - - int tag, matTag; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid uniaxialMaterial Fatigue tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid component tag\n"; - opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; - return TCL_ERROR; - } - - double Dmax = 1.0; - double E0 = 0.191; - double m = -0.458; - double epsmin = NEG_INF_STRAIN; - double epsmax = POS_INF_STRAIN; - - for (int j = 4; j < argc; j++) { - if (strcmp(argv[j], "-Dmax") == 0) { - if ((j + 1 >= argc) || - (Tcl_GetDouble(interp, argv[j + 1], &Dmax) != TCL_OK)) { - opserr << G3_ERROR_PROMPT << "invalid -Dmax"; - opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; - return TCL_ERROR; - } - } else if (strcmp(argv[j], "-E0") == 0) { - if ((j + 1 >= argc) || - (Tcl_GetDouble(interp, argv[j + 1], &E0) != TCL_OK)) { - opserr << G3_ERROR_PROMPT << "invalid -E0"; - opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; - return TCL_ERROR; - } - } else if (strcmp(argv[j], "-m") == 0) { - if ((j + 1 >= argc) || - (Tcl_GetDouble(interp, argv[j + 1], &m) != TCL_OK)) { - opserr << G3_ERROR_PROMPT << "invalid -m"; - opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; - return TCL_ERROR; - } - } else if (strcmp(argv[j], "-min") == 0) { - if ((j + 1 >= argc) || - (Tcl_GetDouble(interp, argv[j + 1], &epsmin) != TCL_OK)) { - opserr << G3_ERROR_PROMPT << "invalid -min "; - opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; - return TCL_ERROR; - } - } else if (strcmp(argv[j], "-max") == 0) { - if ((j + 1 >= argc) || - (Tcl_GetDouble(interp, argv[j + 1], &epsmax) != TCL_OK)) { - opserr << G3_ERROR_PROMPT << "invalid -max"; - opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; - return TCL_ERROR; - } - } - j++; - } - - UniaxialMaterial *theMat = builder->getTypedObject(matTag); - - if (theMat == nullptr) { - opserr << G3_ERROR_PROMPT << "component material does not exist\n"; - opserr << "Component material: " << matTag; - opserr << "\nuniaxialMaterial Fatigue: " << tag << "\n"; - return TCL_ERROR; - } - - // Parsing was successful, allocate the material - UniaxialMaterial *theMaterial = - new FatigueMaterial(tag, *theMat, Dmax, E0, m, epsmin, epsmax); - - if (builder->addTaggedObject(*theMaterial) != TCL_OK) { - delete theMaterial; - return TCL_ERROR; - } - return TCL_OK; - -} - - -static int -TclDispatch_LegacyUniaxials(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char**const argv) -{ - assert(clientData != nullptr); - BasicModelBuilder *builder = static_cast(clientData); - UniaxialMaterial *theMaterial = nullptr; - - if (strcmp(argv[1], "Elastic2") == 0) { - if (argc < 4 || argc > 5) { - opserr << G3_ERROR_PROMPT << "invalid number of arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial Elastic tag? E? " << "\n"; - return TCL_ERROR; - } - - int tag; - double E; - double eta = 0.0; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid uniaxialMaterial Elastic tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid E\n"; - opserr << "uniaxiaMaterial Elastic: " << tag << "\n"; - return TCL_ERROR; - } - - if (argc == 5) { - if (Tcl_GetDouble(interp, argv[4], &eta) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid eta\n"; - opserr << "uniaxialMaterial Elastic: " << tag << "\n"; - return TCL_ERROR; - } - } - - // Parsing was successful, allocate the material - theMaterial = new Elastic2Material(tag, E, eta); - - } else if (strcmp(argv[1], "ENT") == 0) { - if (argc < 4) { - opserr << G3_ERROR_PROMPT << "invalid number of arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial ENT tag? E?" << "\n"; - return TCL_ERROR; - } - - int tag; - double E; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid uniaxialMaterial ENT tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid E\n"; - opserr << "uniaxiaMaterial ENT: " << tag << "\n"; - return TCL_ERROR; - } - - // Parsing was successful, allocate the material - theMaterial = new ENTMaterial(tag, E); - - } - - else if (strcmp(argv[1], "BarSlip") == 0) { - if (argc != 17 && argc != 15) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial BarSlip tag? fc? fy? Es? fu? Eh? db? " - "ld? nb? width? depth? bsflag? type? " - << "\n"; - return TCL_ERROR; - } - - int tag, nb, bsf, typ, dmg=1, unt=1; - double fc, fy, Es, fu, Eh, ld, width, depth, db; - - int argStart = 2; - - if (Tcl_GetInt(interp, argv[argStart++], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid tag\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[argStart++], &fc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid fc\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[argStart++], &fy) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid fy\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[argStart++], &Es) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Es\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[argStart++], &fu) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid fu\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[argStart++], &Eh) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid Eh\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[argStart++], &db) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid db\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[argStart++], &ld) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid ld\n"; - return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[argStart++], &nb) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid nbars\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[argStart++], &width) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid width\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[argStart++], &depth) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid depth\n"; - return TCL_ERROR; - } - - int y; - y = argStart; - - if ((strcmp(argv[y], "strong") == 0) || - (strcmp(argv[y], "Strong") == 0) || (strcmp(argv[y], "weak") == 0) || - (strcmp(argv[y], "Weak") == 0)) { - if ((strcmp(argv[y], "strong") == 0) || - (strcmp(argv[y], "Strong") == 0)) { - bsf = 0; - } - - if ((strcmp(argv[y], "weak") == 0) || (strcmp(argv[y], "Weak") == 0)) { - bsf = 1; - } - } else { - opserr << G3_ERROR_PROMPT << "invalid bond strength specified\n"; - return TCL_ERROR; - } - y++; - - if ((strcmp(argv[y], "beamtop") == 0) || - (strcmp(argv[y], "beamTop") == 0) || - (strcmp(argv[y], "beambot") == 0) || - (strcmp(argv[y], "beamBot") == 0) || - (strcmp(argv[y], "beambottom") == 0) || - (strcmp(argv[y], "beamBottom") == 0) || - (strcmp(argv[y], "beam") == 0) || (strcmp(argv[y], "Beam") == 0) || - (strcmp(argv[y], "Column") == 0) || - (strcmp(argv[y], "column") == 0)) { - if ((strcmp(argv[y], "beamtop") == 0) || - (strcmp(argv[y], "beamTop") == 0) || - (strcmp(argv[y], "beam") == 0) || (strcmp(argv[y], "Beam") == 0)) { - typ = 0; - } - - if ((strcmp(argv[y], "beambot") == 0) || - (strcmp(argv[y], "beamBot") == 0) || - (strcmp(argv[y], "beambottom") == 0) || - (strcmp(argv[y], "beamBottom") == 0)) { - typ = 1; - } - - if ((strcmp(argv[y], "column") == 0) || - (strcmp(argv[y], "Column") == 0)) { - typ = 2; - } - } else { - opserr << G3_ERROR_PROMPT << "invalid location of bar specified\n"; - return TCL_ERROR; - } - if (argc == 17) { - y++; - - if ((strcmp(argv[y], "damage1") == 0) || - (strcmp(argv[y], "Damage1") == 0) || - (strcmp(argv[y], "damage2") == 0) || - (strcmp(argv[y], "Damage2") == 0) || - (strcmp(argv[y], "nodamage") == 0) || - (strcmp(argv[y], "Nodamage") == 0) || - (strcmp(argv[y], "NoDamage") == 0) || - (strcmp(argv[y], "noDamage") == 0)) { - if ((strcmp(argv[y], "damage1") == 0) || - (strcmp(argv[y], "Damage1") == 0)) { - dmg = 1; - } else if ((strcmp(argv[y], "damage2") == 0) || - (strcmp(argv[y], "Damage2") == 0)) { - dmg = 2; - } else if ((strcmp(argv[y], "nodamage") == 0) || - (strcmp(argv[y], "Nodamage") == 0) || - (strcmp(argv[y], "NoDamage") == 0) || - (strcmp(argv[y], "noDamage") == 0)) { - dmg = 0; - } - - } else { - opserr << G3_ERROR_PROMPT << "invalid damage specified\n"; - return TCL_ERROR; - } - - y++; - - if ((strcmp(argv[y], "mpa") == 0) || (strcmp(argv[y], "MPa") == 0) || - (strcmp(argv[y], "mPa") == 0) || (strcmp(argv[y], "Mpa") == 0) || - (strcmp(argv[y], "psi") == 0) || (strcmp(argv[y], "Psi") == 0) || - (strcmp(argv[y], "PSI") == 0) || (strcmp(argv[y], "Pa") == 0) || - (strcmp(argv[y], "pa") == 0) || (strcmp(argv[y], "psf") == 0) || - (strcmp(argv[y], "Psf") == 0) || (strcmp(argv[y], "PSF") == 0) || - (strcmp(argv[y], "ksi") == 0) || (strcmp(argv[y], "Ksi") == 0) || - (strcmp(argv[y], "KSI") == 0) || (strcmp(argv[y], "ksf") == 0) || - (strcmp(argv[y], "Ksf") == 0) || (strcmp(argv[y], "KSF") == 0)) { - if ((strcmp(argv[y], "mpa") == 0) || (strcmp(argv[y], "MPa") == 0) || - (strcmp(argv[y], "mPa") == 0) || (strcmp(argv[y], "Mpa") == 0)) { - unt = 1; - } else if ((strcmp(argv[y], "psi") == 0) || - (strcmp(argv[y], "Psi") == 0) || - (strcmp(argv[y], "PSI") == 0)) { - unt = 2; - } else if ((strcmp(argv[y], "Pa") == 0) || - (strcmp(argv[y], "pa") == 0)) { - unt = 3; - } else if ((strcmp(argv[y], "psf") == 0) || - (strcmp(argv[y], "Psf") == 0) || - (strcmp(argv[y], "PSF") == 0)) { - unt = 4; - } else if ((strcmp(argv[y], "ksi") == 0) || - (strcmp(argv[y], "Ksi") == 0) || - (strcmp(argv[y], "KSI") == 0)) { - unt = 5; - } else if ((strcmp(argv[y], "ksf") == 0) || - (strcmp(argv[y], "Ksf") == 0) || - (strcmp(argv[y], "KSF") == 0)) { - unt = 6; - } - } else { - opserr << G3_ERROR_PROMPT << "invalid unit specified\n"; - return TCL_ERROR; - } - } - - // allocate the material - if (argc == 15) { - theMaterial = new BarSlipMaterial(tag, fc, fy, Es, fu, Eh, db, ld, nb, - width, depth, bsf, typ); - } - - if (argc == 17) { - theMaterial = new BarSlipMaterial(tag, fc, fy, Es, fu, Eh, db, ld, nb, - width, depth, bsf, typ, dmg, unt); - } - - } - - else if (strcmp(argv[1], "ShearPanel") == 0) { - if (argc != 42 && argc != 31) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial ShearPanel tag? stress1p? strain1p? " - "stress2p? strain2p? stress3p? strain3p? stress4p? strain4p? " - << "\n rDispP? rForceP? uForceP? " - << "\n gammaK1? gammaK2? gammaK3? " - "gammaK4? gammaKLimit? gammaD1? gammaD2? gammaD3? gammaD4? " - << "\ngammaDLimit? gammaF1? gammaF2? gammaF3? gammaF4? " - "gammaFLimit? gammaE? YieldStress? "; - return TCL_ERROR; - } - - int tag; - double stress1p, stress2p, stress3p, stress4p; - double strain1p, strain2p, strain3p, strain4p; - double stress1n, stress2n, stress3n, stress4n; - double strain1n, strain2n, strain3n, strain4n; - double rDispP, rForceP, uForceP, rDispN, rForceN, uForceN; - double gammaK1, gammaK2, gammaK3, gammaK4, gammaKLimit; - double gammaD1, gammaD2, gammaD3, gammaD4, gammaDLimit; - double gammaF1, gammaF2, gammaF3, gammaF4, gammaFLimit; - double gammaE, yStr; - - int i = 2; - - if (Tcl_GetInt(interp, argv[i++], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid uniaxialMaterial ShearPanel tag" << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &stress1p) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid stress1p\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &strain1p) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid strain1p\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &stress2p) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid stress2p\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &strain2p) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid strain2p\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &stress3p) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid stress3p\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &strain3p) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid strain3p\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &stress4p) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid stress4p\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &strain4p) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid strain4p\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (argc == 42) { - if (Tcl_GetDouble(interp, argv[i++], &stress1n) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid stress1n\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &strain1n) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid strain1n\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &stress2n) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid stress2n\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &strain2n) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid strain2n\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &stress3n) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid stress3n\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &strain3n) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid strain3n\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &stress4n) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid stress4n\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &strain4n) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid strain4n\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - } - - if (Tcl_GetDouble(interp, argv[i++], &rDispP) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid rDispP\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &rForceP) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid rForceP\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &uForceP) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid uForceP\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (argc == 42) { - if (Tcl_GetDouble(interp, argv[i++], &rDispN) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid rDispN\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &rForceN) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid rForceN\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &uForceN) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid uForceN\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - } - - if (Tcl_GetDouble(interp, argv[i++], &gammaK1) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaK1\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaK2) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaK2\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaK3) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaK3\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaK4) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaK4\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaKLimit) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaKLimit\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaD1) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaD1\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaD2) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaD2\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaD3) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaD3\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaD4) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaD4\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaDLimit) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaDLimit\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaF1) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaF1\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaF2) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaF2\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaF3) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaF3\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaF4) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaF4\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - if (Tcl_GetDouble(interp, argv[i++], &gammaFLimit) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaFLimit\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &gammaE) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid gammaE\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[i++], &yStr) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid yield stress\n"; - opserr << "ShearPanel material: " << tag << "\n"; - return TCL_ERROR; - } - - // allocate the pinching material - if (argc == 42) { - theMaterial = new ShearPanelMaterial( - tag, stress1p, strain1p, stress2p, strain2p, stress3p, strain3p, - stress4p, strain4p, stress1n, strain1n, stress2n, strain2n, - stress3n, strain3n, stress4n, strain4n, rDispP, rForceP, uForceP, - rDispN, rForceN, uForceN, gammaK1, gammaK2, gammaK3, gammaK4, - gammaKLimit, gammaD1, gammaD2, gammaD3, gammaD4, gammaDLimit, - gammaF1, gammaF2, gammaF3, gammaF4, gammaFLimit, gammaE, yStr); - } - if (argc == 31) { - theMaterial = new ShearPanelMaterial( - tag, stress1p, strain1p, stress2p, strain2p, stress3p, strain3p, - stress4p, strain4p, rDispP, rForceP, uForceP, gammaK1, gammaK2, - gammaK3, gammaK4, gammaKLimit, gammaD1, gammaD2, gammaD3, gammaD4, - gammaDLimit, gammaF1, gammaF2, gammaF3, gammaF4, gammaFLimit, - gammaE, yStr); - } - } - - else if (strcmp(argv[1], "Concrete01WithSITC") == 0) { - if (argc < 7) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial Concrete01 tag? fpc? epsc0? fpcu? " - "epscu? " - << "\n"; - return TCL_ERROR; - } - - int tag; - - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid uniaxialMaterial Concrete01 tag" << "\n"; - return TCL_ERROR; - } - - // Read required Concrete01 material parameters - double fpc, epsc0, fpcu, epscu; - - if (Tcl_GetDouble(interp, argv[3], &fpc) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid fpc\n"; - opserr << "Concrete01 material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[4], &epsc0) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid epsc0\n"; - opserr << "Concrete01 material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[5], &fpcu) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid fpcu\n"; - opserr << "Concrete01 material: " << tag << "\n"; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[6], &epscu) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid epscu\n"; - opserr << "Concrete01 material: " << tag << "\n"; - return TCL_ERROR; - } - - if (argc == 7) - // Parsing was successful, allocate the material - theMaterial = new Concrete01WithSITC(tag, fpc, epsc0, fpcu, epscu); - else { - double endStrainSITC; - if (Tcl_GetDouble(interp, argv[7], &endStrainSITC) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid epscu\n"; - opserr << "Concrete01 material: " << tag << "\n"; - return TCL_ERROR; - } - theMaterial = - new Concrete01WithSITC(tag, fpc, epsc0, fpcu, epscu, endStrainSITC); - } - } - - if (theMaterial == nullptr) - return TCL_ERROR; - - if (builder->addTaggedObject(*theMaterial) != TCL_OK) { + opserr << OpenSees::PromptValueError << "Could not add uniaxialMaterial to the model builder.\n"; delete theMaterial; return TCL_ERROR; } @@ -958,67 +218,10 @@ TclDispatch_LegacyUniaxials(ClientData clientData, Tcl_Interp* interp, int argc, return TCL_OK; } -#include -static int -TclCommand_newUniaxialJ2Plasticity(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char** const argv) -{ - // ----- 1D J2 Plasticity ---- - if (argc < 7) { - opserr << "WARNING invalid number of arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial UniaxialJ2Plasticity tag? E? sigmaY? " - "Hkin? " - << endln; - return TCL_ERROR; - } - int tag; - double E, sigmaY, Hkin, Hiso; - Hiso = 0.0; - if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial UniaxialJ2Plasticity tag" - << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { - opserr << "WARNING invalid E\n"; - opserr << "uniaxiaMaterial UniaxialJ2Plasticity: " << tag << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[4], &sigmaY) != TCL_OK) { - opserr << "WARNING invalid sigmaY\n"; - opserr << "uniaxiaMaterial UniaxialJ2Plasticity: " << tag << endln; - return TCL_ERROR; - } - - if (Tcl_GetDouble(interp, argv[5], &Hkin) != TCL_OK) { - opserr << "WARNING invalid Hkin\n"; - opserr << "uniaxiaMaterial SmoothPSConcrete: " << tag << endln; - return TCL_ERROR; - } - - if (argc >= 7) - if (Tcl_GetDouble(interp, argv[6], &Hiso) != TCL_OK) { - opserr << "WARNING invalid Hiso\n"; - opserr << "uniaxialMaterial UniaxialJ2Plasticity: " << tag << endln; - return TCL_ERROR; - } - - // Parsing was successful, allocate the material - UniaxialMaterial* theMaterial = new UniaxialJ2Plasticity(tag, E, sigmaY, Hkin, Hiso); - - assert(clientData != nullptr); - BasicModelBuilder *builder = static_cast(clientData); - builder->addTaggedObject(*theMaterial); - return TCL_OK; -} - - -#include // NM +#include // NM static int TclDispatch_newUniaxialPinching4(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char ** const argv) { @@ -1028,7 +231,7 @@ TclDispatch_newUniaxialPinching4(ClientData clientData, Tcl_Interp* interp, int if (strcmp(argv[1], "Pinching4") == 0) { if (argc != 42 && argc != 31) { - opserr << G3_ERROR_PROMPT << "insufficient arguments\n"; + opserr << OpenSees::PromptValueError << "insufficient arguments\n"; opserr << "Want: uniaxialMaterial Pinching4 tag? stress1p? strain1p? " "stress2p? strain2p? stress3p? strain3p? stress4p? strain4p? " << "\n #include #include +#include #include #include -#include +#include + +// Viscous +extern OPS_Routine OPS_Maxwell; +extern OPS_Routine OPS_ViscousDamper; +extern OPS_Routine OPS_ViscousMaterial; +extern OPS_Routine OPS_ViscoelasticGap; +extern OPS_Routine OPS_DamperMaterial; + extern OPS_Routine OPS_ASD_SMA_3K; +extern OPS_Routine OPS_ASDConcrete1DMaterial; extern OPS_Routine OPS_APDFMD; extern OPS_Routine OPS_APDMD; extern OPS_Routine OPS_APDVFD; -extern OPS_Routine OPS_BWBN; extern OPS_Routine OPS_Bilin02; extern OPS_Routine OPS_Bilin; extern OPS_Routine OPS_BilinearOilDamper; extern OPS_Routine OPS_Bond_SP01; -extern OPS_Routine OPS_BoucWenOriginal; extern OPS_Routine OPS_CFSSSWP; extern OPS_Routine OPS_CFSWSWP; extern OPS_Routine OPS_CableMaterial; extern OPS_Routine OPS_Cast; extern OPS_Routine OPS_CreepMaterial; - -extern OPS_Routine OPS_Concrete01; +// Concrete extern OPS_Routine OPS_Concrete02; extern OPS_Routine OPS_Concrete02IS; extern OPS_Routine OPS_Concrete02Thermal; @@ -42,13 +59,11 @@ extern OPS_Routine OPS_ConcreteL01Material; extern OPS_Routine OPS_ConcreteSakaiKawashima; extern OPS_Routine OPS_ConcreteZ01Material; extern OPS_Routine OPS_ConfinedConcrete01Material; -extern OPS_Routine OPS_DamperMaterial; -extern OPS_Routine OPS_DegradingPinchedBW; + extern OPS_Routine OPS_DoddRestr; extern OPS_Routine OPS_Dodd_Restrepo; extern OPS_Routine OPS_EPPGapMaterial; extern OPS_Routine OPS_ElasticBilin; -extern OPS_Routine OPS_ElasticMaterial; extern OPS_Routine OPS_ElasticMaterialThermal; extern OPS_Routine OPS_ElasticMultiLinear; extern OPS_Routine OPS_ElasticPPMaterial; @@ -59,10 +74,8 @@ extern OPS_Routine OPS_FRPConfinedConcrete; extern OPS_Routine OPS_GMG_CyclicReinforcedConcrete; extern OPS_Routine OPS_FRCC; extern OPS_Routine OPS_GNGMaterial; -extern OPS_Routine OPS_HardeningMaterial; extern OPS_Routine OPS_HoehlerStanton; extern OPS_Routine OPS_HookGap; -extern OPS_Routine OPS_HyperbolicGapMaterial; extern OPS_Routine OPS_HystereticMaterial; extern OPS_Routine OPS_HystereticPoly; extern OPS_Routine OPS_HystereticAsym; @@ -73,18 +86,14 @@ extern OPS_Routine OPS_IMKPeakOriented; extern OPS_Routine OPS_IMKPinching; extern OPS_Routine OPS_JankowskiImpact; extern OPS_Routine OPS_ImpactMaterial; -extern OPS_Routine OPS_InitStrainMaterial; -extern OPS_Routine OPS_InitStressMaterial; extern OPS_Routine OPS_Masonry; extern OPS_Routine OPS_Masonryt; -extern OPS_Routine OPS_Maxwell; extern OPS_Routine OPS_MinMaxMaterial; extern OPS_Routine OPS_ModIMKPeakOriented02; extern OPS_Routine OPS_ModIMKPeakOriented; extern OPS_Routine OPS_ModIMKPinching; extern OPS_Routine OPS_ModIMKPinching02; extern OPS_Routine OPS_MultiLinear; -extern OPS_Routine OPS_OOHystereticMaterial; extern OPS_Routine OPS_OriginCentered; extern OPS_Routine OPS_PinchingLimitState; extern OPS_Routine OPS_PinchingLimitStateMaterial; @@ -98,21 +107,17 @@ extern OPS_Routine OPS_SAWSMaterial; extern OPS_Routine OPS_SLModel; extern OPS_Routine OPS_SMAMaterial; extern OPS_Routine OPS_SPSW02; // SAJalali -extern OPS_Routine OPS_SeriesMaterial; extern OPS_Routine OPS_SimpleFractureMaterial; + extern OPS_Routine OPS_StainlessECThermal; -extern OPS_Routine OPS_Steel01; -extern OPS_Routine OPS_Steel01Thermal; -extern OPS_Routine OPS_Steel02; -extern OPS_Routine OPS_Steel02Fatigue; -extern OPS_Routine OPS_Steel02Thermal; -extern OPS_Routine OPS_Steel2; -extern OPS_Routine OPS_Steel4; extern OPS_Routine OPS_SteelBRB; extern OPS_Routine OPS_SteelECThermal; extern OPS_Routine OPS_SteelFractureDI; // galvisf extern OPS_Routine OPS_SteelMPF; extern OPS_Routine OPS_SteelZ01Material; +extern OPS_Routine OPS_Steel02Fatigue; +extern OPS_Routine OPS_Steel4; + extern OPS_Routine OPS_TDConcrete; // ntosic extern OPS_Routine OPS_TDConcreteEXP; // ntosic extern OPS_Routine OPS_TDConcreteMC10; // ntosic @@ -121,13 +126,10 @@ extern OPS_Routine OPS_TendonL01Material; extern OPS_Routine OPS_Trilinwp2; extern OPS_Routine OPS_Trilinwp; extern OPS_Routine OPS_UVCuniaxial; -extern OPS_Routine OPS_ViscousDamper; -extern OPS_Routine OPS_ViscousMaterial; -extern OPS_Routine OPS_ViscoelasticGap; extern OPS_Routine OPS_pyUCLA; +extern void *OPS_ConcretewBeta(); -extern void *OPS_ConcretewBeta(void); - +extern Tcl_CmdProc Create_OOHystereticMaterial; typedef UniaxialMaterial*(G3_TclUniaxialPackage)(ClientData, Tcl_Interp *, int, TCL_Char ** const); G3_TclUniaxialPackage TclBasicBuilder_addFedeasMaterial; @@ -137,33 +139,47 @@ std::unordered_map tcl_uniaxial_package_ta {"DRAIN", TclBasicBuilder_addDrainMaterial }, {"SNAP", TclBasicBuilder_addSnapMaterial }, {"snap", TclBasicBuilder_addSnapMaterial }, -// #if defined(_STEEL2) || defined(OPSDEF_UNIAXIAL_FEDEAS) -//{"FEDEAS", TclBasicBuilder_addFedeasMaterial}, -// #endif }; -typedef UniaxialMaterial* (TclDispatch_UniaxialMaterial)(G3_Runtime*, int, TCL_Char ** const); -TclDispatch_UniaxialMaterial TclCommand_ReinforcingSteel; - -static Tcl_CmdProc TclCommand_newFatigueMaterial; -static Tcl_CmdProc TclCommand_newUniaxialJ2Plasticity; - -Tcl_CmdProc TclCommand_newFedeasUniaxialDamage; -Tcl_CmdProc TclCommand_ContinuumUniaxialMaterial; +// Elastic +extern Tcl_CmdProc TclCommand_newElasticUniaxialMaterial; +// Plastic +extern Tcl_CmdProc TclCommand_newPlasticMaterial; +extern Tcl_CmdProc TclCommand_newUniaxialJ2Plasticity; +// Fedeas +extern Tcl_CmdProc TclCommand_newFedeasSteel; +extern Tcl_CmdProc TclCommand_newFedeasUniaxialDamage; +extern Tcl_CmdProc TclCommand_newFedeasConcrete; +// Wrapper +extern Tcl_CmdProc TclCommand_addWrappingMaterial; +extern Tcl_CmdProc TclCommand_newFatigueMaterial; +extern Tcl_CmdProc TclCommand_newParallelMaterial; +extern OPS_Routine OPS_SeriesMaterial; +// Bearing Tcl_CmdProc TclCommand_AxialSp; Tcl_CmdProc TclCommand_AxialSpHD; Tcl_CmdProc TclCommand_KikuchiAikenHDR; Tcl_CmdProc TclCommand_KikuchiAikenLRB; +// Concrete Tcl_CmdProc TclCommand_newUniaxialConcrete04; Tcl_CmdProc TclCommand_newUniaxialConcrete06; Tcl_CmdProc TclCommand_newUniaxialConcrete07; -Tcl_CmdProc TclCommand_newUniaxialBoucWen; -Tcl_CmdProc TclCommand_newParallelMaterial; - -// typedef int (TclCommand_UniaxialMaterial)(ClientData, Tcl_Interp*, int, TCL_Char ** const); +// Bouc-Wen +extern Tcl_CmdProc TclCommand_newBoucWen; +extern Tcl_CmdProc TclCommand_newUniaxialBoucWen; +extern Tcl_CmdProc TclCommand_newBoucWenMG; +extern OPS_Routine OPS_DegradingPinchedBW; +// Abutment +Tcl_CmdProc TclCommand_HyperbolicGapMaterial; +// Other static Tcl_CmdProc TclDispatch_newUniaxialPinching4; -static Tcl_CmdProc TclDispatch_LegacyUniaxials; +extern Tcl_CmdProc TclDispatch_LegacyUniaxials; + + +typedef UniaxialMaterial* (TclDispatch_UniaxialMaterial)(G3_Runtime*, int, TCL_Char ** const); +TclDispatch_UniaxialMaterial TclCommand_ReinforcingSteel; + template static int dispatch(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char** const argv) @@ -173,7 +189,7 @@ dispatch(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char** const ar UniaxialMaterial* theMaterial = (UniaxialMaterial*)fn( rt, argc, argv ); if (builder->addTaggedObject(*theMaterial) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "Could not add uniaxialMaterial to the model builder.\n"; + opserr << OpenSees::PromptValueError << "Failed to add UniaxialMaterial to the model builder.\n"; delete theMaterial; return TCL_ERROR; } @@ -189,7 +205,7 @@ dispatch(ClientData clientData, Tcl_Interp* interp, int argc, TCL_Char** const a UniaxialMaterial* theMaterial = fn( rt, argc, argv ); if (builder->addTaggedObject(*theMaterial) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "Could not add uniaxialMaterial to the model builder.\n"; + opserr << OpenSees::PromptValueError << "Could not add uniaxialMaterial to the model builder.\n"; delete theMaterial; return TCL_ERROR; } @@ -204,74 +220,40 @@ dispatch(ClientData clientData, Tcl_Interp* interp, int argc, G3_Char** const ar return fn( clientData, interp, argc, argv ); } -#if 0 -class broker_ { - Tcl_CmdProc* parse; - virtual UniaxialMaterial* alloc(); -}; - -template class broker: public broker_ { - broker(Tcl_CmdProc* parse_): parse(parse_) {}; -}; - -std::unordered_map uniaxial_dispatch_2 { - {"Concrete01", broker<>(dispatch) }, - {"Concrete02", dispatch }, -}; -#endif - std::unordered_map uniaxial_dispatch { - {"APDFMD", dispatch }, - {"APDMD", dispatch }, - {"APDVFD", dispatch }, - - {"FedeasUniaxialDamage", dispatch }, - {"KikuchiAikenHDR", dispatch }, - {"KikuchiAikenLRB", dispatch }, - - {"AxialSp", dispatch }, - {"AxialSpHD", dispatch }, - {"ContinuumUniaxial", dispatch}, - - {"Concrete04", dispatch }, - {"Concrete06", dispatch }, - {"Concrete07", dispatch }, -#if 0 - { "ConcretewBeta", dispatch } -#endif - {"Ratchet", dispatch }, -// {"ReinforcingSteel", dispatch }, - {"ReinforcingSteel", dispatch< OPS_ReinforcingSteel> }, - {"Parallel", dispatch }, - {"BoucWen", dispatch }, - - {"Elastic", dispatch }, - - {"Concrete01", dispatch }, - {"Concrete02", dispatch }, - - {"Bond_SP01", dispatch }, - {"Bond", dispatch }, - - {"Fatigue", dispatch }, -// Composites - {"MinMaxMaterial", dispatch }, - {"MinMax", dispatch }, - - {"Series", dispatch }, - -// Steels - - {"Steel01", dispatch }, - - {"Steel02", dispatch }, + {"Elastic", dispatch}, +// +// Plasticity +// + {"ElasticPP", dispatch }, + {"UniaxialJ2Plasticity", dispatch }, + {"UVCuniaxial", dispatch }, + {"Hardening", dispatch }, + {"Hardening2", dispatch }, +// +// Bouc +// + {"BWBF", dispatch }, + {"BWBN", dispatch }, + {"BoucWenOriginal", dispatch }, + {"BoucWen", dispatch }, + {"BoucWenMG", dispatch }, + {"DegradingPinchedBW", dispatch }, +// +// Steel +// + {"Steel", dispatch}, + {"Steel01", dispatch }, + {"Steel02", dispatch }, + {"Steel2", dispatch }, {"Steel4", dispatch }, - + {"RambergOsgood", dispatch }, + {"RambergOsgoodSteel", dispatch }, + {"ReinforcingSteel", dispatch }, +// {"ReinforcingSteel", dispatch }, {"SteelBRB", dispatch }, - {"SteelFractureDI", dispatch }, - {"Steel02Fatigue", dispatch }, {"Dodd_Restrepo", dispatch }, @@ -282,13 +264,82 @@ std::unordered_map uniaxial_dispatch { {"DoddRestr", dispatch }, #endif + {"SteelZ01Material", dispatch }, + {"SteelZ01", dispatch }, -// Piles - {"PySimple3", dispatch }, +// Concretes + {"Concrete01", dispatch }, + {"Concrete02", dispatch }, + {"Concrete04", dispatch }, + {"Concrete06", dispatch }, + {"Concrete07", dispatch }, + {"Concrete02IS", dispatch }, + {"ConcreteCM", dispatch }, + {"ConfinedConcrete01", dispatch}, + {"ConfinedConcrete", dispatch}, + + {"ConcreteZ01Material", dispatch }, + {"ConcreteZ01", dispatch }, +// +// Viscous +// + {"Maxwell", dispatch }, + {"MaxwellMaterial", dispatch }, + {"ViscousDamper", dispatch }, + {"DamperMaterial", dispatch }, + {"BilinearOilDamper", dispatch }, +// +// Multilinear +// + {"BilinMaterial", dispatch }, + {"Bilin", dispatch }, + {"MultiLinear", dispatch }, + {"IMKBilin", dispatch }, + {"IMKPeakOriented", dispatch }, + {"IMKPinching", dispatch }, + {"ModIMKPinching", dispatch }, + {"ModIMKPinching02", dispatch }, + {"ModIMKPeakOriented", dispatch }, + {"ModIMKPeakOriented02", dispatch }, + {"Bilin02", dispatch }, +// Piles + {"PySimple3", dispatch }, + +// +// Wrappers +// + {"InitStrainMaterial", dispatch}, + {"InitialStrain", dispatch}, + {"InitStrain", dispatch}, + {"InitStressMaterial", dispatch}, + {"InitialStress", dispatch}, + {"InitStress", dispatch}, + {"ContinuumUniaxial", dispatch}, + {"MinMaxMaterial", dispatch }, + {"MinMax", dispatch }, + {"Series", dispatch }, + {"Parallel", dispatch}, + {"Ratchet", dispatch }, + {"Fatigue", dispatch }, + // Other + {"GNG", dispatch }, + {"Bond_SP01", dispatch }, + {"Bond", dispatch }, + {"APDFMD", dispatch }, + {"APDMD", dispatch }, + {"APDVFD", dispatch }, + + {"FedeasUniaxialDamage", dispatch }, + {"KikuchiAikenHDR", dispatch }, + {"KikuchiAikenLRB", dispatch }, + + {"AxialSp", dispatch }, + {"AxialSpHD", dispatch }, + /* {"PlateBearingConnectionThermal", OPS_PlateBearingConnectionThermal}, {"PinchingLimitStateMaterial", OPS_PinchingLimitState }, @@ -301,27 +352,9 @@ std::unordered_map uniaxial_dispatch { {"ImpactMaterial", dispatch }, {"Impact", dispatch }, - {"UVCuniaxial", dispatch }, - {"GNG", dispatch }, - {"SimpleFractureMaterial", dispatch }, {"SimpleFracture", dispatch }, - - {"Maxwell", dispatch }, - {"MaxwellMaterial", dispatch }, - - {"ViscousDamper", dispatch }, - - {"DamperMaterial", dispatch }, - -// Concretes - {"Concrete02IS", dispatch }, - {"ConcreteCM", dispatch }, - {"ConfinedConcrete01", dispatch}, - {"ConfinedConcrete", dispatch}, - - {"BilinearOilDamper", dispatch }, - +// {"Cast", dispatch }, {"CastFuse", dispatch }, @@ -330,22 +363,15 @@ std::unordered_map uniaxial_dispatch { /* {"HoehlerStanton", dispatch }, -*/ +*/ {"SLModel", dispatch }, - {"RambergOsgood", dispatch }, - {"RambergOsgoodSteel", dispatch }, - - {"ReinforcingSteel", dispatch }, - - {"Steel2", dispatch }, - {"OriginCentered", dispatch }, {"HookGap", dispatch }, - {"HyperbolicGapMaterial", dispatch }, + {"HyperbolicGapMaterial", dispatch}, {"FRPConfinedConcrete02", dispatch }, {"FRCC", dispatch }, @@ -353,43 +379,15 @@ std::unordered_map uniaxial_dispatch { {"PinchingLimitState", dispatch }, - {"InitStrainMaterial", dispatch }, - {"InitStrain", dispatch }, - - {"InitStressMaterial", dispatch }, - {"InitStress", dispatch }, - {"pyUCLA", dispatch }, {"PYUCLA", dispatch }, - {"MultiLinear", dispatch }, - - {"BWBN", dispatch }, - - {"DegradingPinchedBW", dispatch }, - - {"IMKBilin", dispatch }, - - {"IMKPeakOriented", dispatch }, - {"IMKPinching", dispatch }, {"JankowskiImpact", dispatch }, - {"ModIMKPinching", dispatch }, - {"ModIMKPinching02", dispatch }, - - {"ModIMKPeakOriented", dispatch }, - - {"ModIMKPeakOriented02", dispatch }, - - {"Bilin02", dispatch }, - - {"BoucWenOriginal", dispatch }, - // Thermal - {"Steel01Thermal", dispatch }, - - {"Steel02Thermal", dispatch }, + {"Steel01Thermal", dispatch }, + {"Steel02Thermal", dispatch }, {"SteelECThermal", dispatch }, @@ -400,7 +398,7 @@ std::unordered_map uniaxial_dispatch { {"ConcreteECThermal", dispatch }, {"Concrete02Thermal", dispatch }, - +// {"ConcreteD", dispatch }, {"ConcreteSakaiKawashima", dispatch }, @@ -412,7 +410,6 @@ std::unordered_map uniaxial_dispatch { {"ResilienceMaterialHR", dispatch }, {"CFSWSWP", dispatch }, - {"CFSSSWP", dispatch }, {"FRPConfinedConcrete", dispatch }, @@ -425,17 +422,8 @@ std::unordered_map uniaxial_dispatch { {"Masonryt", dispatch }, - {"ElasticPP", dispatch }, - {"UniaxialJ2Plasticity", dispatch }, - - {"Hardening", dispatch }, - {"Hardening2", dispatch }, - - {"BilinMaterial", dispatch }, - {"Bilin", dispatch }, {"Hysteretic", dispatch }, - {"HystereticAsym", dispatch }, {"HystereticSmooth", dispatch }, {"HystereticSMMaterial", dispatch }, @@ -443,7 +431,7 @@ std::unordered_map uniaxial_dispatch { {"ElasticPPGap", dispatch }, - {"OOHysteretic", dispatch }, + {"OOHysteretic", dispatch }, {"Viscous", dispatch }, {"ViscoelasticGap", dispatch }, @@ -451,17 +439,12 @@ std::unordered_map uniaxial_dispatch { {"SAWSMaterial", dispatch }, {"SAWS", dispatch }, - {"ConcreteZ01Material", dispatch }, - {"ConcreteZ01", dispatch }, {"ConcreteL01Material", dispatch }, {"ConcreteL01", dispatch }, {"Creep", dispatch }, - {"SteelZ01Material", dispatch }, - {"SteelZ01", dispatch }, - {"TendonL01Material", dispatch }, {"TendonL01", dispatch }, @@ -471,20 +454,20 @@ std::unordered_map uniaxial_dispatch { {"ASD_SMA_3K", dispatch }, + {"ASDConcrete1D", dispatch }, + {"HystereticPoly", dispatch }, {"SPSW02", dispatch }, {"TDConcreteEXP", dispatch }, - {"TDConcrete", dispatch }, - {"TDConcreteMC10", dispatch }, - {"TDConcreteMC10NL", dispatch }, - {"Pinching4", TclDispatch_newUniaxialPinching4 }, + {"Pinching4", TclDispatch_newUniaxialPinching4 }, +// Legacy {"Elastic2", TclDispatch_LegacyUniaxials }, {"ENT", TclDispatch_LegacyUniaxials }, {"BarSlip", TclDispatch_LegacyUniaxials }, diff --git a/SRC/runtime/commands/modeling/uniaxialMaterial.cpp b/SRC/runtime/commands/modeling/uniaxialMaterial.cpp index 20e36b8ecf..e350843504 100644 --- a/SRC/runtime/commands/modeling/uniaxialMaterial.cpp +++ b/SRC/runtime/commands/modeling/uniaxialMaterial.cpp @@ -1,15 +1,24 @@ -/* ****************************************************************** ** -** Opensee - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ****************************************************************** */ +//===----------------------------------------------------------------------===// // +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// // Description: This file contains the function invoked when the user invokes // the uniaxialMaterial command in the interpreter. +//===----------------------------------------------------------------------===// // // Written: fmk, MHS // Created: 07/99 // -// #include #include #include @@ -21,10 +30,12 @@ #include // KM #include // Won Lee #include // Won Lee + #include #include #include // LMS #include // JDW + #include // MHS #include // Mackie #include // MHS @@ -76,11 +87,9 @@ extern OPS_Routine OPS_Cast; extern OPS_Routine OPS_DoddRestr; extern OPS_Routine OPS_ElasticMultiLinear; extern OPS_Routine OPS_HookGap; -extern OPS_Routine OPS_HyperbolicGapMaterial; extern OPS_Routine OPS_FRPConfinedConcrete; extern OPS_Routine OPS_FRPConfinedConcrete02; extern OPS_Routine OPS_UVCuniaxial; -extern OPS_Routine OPS_Steel01Thermal; extern OPS_Routine OPS_Concrete02Thermal; extern OPS_Routine OPS_StainlessECThermal; // L.Jiang [SIF] extern OPS_Routine OPS_SteelECThermal; // L.Jiang [SIF] @@ -95,11 +104,10 @@ extern OPS_Routine OPS_ModIMKPeakOriented; extern OPS_Routine OPS_ModIMKPeakOriented02; extern OPS_Routine OPS_ModIMKPinching; extern OPS_Routine OPS_ModIMKPinching02; -extern void *OPS_ConcretewBeta(void); +extern void *OPS_ConcretewBeta(); extern OPS_Routine OPS_ConcreteD; extern OPS_Routine OPS_PinchingLimitState; extern OPS_Routine OPS_OriginCentered; -extern OPS_Routine OPS_Steel2; extern OPS_Routine OPS_ConcreteSakaiKawashima; extern OPS_Routine OPS_ResilienceMaterialHR; extern OPS_Routine OPS_CFSSSWP; @@ -108,7 +116,6 @@ extern OPS_Routine OPS_ResilienceLow; extern OPS_Routine OPS_ViscousMaterial; extern OPS_Routine OPS_SteelMPF; // K Kolozvari extern OPS_Routine OPS_Bond_SP01; // K Kolozvari -extern OPS_Routine OPS_OOHystereticMaterial; extern OPS_Routine OPS_ElasticPowerFunc; extern OPS_Routine OPS_UVCuniaxial; extern OPS_Routine OPS_DegradingPinchedBW; @@ -135,31 +142,12 @@ typedef struct uniaxialPackageCommand { static UniaxialPackageCommand *theUniaxialPackageCommands = NULL; -static void -printCommand(int argc, TCL_Char ** const argv) -{ - opserr << "Input command: "; - for (int i = 0; i < argc; ++i) - opserr << argv[i] << " "; - opserr << endln; -} - -// external functions - -Tcl_CmdProc TclCommand_KikuchiAikenHDR; -Tcl_CmdProc TclCommand_KikuchiAikenLRB; -UniaxialMaterial *TclBasicBuilder_addDrainMaterial(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv); - -UniaxialMaterial *TclBasicBuilder_addSnapMaterial(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv); - -UniaxialMaterial *TclBasicBuilder_addPyTzQzMaterial(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv, - Domain *theDomain); - -UniaxialMaterial *TclBasicBuilder_FRPCnfinedConcrete(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv, - Domain *theDomain); - -UniaxialMaterial *TclBasicBuilder_addDegradingMaterial(ClientData, Tcl_Interp *, int, TCL_Char **); +UniaxialMaterial *TclBasicBuilder_addDrainMaterial(ClientData, Tcl_Interp *, int argc, TCL_Char ** const argv); +UniaxialMaterial *TclBasicBuilder_addSnapMaterial(ClientData, Tcl_Interp *, int argc, TCL_Char ** const argv); +UniaxialMaterial *TclBasicBuilder_addPyTzQzMaterial(ClientData, Tcl_Interp *, int argc, TCL_Char ** const argv, Domain *); +UniaxialMaterial *TclBasicBuilder_FRPCnfinedConcrete(ClientData, Tcl_Interp *, int argc, TCL_Char ** const argv, Domain *); +UniaxialMaterial *TclBasicBuilder_adDegradingMaterial(ClientData, Tcl_Interp *, int, TCL_Char **); extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, Tcl_Interp *interp, int cArg, int mArg, TCL_Char ** const argv, Domain *domain); @@ -174,7 +162,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (argc < 3) { opserr << "WARNING insufficient number of uniaxial material arguments\n"; opserr << "Want: uniaxialMaterial type? tag? " - << endln; + << "\n"; return TCL_ERROR; } @@ -188,15 +176,6 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp return TCL_ERROR; -#if 0 - } else if (strcmp(argv[1],"HoehlerStanton") == 0) { - void *theMat = OPS_HoehlerStanton(rt, argc, argv); - if (theMat != 0) - theMaterial = (UniaxialMaterial *)theMat; - else - return TCL_ERROR; -#endif - } else if ((strcmp(argv[1], "BilinearOilDamper") == 0)) { void *theMat = OPS_BilinearOilDamper(rt, argc, argv); if (theMat != 0) @@ -222,15 +201,6 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp return TCL_ERROR; #endif -#if 0 - } else if (strcmp(argv[1],"HoehlerStanton") == 0) { - void *theMat = OPS_HoehlerStanton(rt, argc, argv); - if (theMat != 0) - theMaterial = (UniaxialMaterial *)theMat; - else - return TCL_ERROR; -#endif - } else if (strcmp(argv[1], "ReinforcingSteel") == 0) { void *theMat = OPS_ReinforcingSteel(rt, argc, argv); @@ -283,14 +253,8 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp else return TCL_ERROR; - } else if (strcmp(argv[1], "Steel01Thermal") == 0) { - void *theMat = OPS_Steel01Thermal(rt, argc, argv); - if (theMat != 0) - theMaterial = (UniaxialMaterial *)theMat; - else - return TCL_ERROR; - - } else if (strcmp(argv[1], "ConcretewBeta") == 0) { + } + else if (strcmp(argv[1], "ConcretewBeta") == 0) { void *theMat = OPS_ConcretewBeta(); if (theMat != 0) theMaterial = (UniaxialMaterial *)theMat; @@ -309,8 +273,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp } else if (strcmp(argv[1], "Elastic2") == 0) { if (argc < 4 || argc > 5) { opserr << "WARNING invalid number of arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial Elastic tag? E? " << endln; + opserr << "Want: uniaxialMaterial Elastic tag? E? " << "\n"; return TCL_ERROR; } @@ -319,20 +282,20 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp double eta = 0.0; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial Elastic tag" << endln; + opserr << "WARNING invalid uniaxialMaterial Elastic tag" << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { opserr << "WARNING invalid E\n"; - opserr << "uniaxiaMaterial Elastic: " << tag << endln; + opserr << "uniaxiaMaterial Elastic: " << tag << "\n"; return TCL_ERROR; } if (argc == 5) { if (Tcl_GetDouble(interp, argv[4], &eta) != TCL_OK) { opserr << "WARNING invalid eta\n"; - opserr << "uniaxialMaterial Elastic: " << tag << endln; + opserr << "uniaxialMaterial Elastic: " << tag << "\n"; return TCL_ERROR; } } @@ -343,8 +306,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp } else if (strcmp(argv[1], "ENT") == 0) { if (argc < 4) { opserr << "WARNING invalid number of arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial ENT tag? E?" << endln; + opserr << "Want: uniaxialMaterial ENT tag? E?" << "\n"; return TCL_ERROR; } @@ -352,13 +314,13 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp double E; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial ENT tag" << endln; + opserr << "WARNING invalid uniaxialMaterial ENT tag" << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[3], &E) != TCL_OK) { opserr << "WARNING invalid E\n"; - opserr << "uniaxiaMaterial ENT: " << tag << endln; + opserr << "uniaxiaMaterial ENT: " << tag << "\n"; return TCL_ERROR; } @@ -379,16 +341,15 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp // Check that there is the minimum number of arguments if (argc < 9) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial Steel03 tag? fy? E0? b? r? cR1 cR2?"; - opserr << " " << endln; + opserr << " " << "\n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial Steel03 tag" << endln; + opserr << "WARNING invalid uniaxialMaterial Steel03 tag" << "\n"; return TCL_ERROR; } @@ -397,37 +358,31 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (Tcl_GetDouble(interp, argv[3], &fy) != TCL_OK) { opserr << "WARNING invalid fy\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &E) != TCL_OK) { opserr << "WARNING invalid E0\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &b) != TCL_OK) { opserr << "WARNING invalid b\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6], &r) != TCL_OK) { opserr << "WARNING invalid r\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[7], &cR1) != TCL_OK) { opserr << "WARNING invalid cR1\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8], &cR2) != TCL_OK) { opserr << "WARNING invalid cR2\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; return TCL_ERROR; } @@ -436,31 +391,31 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (argc > 9) { if (argc < 13) { opserr << "WARNING insufficient number of hardening parameters\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; + opserr << "uniaxialMaterial Steel03: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9], &a1) != TCL_OK) { opserr << "WARNING invalid a1\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; + opserr << "uniaxialMaterial Steel03: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[10], &a2) != TCL_OK) { opserr << "WARNING invalid a2\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; + opserr << "uniaxialMaterial Steel03: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[11], &a3) != TCL_OK) { opserr << "WARNING invalid a3\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; + opserr << "uniaxialMaterial Steel03: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[12], &a4) != TCL_OK) { opserr << "WARNING invalid a4\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; + opserr << "uniaxialMaterial Steel03: " << tag << "\n"; return TCL_ERROR; } @@ -482,31 +437,20 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp } - else if (strcmp(argv[1], "OOHysteretic") == 0) { - - void *theMat = OPS_OOHystereticMaterial(rt, argc, argv); - if (theMat != 0) - theMaterial = (UniaxialMaterial *)theMat; - else - return TCL_ERROR; - - } - else if (strcmp(argv[1], "Concrete04") == 0) { - // opserr << argc << endln; + // opserr << argc << "\n"; if (argc != 10 && argc != 9 && argc != 7) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial Concrete04 tag? fpc? epsc0? epscu? " "Ec0? >" - << endln; + << "\n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial Concrete04 tag" << endln; + opserr << "WARNING invalid uniaxialMaterial Concrete04 tag" << "\n"; return TCL_ERROR; } @@ -515,43 +459,36 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (Tcl_GetDouble(interp, argv[3], &fpc) != TCL_OK) { opserr << "WARNING invalid fpc\n"; - opserr << "Concrete04 material: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &epsc0) != TCL_OK) { opserr << "WARNING invalid epsc0\n"; - opserr << "Concrete04 material: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &epscu) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "Concrete04 material: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6], &Ec0) != TCL_OK) { opserr << "WARNING invalid Ec0\n"; - opserr << "Concrete04 material: " << tag << endln; return TCL_ERROR; } if (argc == 9 || argc == 10) { if (Tcl_GetDouble(interp, argv[7], &ft) != TCL_OK) { opserr << "WARNING invalid ft\n"; - opserr << "Concrete04 material: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8], &etu) != TCL_OK) { opserr << "WARNING invalid etu\n"; - opserr << "Concrete04 material: " << tag << endln; return TCL_ERROR; } } if (argc == 10) { if (Tcl_GetDouble(interp, argv[9], &beta) != TCL_OK) { opserr << "WARNING invalid beta\n"; - opserr << "Concrete04 material: " << tag << endln; return TCL_ERROR; } } @@ -569,17 +506,16 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp else if (strcmp(argv[1], "Concrete06") == 0) { if (argc < 12) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial Concrete06 tag? fc? eo? r? k? alphaC? " "fcr? ecr? b? alphaT?" - << endln; + << "\n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial Concrete06 tag" << endln; + opserr << "WARNING invalid uniaxialMaterial tag" << "\n"; return TCL_ERROR; } @@ -588,55 +524,55 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (Tcl_GetDouble(interp, argv[3], &fc) != TCL_OK) { opserr << "WARNING invalid fc\n"; - opserr << "Concrete06 material: " << tag << endln; + opserr << "Concrete06 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &eo) != TCL_OK) { opserr << "WARNING invalid eo\n"; - opserr << "Concrete06 material: " << tag << endln; + opserr << "Concrete06 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &r) != TCL_OK) { opserr << "WARNING invalid r\n"; - opserr << "Concrete06 material: " << tag << endln; + opserr << "Concrete06 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6], &k) != TCL_OK) { opserr << "WARNING invalid k\n"; - opserr << "Concrete06 material: " << tag << endln; + opserr << "Concrete06 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[7], &alphaC) != TCL_OK) { opserr << "WARNING invalid alphaC\n"; - opserr << "Concrete06 material: " << tag << endln; + opserr << "Concrete06 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8], &fcr) != TCL_OK) { opserr << "WARNING invalid fcr\n"; - opserr << "Concrete06 material: " << tag << endln; + opserr << "Concrete06 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9], &ecr) != TCL_OK) { opserr << "WARNING invalid ecr\n"; - opserr << "Concrete06 material: " << tag << endln; + opserr << "Concrete06 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[10], &b) != TCL_OK) { opserr << "WARNING invalid b\n"; - opserr << "Concrete06 material: " << tag << endln; + opserr << "Concrete06 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[11], &alphaT) != TCL_OK) { opserr << "WARNING invalid alphaT\n"; - opserr << "Concrete06 material: " << tag << endln; + opserr << "Concrete06 material: " << tag << "\n"; return TCL_ERROR; } @@ -649,7 +585,6 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp // Check to see if there are enough arquements if (argc < 11) { opserr << "WARNING: Insufficient arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial Concrete07 tag? fpc? epsc0? Ec? fpt? " "epst0? xcrp? xcrn? r?\n"; return TCL_ERROR; @@ -667,57 +602,44 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (Tcl_GetDouble(interp, argv[3], &fpc) != TCL_OK) { opserr << "WARNING: Invalid peak compression stress\n"; - opserr << "uniaxialMaterial Concrete07: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &epsc0) != TCL_OK) { opserr << "WARNING: Invalid peak compression strain\n"; - opserr << "uniaxialMaterial Concrete07: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &Ec) != TCL_OK) { opserr << "WARNING: Invalid Young's Modulus\n"; - opserr << "uniaxialMaterial Concrete07: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6], &fpt) != TCL_OK) { opserr << "WARNING: Invalid peak tension stress\n"; - opserr << "uniaxialMaterial Concrete07: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[7], &epst0) != TCL_OK) { opserr << "WARNING: Invalid peak tension strain\n"; - opserr << "uniaxialMaterial Concrete07: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8], &xcrp) != TCL_OK) { opserr << "WARNING: Invalid critical nondimensional strain in tension\n"; - opserr << "uniaxialMaterial Concrete07: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9], &xcrn) != TCL_OK) { opserr << "WARNING: Invalid critical nondimensional strain in compression\n"; - opserr << "uniaxialMaterial Concrete07: " << tag << endln; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[10], &r) != TCL_OK) { opserr << "WARNING: Invalid value for r\n"; - opserr << "uniaxialMaterial Concrete07: " << tag << endln; } - // opserr << "fpc: " << fpc << endln << "epsc0: " << epsc0 << endln << - //"Ec: " << Ec << endln; opserr << "fpt: " << fpt << endln << "epst0: " << - //epst0 << endln << "xcrp: " << xcrp << endln; opserr << "xcrn: " << xcrn << - //endln << "r: " << r << endln; - // Parsing was successful, allocate the material theMaterial = @@ -727,8 +649,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp else if (strcmp(argv[1], "PathIndependent") == 0) { if (argc < 4) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial PathIndependent tag? matTag?" << endln; + opserr << "Want: uniaxialMaterial PathIndependent tag? matTag?" << "\n"; return TCL_ERROR; } @@ -736,13 +657,13 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { opserr << "WARNING invalid tag\n"; - opserr << "PathIndependent material: " << tag << endln; + opserr << "PathIndependent material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { opserr << "WARNING invalid matTag\n"; - opserr << "PathIndependent material: " << tag << endln; + opserr << "PathIndependent material: " << tag << "\n"; return TCL_ERROR; } @@ -752,12 +673,12 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp theMaterial = new PathIndependentMaterial(tag, *material); } + else if (strcmp(argv[1], "Backbone") == 0) { if (argc < 4) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); - opserr << "Want: uniaxialMaterial Backbone tag? bbTag?" << endln; + opserr << "Want: uniaxialMaterial Backbone tag? bbTag?" << "\n"; return TCL_ERROR; } @@ -765,13 +686,13 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { opserr << "WARNING invalid tag\n"; - opserr << "Backbone material: " << tag << endln; + opserr << "Backbone material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &bbTag) != TCL_OK) { opserr << "WARNING invalid bTag\n"; - opserr << "Backbone material: " << tag << endln; + opserr << "Backbone material: " << tag << "\n"; return TCL_ERROR; } @@ -780,7 +701,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (backbone == 0) { opserr << "WARNING backbone does not exist\n"; opserr << "backbone: " << bbTag; - opserr << "\nuniaxialMaterial Backbone: " << tag << endln; + opserr << "\nuniaxialMaterial Backbone: " << tag << "\n"; return TCL_ERROR; } @@ -790,23 +711,22 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp else if (strcmp(argv[1], "Fatigue") == 0) { if (argc < 4) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial Fatigue tag? matTag?"; - opserr << " <-D_max dmax?> <-e0 e0?> <-m m?>" << endln; - opserr << " <-min min?> <-max max?>" << endln; + opserr << " <-D_max dmax?> <-e0 e0?> <-m m?>" << "\n"; + opserr << " <-min min?> <-max max?>" << "\n"; return TCL_ERROR; } int tag, matTag; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial Fatigue tag" << endln; + opserr << "WARNING invalid uniaxialMaterial Fatigue tag" << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &matTag) != TCL_OK) { opserr << "WARNING invalid component tag\n"; - opserr << "uniaxialMaterial Fatigue: " << tag << endln; + opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; return TCL_ERROR; } @@ -821,35 +741,35 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if ((j + 1 >= argc) || (Tcl_GetDouble(interp, argv[j + 1], &Dmax) != TCL_OK)) { opserr << "WARNING invalid -Dmax"; - opserr << "uniaxialMaterial Fatigue: " << tag << endln; + opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; return TCL_ERROR; } } else if (strcmp(argv[j], "-E0") == 0) { if ((j + 1 >= argc) || (Tcl_GetDouble(interp, argv[j + 1], &E0) != TCL_OK)) { opserr << "WARNING invalid -E0"; - opserr << "uniaxialMaterial Fatigue: " << tag << endln; + opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; return TCL_ERROR; } } else if (strcmp(argv[j], "-m") == 0) { if ((j + 1 >= argc) || (Tcl_GetDouble(interp, argv[j + 1], &m) != TCL_OK)) { opserr << "WARNING invalid -m"; - opserr << "uniaxialMaterial Fatigue: " << tag << endln; + opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; return TCL_ERROR; } } else if (strcmp(argv[j], "-min") == 0) { if ((j + 1 >= argc) || (Tcl_GetDouble(interp, argv[j + 1], &epsmin) != TCL_OK)) { opserr << "WARNING invalid -min "; - opserr << "uniaxialMaterial Fatigue: " << tag << endln; + opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; return TCL_ERROR; } } else if (strcmp(argv[j], "-max") == 0) { if ((j + 1 >= argc) || (Tcl_GetDouble(interp, argv[j + 1], &epsmax) != TCL_OK)) { opserr << "WARNING invalid -max"; - opserr << "uniaxialMaterial Fatigue: " << tag << endln; + opserr << "uniaxialMaterial Fatigue: " << tag << "\n"; return TCL_ERROR; } } @@ -930,7 +850,6 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp else if (strcmp(argv[1], "Pinching4") == 0) { if (argc != 42 && argc != 31) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial Pinching4 tag? stress1p? strain1p? " "stress2p? strain2p? stress3p? strain3p? stress4p? strain4p? " << "\n" - << endln; + << "\n"; return TCL_ERROR; } @@ -1233,57 +1151,57 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (Tcl_GetInt(interp, argv[argStart++], &tag) != TCL_OK) { opserr << "WARNING invalid tag\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argStart++], &fc) != TCL_OK) { opserr << "WARNING invalid fc\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argStart++], &fy) != TCL_OK) { opserr << "WARNING invalid fy\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argStart++], &Es) != TCL_OK) { opserr << "WARNING invalid Es\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argStart++], &fu) != TCL_OK) { opserr << "WARNING invalid fu\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argStart++], &Eh) != TCL_OK) { opserr << "WARNING invalid Eh\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argStart++], &db) != TCL_OK) { opserr << "WARNING invalid db\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argStart++], &ld) != TCL_OK) { opserr << "WARNING invalid ld\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[argStart++], &nb) != TCL_OK) { opserr << "WARNING invalid nbars\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argStart++], &width) != TCL_OK) { opserr << "WARNING invalid width\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[argStart++], &depth) != TCL_OK) { opserr << "WARNING invalid depth\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } @@ -1302,7 +1220,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp } } else { opserr << "WARNING invalid bond strength specified\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } y++; @@ -1334,7 +1252,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp } } else { opserr << "WARNING invalid location of bar specified\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } if (argc == 17) { @@ -1363,7 +1281,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp } else { opserr << "WARNING invalid damage specified\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } @@ -1403,7 +1321,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp } } else { opserr << "WARNING invalid unit specified\n"; - opserr << "BarSlip: " << tag << endln; + opserr << "BarSlip: " << tag << "\n"; return TCL_ERROR; } } @@ -1424,7 +1342,6 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp else if (strcmp(argv[1], "ShearPanel") == 0) { if (argc != 42 && argc != 31) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial ShearPanel tag? stress1p? strain1p? " "stress2p? strain2p? stress3p? strain3p? stress4p? strain4p? " << "\n" - << endln; + << "\n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial Concrete01 tag" << endln; + opserr << "WARNING invalid uniaxialMaterial Concrete01 tag" << "\n"; return TCL_ERROR; } @@ -1720,25 +1636,25 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (Tcl_GetDouble(interp, argv[3], &fpc) != TCL_OK) { opserr << "WARNING invalid fpc\n"; - opserr << "Concrete01 material: " << tag << endln; + opserr << "Concrete01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &epsc0) != TCL_OK) { opserr << "WARNING invalid epsc0\n"; - opserr << "Concrete01 material: " << tag << endln; + opserr << "Concrete01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &fpcu) != TCL_OK) { opserr << "WARNING invalid fpcu\n"; - opserr << "Concrete01 material: " << tag << endln; + opserr << "Concrete01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6], &epscu) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "Concrete01 material: " << tag << endln; + opserr << "Concrete01 material: " << tag << "\n"; return TCL_ERROR; } @@ -1749,7 +1665,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp double endStrainSITC; if (Tcl_GetDouble(interp, argv[7], &endStrainSITC) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "Concrete01 material: " << tag << endln; + opserr << "Concrete01 material: " << tag << "\n"; return TCL_ERROR; } theMaterial = @@ -1760,7 +1676,6 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp else if (strcmp(argv[1], "ECC01") == 0) { if (argc < 16) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial ECC01 TAG? SIGT0? EPST0? SIGT1? EPST1? " "EPST2? SIGC0? EPSC0? EPSC1? "; opserr << "ALPHAT1? ALPHAT2? ALPHAC? ALPHACU? BETAT? BETAC\n"; @@ -1772,82 +1687,82 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp ALPHAT2, ALPHAC, ALPHACU, BETAT, BETAC; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial ECC01 tag" << endln; + opserr << "WARNING invalid uniaxialMaterial ECC01 tag" << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[3], &SIGT0) != TCL_OK) { opserr << "WARNING invalid SIGTO\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &EPST0) != TCL_OK) { opserr << "WARNING invalid EPSTO\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &SIGT1) != TCL_OK) { opserr << "WARNING invalid SIGT1\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6], &EPST1) != TCL_OK) { opserr << "WARNING invalid EPST1\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[7], &EPST2) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8], &SIGC0) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9], &EPSC0) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[10], &EPSC1) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[11], &ALPHAT1) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[12], &ALPHAT2) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[13], &ALPHAC) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[14], &ALPHACU) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[15], &BETAT) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[16], &BETAC) != TCL_OK) { opserr << "WARNING invalid epscu\n"; - opserr << "ECC01 material: " << tag << endln; + opserr << "ECC01 material: " << tag << "\n"; return TCL_ERROR; } @@ -1867,10 +1782,9 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp else if (strcmp(argv[1], "SelfCentering") == 0) { if (argc < 7) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial SelfCentering tag? k1? k2? ActF? beta? " "" - << endln; + << "\n"; return TCL_ERROR; } @@ -1878,38 +1792,38 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp double k1, k2, ActF, beta, rBear, SlipDef, BearDef; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial SelfCentering tag" << endln; + opserr << "WARNING invalid uniaxialMaterial SelfCentering tag" << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[3], &k1) != TCL_OK) { opserr << "WARNING invalid k1\n"; - opserr << "uniaxialMaterial SelfCentering: " << tag << endln; + opserr << "uniaxialMaterial SelfCentering: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &k2) != TCL_OK) { opserr << "WARNING invalid k2\n"; - opserr << "uniaxialMaterial SelfCentering: " << tag << endln; + opserr << "uniaxialMaterial SelfCentering: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &ActF) != TCL_OK) { opserr << "WARNING invalid ActF\n"; - opserr << "uniaxialMaterial SelfCentering: " << tag << endln; + opserr << "uniaxialMaterial SelfCentering: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[6], &beta) != TCL_OK) { opserr << "WARNING invalid beta\n"; - opserr << "uniaxialMaterial SelfCentering: " << tag << endln; + opserr << "uniaxialMaterial SelfCentering: " << tag << "\n"; return TCL_ERROR; } if (argc == 8) { if (Tcl_GetDouble(interp, argv[7], &SlipDef) != TCL_OK) { opserr << "WARNING invalid SlipDef\n"; - opserr << "uniaxialMaterial SelfCentering: " << tag << endln; + opserr << "uniaxialMaterial SelfCentering: " << tag << "\n"; return TCL_ERROR; } // Parsing was successful, allocate the material @@ -1920,17 +1834,17 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp else if (argc > 8) { if (Tcl_GetDouble(interp, argv[7], &SlipDef) != TCL_OK) { opserr << "WARNING invalid SlipDef\n"; - opserr << "uniaxialMaterial SelfCentering: " << tag << endln; + opserr << "uniaxialMaterial SelfCentering: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8], &BearDef) != TCL_OK) { opserr << "WARNING invalid BearDef\n"; - opserr << "uniaxialMaterial SelfCentering: " << tag << endln; + opserr << "uniaxialMaterial SelfCentering: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9], &rBear) != TCL_OK) { opserr << "WARNING invalid rBear\n"; - opserr << "uniaxialMaterial SelfCentering: " << tag << endln; + opserr << "uniaxialMaterial SelfCentering: " << tag << "\n"; return TCL_ERROR; } // Parsing was successful, allocate the material @@ -1948,16 +1862,15 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp // Check that there is the minimum number of arguments if (argc < 4) { opserr << "WARNING insufficient arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial SteelMP tag? fy? E0? b? "; - opserr << " " << endln; + opserr << " " << "\n"; return TCL_ERROR; } int tag; if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { - opserr << "WARNING invalid uniaxialMaterial SteelMP tag" << endln; + opserr << "WARNING invalid uniaxialMaterial SteelMP tag" << "\n"; return TCL_ERROR; } @@ -1966,25 +1879,24 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (Tcl_GetDouble(interp, argv[3], &fy) != TCL_OK) { opserr << "WARNING invalid fy\n"; - opserr << "uniaxialMaterial SteelMP: " << tag << endln; + opserr << "uniaxialMaterial SteelMP: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &E) != TCL_OK) { opserr << "WARNING invalid E0\n"; - opserr << "uniaxialMaterial SteelMP: " << tag << endln; + opserr << "uniaxialMaterial SteelMP: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &b) != TCL_OK) { opserr << "WARNING invalid b\n"; - opserr << "uniaxialMaterial SteelMP: " << tag << endln; + opserr << "uniaxialMaterial SteelMP: " << tag << "\n"; return TCL_ERROR; } if (argc < 5) { opserr << "WARNING insufficient number of hardening parameters\n"; - opserr << "uniaxialMaterial Steel03: " << tag << endln; return TCL_ERROR; } @@ -1999,31 +1911,31 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (argc > 6) { if (Tcl_GetDouble(interp, argv[6], &r) != TCL_OK) { opserr << "WARNING invalid r\n"; - opserr << "uniaxialMaterial SteelMP: " << tag << endln; + opserr << "uniaxialMaterial SteelMP: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[7], &coeffR1) != TCL_OK) { opserr << "WARNING invalid CR1\n"; - opserr << "uniaxialMaterial SteelMP: " << tag << endln; + opserr << "uniaxialMaterial SteelMP: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[8], &coeffR2) != TCL_OK) { opserr << "WARNING invalid CR2\n"; - opserr << "uniaxialMaterial SteelMP: " << tag << endln; + opserr << "uniaxialMaterial SteelMP: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[9], &a1) != TCL_OK) { opserr << "WARNING invalid a1\n"; - opserr << "uniaxialMaterial SteelMP: " << tag << endln; + opserr << "uniaxialMaterial SteelMP: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[10], &a2) != TCL_OK) { opserr << "WARNING invalid a2\n"; - opserr << "uniaxialMaterial SteelMP: " << tag << endln; + opserr << "uniaxialMaterial SteelMP: " << tag << "\n"; return TCL_ERROR; } } // if @@ -2034,10 +1946,9 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp else if (strcmp(argv[1], "SmoothPSConcrete") == 0) { if (argc < 6 || argc > 9) { opserr << "WARNING invalid number of arguments\n"; - printCommand(argc, argv); opserr << "Want: uniaxialMaterial SmoothPSConcrete tag? fc? fu? Ec? " " " - << endln; + << "\n"; return TCL_ERROR; } @@ -2049,46 +1960,46 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp if (Tcl_GetInt(interp, argv[2], &tag) != TCL_OK) { opserr << "WARNING invalid uniaxialMaterial SmoothPSConcrete tag" - << endln; + << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[3], &fc) != TCL_OK) { opserr << "WARNING invalid fc\n"; - opserr << "uniaxiaMaterial SmoothPSConcrete: " << tag << endln; + opserr << "uniaxiaMaterial SmoothPSConcrete: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[4], &fu) != TCL_OK) { opserr << "WARNING invalid fu\n"; - opserr << "uniaxiaMaterial SmoothPSConcrete: " << tag << endln; + opserr << "uniaxiaMaterial SmoothPSConcrete: " << tag << "\n"; return TCL_ERROR; } if (Tcl_GetDouble(interp, argv[5], &Ec) != TCL_OK) { opserr << "WARNING invalid Ec\n"; - opserr << "uniaxiaMaterial SmoothPSConcrete: " << tag << endln; + opserr << "uniaxiaMaterial SmoothPSConcrete: " << tag << "\n"; return TCL_ERROR; } if (argc >= 7) if (Tcl_GetDouble(interp, argv[6], &eps0) != TCL_OK) { opserr << "WARNING invalid eps0\n"; - opserr << "uniaxialMaterial SmoothPSConcrete: " << tag << endln; + opserr << "uniaxialMaterial SmoothPSConcrete: " << tag << "\n"; return TCL_ERROR; } if (argc >= 8) if (Tcl_GetDouble(interp, argv[7], &epsu) != TCL_OK) { opserr << "WARNING invalid epsu\n"; - opserr << "uniaxialMaterial SmoothPSConcrete: " << tag << endln; + opserr << "uniaxialMaterial SmoothPSConcrete: " << tag << "\n"; return TCL_ERROR; } if (argc >= 9) if (Tcl_GetDouble(interp, argv[8], &eta) != TCL_OK) { opserr << "WARNING invalid eta\n"; - opserr << "uniaxialMaterial SmoothPSConcrete: " << tag << endln; + opserr << "uniaxialMaterial SmoothPSConcrete: " << tag << "\n"; return TCL_ERROR; } @@ -2136,7 +2047,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp TclBasicBuilder_addDegradingMaterial(clientData, interp, argc, argv); #endif - if (theMaterial == 0) { + if (theMaterial == nullptr) { // // maybe element in a class package already loaded // loop through linked list of loaded functions comparing names & if find @@ -2160,7 +2071,7 @@ TclBasicBuilderUniaxialMaterialCommand(ClientData clientData, Tcl_Interp *interp // if still here the element command does not exist // if (theMaterial == nullptr) { - opserr << "WARNING could not create uniaxialMaterial " << argv[1] << endln; + opserr << "WARNING could not create uniaxialMaterial " << argv[1] << "\n"; return TCL_ERROR; } diff --git a/SRC/runtime/commands/modeling/Block2D.cpp b/SRC/runtime/commands/modeling/utilities/Block2D.cpp similarity index 95% rename from SRC/runtime/commands/modeling/Block2D.cpp rename to SRC/runtime/commands/modeling/utilities/Block2D.cpp index f64784c45e..95e797be80 100644 --- a/SRC/runtime/commands/modeling/Block2D.cpp +++ b/SRC/runtime/commands/modeling/utilities/Block2D.cpp @@ -1,8 +1,10 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// +// https://xara.so +//===----------------------------------------------------------------------===// // // Description: This file contains the class definition for Block2D. // @@ -12,7 +14,7 @@ #include #include #include -#include +#include "Block2D.h" Block2D::Block2D(int numx, int numy, @@ -44,14 +46,7 @@ Block2D::Block2D(int numx, int numy, } -//destructor -Block2D::~Block2D( ) -{ - -} - - -//set up xl array +// set up xl array int Block2D::setUpXl( const ID &nodeID, const Matrix &coorArray ) { diff --git a/SRC/runtime/commands/modeling/Block2D.h b/SRC/runtime/commands/modeling/utilities/Block2D.h similarity index 73% rename from SRC/runtime/commands/modeling/Block2D.h rename to SRC/runtime/commands/modeling/utilities/Block2D.h index ff2c7c3fb5..9028ad2ee1 100644 --- a/SRC/runtime/commands/modeling/Block2D.h +++ b/SRC/runtime/commands/modeling/utilities/Block2D.h @@ -1,8 +1,10 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// +// https://xara.so +//===----------------------------------------------------------------------===// // // Description: This file contains the implementation of Block2D. // @@ -20,21 +22,18 @@ class Vector; class Block2D { - public: +public: - //constructor Block2D(int numx, int numy, const ID& nodeID, const Matrix& coorArray, int numNodeElement); - // destructor - ~Block2D(); - // generate node + // generate nodes Vector3D getNodalCoords(int i, int j); - // generate element + // generate elements const ID &getElementNodes(int i, int j); @@ -47,11 +46,11 @@ class Block2D { // shape functions void shape2d(double x1, - double x2, - double shape[9]); + double x2, + double shape[9]); - int nx; //number of elements x-direction - int ny; //number of elements y-direction + int nx; // number of elements x-direction + int ny; // number of elements y-direction double xl[3][9]; //block coordinates diff --git a/SRC/runtime/commands/modeling/Block3D.cpp b/SRC/runtime/commands/modeling/utilities/Block3D.cpp similarity index 88% rename from SRC/runtime/commands/modeling/Block3D.cpp rename to SRC/runtime/commands/modeling/utilities/Block3D.cpp index 445a98adfa..f17d76d626 100644 --- a/SRC/runtime/commands/modeling/Block3D.cpp +++ b/SRC/runtime/commands/modeling/utilities/Block3D.cpp @@ -1,18 +1,18 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// -// +// https://xara.so +//===----------------------------------------------------------------------===// // Description: This file contains the implementation of Block3D. // // Written: Ed Love // Created: 07/01 // -#include +#include "Block3D.h" -//constructor Block3D::Block3D(int numx, int numy, int numz, const ID& nodeID, const Matrix& coorArray ) @@ -24,13 +24,7 @@ Block3D::Block3D(int numx, int numy, int numz, } -// destructor -Block3D::~Block3D( ) -{ -} - - -//set up xl array +// set up xl array void Block3D::setUpXl( const ID &nodeID, const Matrix &coorArray ) { @@ -264,16 +258,15 @@ void Block3D::transformNodalCoordinates( ) } - -//shape functions -void Block3D::shape3d( double r, double s, double t, - double shape[27] ) +void +Block3D::shape3d( double r, double s, double t, double shape[27]) /* * Adapted from: subroutine shp04(shp,glu,glo,gu,eu,to,xjac,detj,r,s,t,xl,ul) c----------------------------------------------------------------------- c.....compute shape functions and their derivatives for linear,quadratic -c.....lagrangian and serendipity isoparametric 3-d elements +c.....lagrangian and serendipity isoparametric 3-d hexahedral elements +c..... c.....global coordinate system x,y,z c.....local coordinate system xsi,eta,zeta c----------------------------------------------------------------------- @@ -281,9 +274,7 @@ c----------------------------------------------------------------------- { static constexpr int ri[] = {-1, 1, 1,-1, -1, 1, 1,-1, -1, 1, 1,-1, 0, 1, 0,-1, 0, 0, 1, 0,-1, 0, 0, 1, 0,-1, 0}; - static constexpr int si[] = {-1,-1, 1, 1, -1,-1, 1, 1, -1,-1, 1, 1, -1, 0, 1, 0, 0, -1, 0, 1, 0, 0, -1, 0, 1, 0, 0}; - static constexpr int ti[] = {-1,-1,-1,-1, 1, 1, 1, 1, 0, 0, 0, 0, -1,-1,-1,-1,-1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; @@ -299,46 +290,45 @@ c----------------------------------------------------------------------- int kk; - //shape functions for 27-node element + // shape functions for 27-node element for (int k=1; k<=27; k++ ) { - kk = k-1; //C-style numbering + kk = k-1; // C-style numbering double r0 = r*ri[kk]; double s0 = s*si[kk]; double t0 = t*ti[kk]; - //corner nodes top/bottom + // corner nodes top/bottom if ( k>=1 && k<=8 ) - shape[kk] = d8*(rr+r0) *(ss+s0) *(tt+t0); + shape[kk] = d8*(rr+r0) *(ss+s0) *(tt+t0); - //corner nodes midside + // corner nodes midside if ( k>=9 && k<=12 ) - shape[kk] = d4*(rr+r0) *(ss+s0) *(d1-tt); + shape[kk] = d4*(rr+r0) *(ss+s0) *(d1-tt); - //midside nodes top/bottom r-dir + // midside nodes top/bottom r-dir if ( k==13 || k==15 || k==18 || k==20 ) - shape[kk] = d4*(d1-rr)*(ss+s0) *(tt+t0); + shape[kk] = d4*(d1-rr)*(ss+s0) *(tt+t0); - //midside nodes top/bottom s-dir + // midside nodes top/bottom s-dir if ( k==14 || k==16 || k==19 || k==21 ) shape[kk] = d4*(rr+r0) *(d1-ss)*(tt+t0); - //midside nodes mid plane r-dir + // midside nodes mid plane r-dir if ( k==23 || k==25 ) shape[kk] = d2*(d1-rr)*(ss+s0) *(d1-tt); - //midside nodes mid plane s-dir + // midside nodes mid plane s-dir if ( k==24 || k==26 ) shape[kk] = d2*(rr+r0) *(d1-ss)*(d1-tt); - //central nodes top/bottom + // central nodes top/bottom if ( k==17 || k==22 ) shape[kk] = d2*(d1-rr)*(d1-ss)*(tt+t0); if ( k==27 ) shape[kk] = (d1-rr)*(d1-ss)*(d1-tt); - } return; diff --git a/SRC/runtime/commands/modeling/Block3D.h b/SRC/runtime/commands/modeling/utilities/Block3D.h similarity index 69% rename from SRC/runtime/commands/modeling/Block3D.h rename to SRC/runtime/commands/modeling/utilities/Block3D.h index 981546ca46..eb80fd5b95 100644 --- a/SRC/runtime/commands/modeling/Block3D.h +++ b/SRC/runtime/commands/modeling/utilities/Block3D.h @@ -1,9 +1,10 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// -// +// https://xara.so +//===----------------------------------------------------------------------===// // Written: Ed Love // Created: 07/01 // @@ -20,31 +21,25 @@ class Block3D { - public: +public: - //constructor Block3D(int numx, int numy, int numz, const ID& nodeID, const Matrix& coorArray); - //destructor - virtual ~Block3D(); - - //generate node + // generate nodes const Vector &getNodalCoords(int i, int j, int k); - //generate element + // generate elements const ID &getElementNodes(int i, int j, int k); protected: private: - int nx; //number of elements x-direction - - int ny; //number of elements y-direction - - int nz; //number of elements z-direction + int nx; // number of elements x-direction + int ny; // number of elements y-direction + int nz; // number of elements z-direction double xl[3][27]; //block coordinates @@ -52,13 +47,13 @@ class Block3D { ID element; //ID-array of an element - //set up xl array + // set up xl array void setUpXl(const ID &nodeID, const Matrix &coorArray); - //transform to real coordiantes + // transform to real coordiantes void transformNodalCoordinates(); - //shape functions + // shape functions void shape3d(double x1, double x2, double x3, diff --git a/SRC/runtime/commands/modeling/blockND.cpp b/SRC/runtime/commands/modeling/utilities/blockND.cpp similarity index 67% rename from SRC/runtime/commands/modeling/blockND.cpp rename to SRC/runtime/commands/modeling/utilities/blockND.cpp index 6b49fe43b7..be8f818707 100644 --- a/SRC/runtime/commands/modeling/blockND.cpp +++ b/SRC/runtime/commands/modeling/utilities/blockND.cpp @@ -1,35 +1,35 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// +// https://xara.so +//===----------------------------------------------------------------------===// // // NOTE: This doesnt really need access to the model builder, it would // work with just the domain // -#ifdef _TCL85 -# define TCL_Char const char -#elif _TCL84 -# define TCL_Char const char -#else -# define TCL_Char char -#endif #include +#include #include #include #include +#include #include #include #include -#include +#include #include #include "Block2D.h" #include "Block3D.h" +using OpenSees::MatrixND; int -TclCommand_doBlock2D(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) +TclCommand_doBlock2D(ClientData clientData, + Tcl_Interp *interp, + Tcl_Size argc, + TCL_Char ** const argv) { assert(clientData != nullptr); BasicModelBuilder* builder = static_cast(clientData); @@ -38,41 +38,44 @@ TclCommand_doBlock2D(ClientData clientData, Tcl_Interp *interp, int argc, int ndf = builder->getNDF(); if (ndm < 2) { - opserr << G3_ERROR_PROMPT - << "model dimension (ndm) must be at leat 2 " << "\n"; + opserr << OpenSees::PromptValueError + << "model dimension (ndm) must be at leat 2 " + << OpenSees::SignalMessageEnd; return TCL_ERROR; } if (argc < 8) { - opserr << G3_ERROR_PROMPT << "incorrect number of args, expected:" - "\n\tblock2D numX? numY? startNode? startEle? eleType? eleArgs?"; + opserr << OpenSees::PromptValueError << "incorrect number of args, expected:" + "\n\tblock2D numX? numY? startNode? startEle? eleType? eleArgs?" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } int numX, numY, startNodeNum, startEleNum; if (Tcl_GetInt(interp, argv[1], &numX) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "invalid numX (" << argv[1] << "), expected:\n\t" - << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; + opserr << OpenSees::PromptValueError + << "invalid numX (" << argv[1] << ")" + << OpenSees::SignalMessageEnd; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &numY) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; + opserr << OpenSees::PromptValueError << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; opserr << " : invalid numY: " << argv[2] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &startNodeNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; + opserr << OpenSees::PromptValueError << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; opserr << " : invalid startNode: " << argv[3] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[4], &startEleNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; + opserr << OpenSees::PromptValueError << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; opserr << " : invalid startEle: " << argv[4] << "\n"; return TCL_ERROR; } - static Matrix Coordinates(9,3); - Coordinates.Zero(); + MatrixND<9,3> Coordinates; + Coordinates.zero(); static ID haveNode(9); for (int k=0; k<9; k++) @@ -82,19 +85,19 @@ TclCommand_doBlock2D(ClientData clientData, Tcl_Interp *interp, int argc, if (argc == 10) { if (strcmp(argv[7],"-numEleNodes") == 0) if (Tcl_GetInt(interp, argv[8], &numNodes) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block2D numX? numY? startNode? startEle? eleType eleArgs?"; + opserr << OpenSees::PromptValueError << "block2D numX? numY? startNode? startEle? eleType eleArgs?"; opserr << " -numEleNodes numNodes?: invalid numNodes: " << argv[8] << "\n"; return TCL_ERROR; } if (numNodes != 4 && numNodes != 9) { - opserr << G3_ERROR_PROMPT << "block2D numX? numY? startNode? startEle? eleType? eleArgs? "; + opserr << OpenSees::PromptValueError << "block2D numX? numY? startNode? startEle? eleType? eleArgs? "; opserr << "-numEleNodes numNodes?: invalid numNodes: " << argv[8] << " 4 or 9 only\n"; return TCL_ERROR; } if (numNodes == 9) { if (((numX % 2) != 0) || ((numY % 2) != 0)) { - opserr << G3_ERROR_PROMPT << "block2D numX? numY? startNode? startEle? eleType? eleArgs? "; + opserr << OpenSees::PromptValueError << "block2D numX? numY? startNode? startEle? eleType? eleArgs? "; opserr << "numX and numY must both be even when using -numEleNodes 9\n"; return TCL_ERROR; } @@ -116,26 +119,26 @@ TclCommand_doBlock2D(ClientData clientData, Tcl_Interp *interp, int argc, int nodeTag; double value; if ((count + ndm + 1) > argcNodes) { - opserr << G3_ERROR_PROMPT << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; + opserr << OpenSees::PromptValueError << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; opserr << " : invalid number of node args: " << argv[7] << "\n"; Tcl_Free((char *)argvNodes); return TCL_ERROR; } if (Tcl_GetInt(interp, argvNodes[count], &nodeTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; + opserr << OpenSees::PromptValueError << "block2D numX? numY? startNode? startEle? eleType? eleArgs?"; opserr << " : invalid node tag: " << argvNodes[count] << "\n"; Tcl_Free((char *)argvNodes); return TCL_ERROR; } if (nodeTag < 1 || nodeTag > 9) { - opserr << G3_ERROR_PROMPT + opserr << OpenSees::PromptValueError << " : invalid node tag out of bounds [1,9]: " << argvNodes[count] << "\n"; Tcl_Free((char *)argvNodes); return TCL_ERROR; } for (int i=0; i(nodeID, nodeCoords(0), nodeCoords(1), nodeCoords(2)); - break; - case 6: - theNode = new NodeND<3, 6>(nodeID, nodeCoords(0), nodeCoords(1), nodeCoords(2)); - break; - default: - theNode = new Node(nodeID, ndf, nodeCoords(0), nodeCoords(1), nodeCoords(2)); - break; - } - } else - theNode = new Node(nodeID, ndf, nodeCoords(0), nodeCoords(1), nodeCoords(2)); - // theNode = new Node(nodeID,ndf, nodeCoords(0), nodeCoords(1), nodeCoords(2)); +// theNode = new HeapNode(nodeID, ndf, nodeCoords(0), nodeCoords(1), nodeCoords(2)); + theNode = new Node(nodeID,ndf, nodeCoords(0), nodeCoords(1), nodeCoords(2)); } if (theTclDomain->addNode(theNode) == false) { - opserr << G3_ERROR_PROMPT << "failed to add node to the domain\n"; + opserr << OpenSees::PromptValueError << "failed to add node to the domain\n"; opserr << "node: " << nodeID << "\n"; delete theNode; return TCL_ERROR; @@ -237,9 +228,11 @@ TclCommand_doBlock2D(ClientData clientData, Tcl_Interp *interp, int argc, int -TclCommand_doBlock3D(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) +TclCommand_doBlock3D(ClientData clientData, Tcl_Interp *interp, Tcl_Size argc, + TCL_Char ** const argv) { + // block3D numX? numY? startNode? startEle? eleType? eleArgs? + // assert(clientData != nullptr); BasicModelBuilder* builder = static_cast(clientData); Domain *theTclDomain = builder->getDomain(); @@ -247,42 +240,40 @@ TclCommand_doBlock3D(ClientData clientData, Tcl_Interp *interp, int argc, int ndf = builder->getNDF(); if (ndm < 3) { - opserr << G3_ERROR_PROMPT << "block3D numX? numY? startNode? startEle? eleType? eleArgs?"; + opserr << OpenSees::PromptValueError << "block3D numX? numY? startNode? startEle? eleType? eleArgs?"; opserr << " : model dimension (ndm) must be at leat 2 " << "\n"; return TCL_ERROR; } int numX, numY, numZ, startNodeNum, startEleNum; if (Tcl_GetInt(interp, argv[1], &numX) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block3D numX? numY? numZ? startNode? startEle? eleType? eleArgs?"; - opserr << " : invalid numX: " << argv[1] << "\n"; + opserr << OpenSees::PromptValueError << "invalid numX: " << argv[1] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[2], &numY) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block3D numX? numY? numZ? startNode? startEle? eleType? eleArgs?"; - opserr << " : invalid numY: " << argv[2] << "\n"; + opserr << OpenSees::PromptValueError << "invalid numY: " << argv[2] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[3], &numZ) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block3D numX? numY? numZ? startNode? startEle? eleType? eleArgs?"; + opserr << OpenSees::PromptValueError << "block3D numX? numY? numZ? startNode? startEle? eleType? eleArgs?"; opserr << " : invalid numZ: " << argv[3] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[4], &startNodeNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block3D numX? numY? numZ? startNode? startEle? eleType? eleArgs?"; + opserr << OpenSees::PromptValueError << "block3D numX? numY? numZ? startNode? startEle? eleType? eleArgs?"; opserr << " : invalid startNode: " << argv[4] << "\n"; return TCL_ERROR; } if (Tcl_GetInt(interp, argv[5], &startEleNum) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block3D numX? numY? numZ? startNode? startEle? eleType? eleArgs?"; - opserr << " : invalid startEle: " << argv[5] << "\n"; + opserr << OpenSees::PromptValueError << "invalid startEle: " << argv[5] << "\n"; return TCL_ERROR; } - static Matrix Coordinates(27,3); + MatrixND<27,3> Coordinates; static ID haveNode(27); - Coordinates.Zero(); - for (int k=0; k<27; k++) haveNode(k) = -1; + Coordinates.zero(); + for (int k=0; k<27; k++) + haveNode(k) = -1; TCL_Char *nodalInfo = argv[8]; TCL_Char ** argvNodes; @@ -294,28 +285,25 @@ TclCommand_doBlock3D(ClientData clientData, Tcl_Interp *interp, int argc, int count = 0; while (count < argcNodes) { if ((count + ndm + 1) > argcNodes) { - opserr << G3_ERROR_PROMPT << "block3D numX? numY? numZ? startNode? startEle? eleType eleArgs?"; - opserr << " : invalid number of node args: " << argv[8] << "\n"; + opserr << OpenSees::PromptValueError << "invalid number of node args: " << argv[8] << "\n"; Tcl_Free((char *)argvNodes); return TCL_ERROR; } int nodeTag; double value; if (Tcl_GetInt(interp, argvNodes[count], &nodeTag) != TCL_OK) { - opserr << G3_ERROR_PROMPT << "block3D numX? numY? numZ? startNode? startEle? eleType? eleArgs?"; - opserr << " : invalid node id in node args: " << argvNodes[count] << "\n"; + opserr << OpenSees::PromptValueError << "invalid node id in node args: " << argvNodes[count] << "\n"; Tcl_Free((char *)argvNodes); return TCL_ERROR; } if (nodeTag < 1 || nodeTag > 27) { - opserr << G3_ERROR_PROMPT << "block3D numX? numY? numZ? startNode? startEle? eleType? eleArgs?"; - opserr << " : node tag out of bounds [1, 27]: " << argvNodes[count] << "\n"; + opserr << OpenSees::PromptValueError << "node tag out of bounds [1, 27]: " << argvNodes[count] << "\n"; Tcl_Free((char *)argvNodes); return TCL_ERROR; } for (int i=0; i(nodeID, nodeCoords(0), nodeCoords(1), nodeCoords(2)); - break; - case 6: - theNode = new NodeND<3, 6>(nodeID, nodeCoords(0), nodeCoords(1), nodeCoords(2)); - break; - default: - theNode = new Node(nodeID, ndf, nodeCoords(0), nodeCoords(1), nodeCoords(2)); - break; - } - } else - theNode = new Node(nodeID, ndf, nodeCoords(0), nodeCoords(1), nodeCoords(2)); - - // theNode = new Node(nodeID,ndf,nodeCoords(0),nodeCoords(1),nodeCoords(2)); +// theNode = new HeapNode(nodeID, ndf, nodeCoords(0), nodeCoords(1), nodeCoords(2)); + theNode = new Node(nodeID,ndf,nodeCoords(0),nodeCoords(1),nodeCoords(2)); if (theTclDomain->addNode(theNode) == false) { - opserr << G3_ERROR_PROMPT << "failed to add node to the domain\n"; + opserr << OpenSees::PromptValueError << "failed to add node to the domain\n"; opserr << "node: " << nodeID << "\n"; delete theNode; return TCL_ERROR; @@ -421,7 +395,7 @@ TclCommand_doBlock(ClientData clientData, Tcl_Interp *interp, int argc, int ndm = builder->getNDM(); if (argc < 1) { - opserr << G3_ERROR_PROMPT << "block {args}\n"; + opserr << OpenSees::PromptValueError << "block {args}\n"; return TCL_ERROR; } diff --git a/SRC/runtime/commands/packages.cpp b/SRC/runtime/commands/packages.cpp index cc3ad4d46c..77f015d871 100644 --- a/SRC/runtime/commands/packages.cpp +++ b/SRC/runtime/commands/packages.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -115,110 +124,6 @@ getLibraryFunction(const char *libName, const char *funcName, void **libHandle, typedef TransientIntegrator** (*OPS_GetTransientIntegratorPtrType)(); typedef ConvergenceTest** (*OPS_GetTestPtrType)(); typedef bool* (*OPS_builtModelPtrType)(); -#if 0 - typedef void(_cdecl* setGlobalPointersFunction)( - OPS_Stream*, - Domain*, - SimulationInformation*, - OPS_ErrorPtrType, - OPS_GetIntInputPtrType, - OPS_GetDoubleInputPtrType, - OPS_AllocateElementPtrType, - OPS_AllocateMaterialPtrType, - OPS_GetUniaxialMaterialPtrType, - OPS_GetNDMaterialPtrType, - OPS_GetSectionForceDeformationPtrType, - OPS_GetCrdTransfPtrType, - OPS_GetFrictionModelPtrType, - OPS_InvokeMaterialDirectlyPtrType, - OPS_GetNodeInfoPtrType, - OPS_GetNodeInfoPtrType, - OPS_GetNodeInfoPtrType, - OPS_GetNodeInfoPtrType, - OPS_GetNodeInfoPtrType, - OPS_GetNodeInfoPtrType, - OPS_GetNumRemainingInputArgsType, - OPS_ResetCurrentInputArgType, - //OPS_ResetInputType, - OPS_ResetInputNoBuilderType, - OPS_GetStringType, - OPS_GetStringCopyType, - OPS_GetIntPtrType, - OPS_GetIntPtrType, - OPS_GetFEDatastorePtrType, - OPS_GetInterpPWD_PtrType, - OPS_GetAnalysisModelPtrType, - OPS_GetAlgorithmPtrType, - OPS_GetHandlerPtrType, - OPS_GetNumbererPtrType, - OPS_GetSOEPtrType, - OPS_GetEigenSOEPtrType, - OPS_GetStaticAnalysisPtrType, - OPS_GetTransientAnalysisPtrType, - OPS_GetVariableTimeStepTransientAnalysisPtrType, - OPS_GetNumEigenPtrType, - OPS_GetStaticIntegratorPtrType, - OPS_GetTransientIntegratorPtrType, - OPS_GetTestPtrType, - OPS_builtModelPtrType, - OPS_GetDomainPointerType); - - setGlobalPointersFunction funcPtr; - // look for pointer function - funcPtr = (setGlobalPointersFunction)GetProcAddress((HMODULE)hLib, "setGlobalPointers"); - if (funcPtr == 0) { - FreeLibrary((HMODULE)hLib); - return -2; - } -#endif -#if 0 - // invoke pointer function - (funcPtr)(opserrPtr, - ops_TheActiveDomain, - nullptr, // theSimulationInfoPtr, - OPS_Error, - OPS_GetIntInput, - OPS_GetDoubleInput, - OPS_AllocateElement, - OPS_AllocateMaterial, - OPS_GetUniaxialMaterial, - OPS_GetNDMaterial, - OPS_GetSectionForceDeformation, - OPS_GetCrdTransf, - OPS_GetFrictionModel, - OPS_InvokeMaterialDirectly, - OPS_GetNodeCrd, - OPS_GetNodeDisp, - OPS_GetNodeVel, - OPS_GetNodeAccel, - OPS_GetNodeIncrDisp, - OPS_GetNodeIncrDeltaDisp, - OPS_GetNumRemainingInputArgs, - OPS_ResetCurrentInputArg, - //OPS_ResetInput, - OPS_ResetInputNoBuilder, - OPS_GetString, - OPS_GetStringCopy, - OPS_GetNDM, - OPS_GetNDF, - OPS_GetFEDatastore, - OPS_GetInterpPWD, - OPS_GetAnalysisModel, - OPS_GetAlgorithm, - OPS_GetHandler, - OPS_GetNumberer, - OPS_GetSOE, - OPS_GetEigenSOE, - OPS_GetStaticAnalysis, - OPS_GetTransientAnalysis, - OPS_GetVariableTimeStepTransientAnalysis, - OPS_GetNumEigen, - OPS_GetStaticIntegrator, - OPS_GetTransientIntegrator, - OPS_GetTest, - OPS_builtModel, - OPS_GetDomain); -# endif LocalInitPtrType initPtr; initPtr = (LocalInitPtrType)GetProcAddress((HMODULE)hLib, "localInit"); if (initPtr != 0) { diff --git a/SRC/runtime/commands/packages.h b/SRC/runtime/commands/packages.h index 2ee1d68c28..f76aed5b2f 100644 --- a/SRC/runtime/commands/packages.h +++ b/SRC/runtime/commands/packages.h @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // diff --git a/SRC/runtime/commands/parallel/CMakeLists.txt b/SRC/runtime/commands/parallel/CMakeLists.txt index 62099d954a..dc3d8af3bf 100644 --- a/SRC/runtime/commands/parallel/CMakeLists.txt +++ b/SRC/runtime/commands/parallel/CMakeLists.txt @@ -1,18 +1,40 @@ +#============================================================================== +# +# OpenSees -- Open System For Earthquake Engineering Simulation +# Pacific Earthquake Engineering Research Center +# +#============================================================================== -target_compile_definitions(OpenSeesRT_Parallel PRIVATE - _PARALLEL_INTERPRETERS - _PARALLEL_PROCESSING # OpenSeesSP +return() + +find_package(MPI) +if (NOT MPI_FOUND) + return() +endif() + + +add_library(OpenSeesRT_Parallel OBJECT) + +target_include_directories(OpenSeesRT_Parallel + PRIVATE + ${OPS_SRC_DIR}/domain/partitioner/ + ${OPS_SRC_DIR}/analysis/analysis/ ) -target_link_libraries(OpenSeesRT_Parallel PRIVATE OPS_Parallel OPS_Actor) -target_sources(OpenSeesRT_Parallel PRIVATE - parallel_commands.cpp + +target_link_libraries(OpenSeesRT_Parallel PRIVATE + OPS_Runtime + OPS_Parallel + OPS_Actor + MPI::MPI_CXX +# ${MPI_CXX_LIBRARIES} ) -add_executable(OpenSeesSP EXCLUDE_FROM_ALL ) -add_executable(OpenSeesMP EXCLUDE_FROM_ALL ) +target_sources(OpenSeesRT_Parallel PRIVATE + machine.cpp +) -if(MKL_FOUND) +if (MKL_FOUND) message(STATUS "MKL was found.") set(SCALAPACK_LIBRARIES ${MKL_LIBRARIES}) else() @@ -21,20 +43,55 @@ else() message(">>> ScaLAPACK: ${ScaLAPACK_LIBRARIES}") endif() -target_link_libraries(OpenSeesRT_Parallel PRIVATE OPS_Parallel OPS_Actor - ${MPI_CXX_LIBRARIES} - /usr/lib/libscalapack.so +target_link_libraries(OpenSeesRT_Parallel PRIVATE + OPS_Parallel + OPS_Actor + MPI::MPI_CXX +# /usr/lib/libscalapack.so ${MPI_Fortran_LIBRARIES} - ${MPI_CXX_LINK_FLAGS} ) -target_sources(OpenSeesMP PRIVATE mpiMain.cpp) -target_link_libraries(OpenSeesMP PRIVATE OPS_Parallel OPS_Actor OpenSeesRT ${MPI_LIBRARIES}) +# +# OpenSeesMP +# +add_library(LibOpenSeesMP SHARED EXCLUDE_FROM_ALL ) +set_property(TARGET LibOpenSeesMP PROPERTY POSITION_INDEPENDENT_CODE 1) + +target_link_libraries(LibOpenSeesMP PRIVATE + OpenSeesRT_Parallel + OPS_Parallel + OPS_Actor + OpenSeesRT + OPS_Runtime + MPI::MPI_CXX +) + +target_sources(LibOpenSeesMP PRIVATE + communicate.cpp + ${OPS_SRC_DIR}/parallel/OpenSeesMP.cpp +) + +# +# OpenSeesSP +# +add_library(LibOpenSeesSP SHARED EXCLUDE_FROM_ALL ) +set_property(TARGET LibOpenSeesSP PROPERTY POSITION_INDEPENDENT_CODE 1) + +target_sources(LibOpenSeesSP PRIVATE + partition.cpp + ${OPS_SRC_DIR}/parallel/OpenSeesSP.cpp +) -target_sources(OpenSeesSP PRIVATE mpiMain.cpp) -target_link_libraries(OpenSeesSP PRIVATE OPS_Parallel OPS_Actor OpenSeesRT ${MPI_LIBRARIES} - ${MPI_CXX_LIBRARIES} - /usr/lib/libscalapack.so - ${MPI_Fortran_LIBRARIES} - ${MPI_CXX_LINK_FLAGS} +target_link_libraries(LibOpenSeesSP + PRIVATE + OpenSeesRT_Parallel + OPS_Parallel + OPS_Partition + OPS_Analysis + OPS_Runtime + OPS_Actor + OpenSeesRT + MPI::MPI_CXX + METIS +# /usr/lib/libscalapack.so ) diff --git a/SRC/runtime/commands/parallel/communicate.cpp b/SRC/runtime/commands/parallel/communicate.cpp new file mode 100644 index 0000000000..33ef252cb4 --- /dev/null +++ b/SRC/runtime/commands/parallel/communicate.cpp @@ -0,0 +1,168 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +#include +#include +#include +#include +#include +#include + + +static int opsBarrier(ClientData, Tcl_Interp *, int, TCL_Char ** const argv); +static int opsSend(ClientData, Tcl_Interp *, int, TCL_Char ** const argv); +static int opsRecv(ClientData, Tcl_Interp *, int,TCL_Char ** const argv); + +void +Init_Communication(Tcl_Interp* interp, MachineBroker* theMachineBroker) +{ + Tcl_CreateCommand(interp, "send", &opsSend, (ClientData)theMachineBroker, (Tcl_CmdDeleteProc *)NULL); + Tcl_CreateCommand(interp, "recv", &opsRecv, (ClientData)theMachineBroker, (Tcl_CmdDeleteProc *)NULL); + Tcl_CreateCommand(interp, "barrier", &opsBarrier, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); +} + + +static int +opsSend(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +{ + if (argc < 2) + return TCL_OK; + + int otherPID = -1; + MachineBroker* theMachineBroker = (MachineBroker*)clientData; + int myPID = theMachineBroker->getPID(); + int np = theMachineBroker->getNP(); + const char *dataToSend = argv[argc - 1]; + int msgLength = strlen(dataToSend) + 1; + + const char *gMsg = dataToSend; + + if (strcmp(argv[1], "-pid") == 0 && argc > 3) { + + if (Tcl_GetInt(interp, argv[2], &otherPID) != TCL_OK) { + opserr << "send -pid pid? data? - pid: " << argv[2] << " invalid\n"; + return TCL_ERROR; + } + + if (otherPID > -1 && otherPID != myPID && otherPID < np) { + + MPI_Send((void *)(&msgLength), 1, MPI_INT, otherPID, 0, MPI_COMM_WORLD); + MPI_Send((void *)gMsg, msgLength, MPI_CHAR, otherPID, 1, MPI_COMM_WORLD); + + } else { + opserr << "send -pid pid? data? - pid: " << otherPID << " invalid\n"; + return TCL_ERROR; + } + + } else { + if (myPID == 0) { + MPI_Bcast((void *)(&msgLength), 1, MPI_INT, 0, MPI_COMM_WORLD); + MPI_Bcast((void *)gMsg, msgLength, MPI_CHAR, 0, MPI_COMM_WORLD); + } else { + opserr << "send data - only process 0 can do a broadcast - you may need " + "to kill the application"; + return TCL_ERROR; + } + } + return TCL_OK; +} + +static int +opsRecv(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +{ + MachineBroker* theMachineBroker = (MachineBroker*)clientData; + if (argc < 2) + return TCL_OK; + + int otherPID = 0; + int myPID = theMachineBroker->getPID(); + int np = theMachineBroker->getNP(); + TCL_Char *varToSet = argv[argc - 1]; + + int msgLength = 0; + char *gMsg = 0; + + if (strcmp(argv[1], "-pid") == 0 && argc > 3) { + + bool fromAny = false; + + if ((strcmp(argv[2], "ANY") == 0) || (strcmp(argv[2], "ANY_SOURCE") == 0) || + (strcmp(argv[2], "MPI_ANY_SOURCE") == 0)) { + fromAny = true; + } else { + if (Tcl_GetInt(interp, argv[2], &otherPID) != TCL_OK) { + opserr << "recv -pid pid? data? - pid: " << argv[2] << " invalid\n"; + return TCL_ERROR; + } + } + + if (otherPID > -1 && otherPID < np) { + MPI_Status status; + + if (fromAny == false) + if (myPID != otherPID) + MPI_Recv((void *)(&msgLength), 1, MPI_INT, otherPID, 0, + MPI_COMM_WORLD, &status); + else { + opserr << "recv -pid pid? data? - " << otherPID + << " cant receive from self!\n"; + return TCL_ERROR; + } + else { + MPI_Recv((void *)(&msgLength), 1, MPI_INT, MPI_ANY_SOURCE, 0, + MPI_COMM_WORLD, &status); + otherPID = status.MPI_SOURCE; + } + + if (msgLength > 0) { + gMsg = new char[msgLength]; + + MPI_Recv((void *)gMsg, msgLength, MPI_CHAR, otherPID, 1, MPI_COMM_WORLD, + &status); + + Tcl_SetVar(interp, varToSet, gMsg, TCL_LEAVE_ERR_MSG); + } + + } else { + opserr << "recv -pid pid? data? - " << otherPID << " invalid\n"; + return TCL_ERROR; + } + } else { + if (myPID != 0) { + MPI_Bcast((void *)(&msgLength), 1, MPI_INT, 0, MPI_COMM_WORLD); + + if (msgLength > 0) { + gMsg = new char[msgLength]; + + MPI_Bcast((void *)gMsg, msgLength, MPI_CHAR, 0, MPI_COMM_WORLD); + + Tcl_SetVar(interp, varToSet, gMsg, TCL_LEAVE_ERR_MSG); + } + + } else { + opserr << "recv data - only process 0 can do a broadcast - you may need " + "to kill the application"; + return TCL_ERROR; + } + } + return TCL_OK; +} + +static int +opsBarrier(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +{ + return MPI_Barrier(MPI_COMM_WORLD); +} + diff --git a/SRC/runtime/commands/parallel/machine.cpp b/SRC/runtime/commands/parallel/machine.cpp new file mode 100644 index 0000000000..9379b450c1 --- /dev/null +++ b/SRC/runtime/commands/parallel/machine.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +#include +#include +#include +#include + +static int getPID(ClientData, Tcl_Interp *, int, TCL_Char ** const argv); +static int getNP( ClientData, Tcl_Interp *, int, TCL_Char ** const argv); + + +void +Init_MachineRuntime(Tcl_Interp* interp, MachineBroker* theMachineBroker) +{ + Tcl_CreateCommand(interp, "getNP", &getNP, (ClientData)theMachineBroker, (Tcl_CmdDeleteProc *)NULL); + Tcl_CreateCommand(interp, "getPID", &getPID, (ClientData)theMachineBroker, (Tcl_CmdDeleteProc *)NULL); +} + +static int +getPID(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +{ + int pid = 0; + + MachineBroker* theMachineBroker = (MachineBroker*)clientData; + + if (theMachineBroker != nullptr) + pid = theMachineBroker->getPID(); + + // now we copy the value to the tcl string that is returned + Tcl_SetObjResult(interp, Tcl_NewIntObj(pid)); + + return TCL_OK; +} + +static int +getNP(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) +{ + int np = 1; + MachineBroker* theMachineBroker = (MachineBroker*)clientData; + + if (theMachineBroker != nullptr) + np = theMachineBroker->getNP(); + + // now we copy the value to the tcl string that is returned + Tcl_SetObjResult(interp, Tcl_NewIntObj(np)); + + return TCL_OK; +} + + diff --git a/SRC/runtime/commands/parallel/mpiMain.cpp b/SRC/runtime/commands/parallel/mpiMain.cpp deleted file mode 100644 index 57db9fc825..0000000000 --- a/SRC/runtime/commands/parallel/mpiMain.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ - -/* - * tclAppInit.c -- - * - * Provides a default version of the main program and Tcl_AppInit - * procedure for Tcl applications (without Tk). - * - * Copyright (c) 1993 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * Copyright (c) 1998-1999 by Scriptics Corporation. - * - * See Tcl/Tk License Terms for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: mpiMain.cpp,v 1.13 2010-04-23 23:01:14 fmk Exp $ - -Tcl/Tk License Terms: -This software is copyrighted by the Regents of the University of -California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState -Corporation and other parties. The following terms apply to all files -associated with the software unless explicitly disclaimed in -individual files. - -The authors hereby grant permission to use, copy, modify, distribute, -and license this software and its documentation for any purpose, provided -that existing copyright notices are retained in all copies and that this -notice is included verbatim in any distributions. No written agreement, -license, or royalty fee is required for any of the authorized uses. -Modifications to this software may be copyrighted by their authors -and need not follow the licensing terms described here, provided that -the new terms are clearly indicated on the first page of each file where -they apply. - -IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY -FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES -ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY -DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE -IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE -NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR -MODIFICATIONS. - -GOVERNMENT USE: If you are acquiring this software on behalf of the -U.S. government, the Government shall have only "Restricted Rights" -in the software and related documentation as defined in the Federal -Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you -are acquiring the software on behalf of the Department of Defense, the -software shall be classified as "Commercial Computer Software" and the -Government shall have only "Restricted Rights" as defined in Clause -252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the -authors grant the U.S. Government and others acting in its behalf -permission to use and distribute the software in accordance with the -terms specified in this license. - - */ - -extern "C" { -#include -} - - -// #include -#include "commands.h" - -/* - * The following variable is a special hack that is needed in order for - * Sun shared libraries to be used for Tcl. - */ - -#ifdef _KAI -//extern "C" int matherr(); -#endif - -#ifdef _UNIX -//#include - -//int *tclDummyMathPtr = (int *)matherr; -#endif - - -#ifdef TCL_TEST - -extern "C" { -#include "tclInt.h" -} - - - -extern int Procbodytest_Init _ANSI_ARGS_((Tcl_Interp *interp)); -extern int Procbodytest_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); -extern int TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp)); -extern int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); -#ifdef TCL_THREADS -extern int TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp)); -#endif - -#endif /* TCL_TEST */ - -#ifdef TCL_XT_TEST -extern void XtToolkitInitialize _ANSI_ARGS_((void)); -extern int Tclxttest_Init _ANSI_ARGS_((Tcl_Interp *interp)); -#endif - -/* - *---------------------------------------------------------------------- - * - * main -- - * - * This is the main program for the application. - * - * Results: - * None: Tcl_Main never returns here, so this procedure never - * returns either. - * - * Side effects: - * Whatever the application does. - * - *---------------------------------------------------------------------- - */ - -extern void g3TclMain(int argc, char **argv, Tcl_AppInitProc *appInitProc, int rank, int np); -#include -#include - -#include -#include -#include -#include -#include - -#include - -extern PartitionedDomain theDomain; -extern int OPS_PARALLEL_PROCESSING; -extern int OPS_NUM_SUBDOMAINS; -extern bool OPS_PARTITIONED; -extern FEM_ObjectBroker *OPS_OBJECT_BROKER; -extern MachineBroker *OPS_MACHINE; -extern bool OPS_USING_MAIN_DOMAIN; -extern int OPS_MAIN_DOMAIN_PARTITION_ID; - -extern DomainPartitioner *OPS_DOMAIN_PARTITIONER; -extern GraphPartitioner *OPS_GRAPH_PARTITIONER; -extern LoadBalancer *OPS_BALANCER; -extern FEM_ObjectBroker *OPS_OBJECT_BROKER; -extern MachineBroker *OPS_MACHINE; -extern Channel **OPS_theChannels; - -extern MachineBroker *theMachineBroker; -extern Channel **theChannels; -extern int numChannels; -extern int OPS_rank; -extern int OPS_np; - -#include - -int -main(int argc, char **argv) -{ - theMachineBroker = new MPI_MachineBroker(0, argc, argv); - FEM_ObjectBrokerAllClasses theBroker; - theMachineBroker->setObjectBroker(&theBroker); - - OPS_rank = theMachineBroker->getPID(); - OPS_np = theMachineBroker->getNP(); - - // - // depending on rank we do something - // - if (OPS_rank != 0) { - - // - // on secondary processes we spin waiting to create & run actors - // - fprintf(stderr, "Secondary Process Running %d\n", OPS_rank); - theMachineBroker->runActors(); - - } else { - - // - // on process 0 we create some ShadowSubdomains & then start the OpenSees interpreter - // - fprintf(stderr, "Primary Process Running OpenSees Interpreter %d\n", OPS_rank); - - // - // set some global parameters - // - OPS_OBJECT_BROKER = &theBroker; - // OPS_MACHINE = &theMachine; - OPS_MACHINE = theMachineBroker; - OPS_PARALLEL_PROCESSING = OPS_np; - - /* only use p0 if even number of partitions - if (OPS_np%2 == 0) { - OPS_NUM_SUBDOMAINS = OPS_np; - OPS_USING_MAIN_DOMAIN = true; - OPS_MAIN_DOMAIN_PARTITION_ID = 1; - } else - OPS_NUM_SUBDOMAINS = OPS_np - 1; - */ - // always use p0 even if ODD number of partitions - OPS_NUM_SUBDOMAINS = OPS_np; - OPS_USING_MAIN_DOMAIN = true; - OPS_MAIN_DOMAIN_PARTITION_ID = 1; - - OPS_PARTITIONED = false; - - // - // the rest straightr out of regular tclMain to start our interpreter - // - - /* - * The following #if block allows you to change the AppInit - * function by using a #define of TCL_LOCAL_APPINIT instead - * of rewriting this entire file. The #if checks for that - * #define and uses Tcl_AppInit if it doesn't exist. - */ - -#ifndef TCL_LOCAL_APPINIT -#define TCL_LOCAL_APPINIT Tcl_AppInit -#endif - - /* fmk - comment out the following block to get to compile - extern "C" int TCL_LOCAL_APPINIT _ANSI_ARGS_((Tcl_Interp *interp)); - fmk - end commented block */ - - /* - * The following #if block allows you to change how Tcl finds the startup - * script, prime the library or encoding paths, fiddle with the argv, - * etc., without needing to rewrite Tcl_Main() - */ - -#ifdef TCL_LOCAL_MAIN_HOOK - extern int TCL_LOCAL_MAIN_HOOK _ANSI_ARGS_((int *argc, char ***argv)); -#endif - -#ifdef TCL_XT_TEST - XtToolkitInitialize(); -#endif - -#ifdef TCL_LOCAL_MAIN_HOOK - TCL_LOCAL_MAIN_HOOK(&argc, &argv); -#endif - - g3TclMain(argc, argv, TCL_LOCAL_APPINIT, 1, 0); - - // some clean up to shut the remotes down if still running - theDomain.clearAll(); - - // shutdown the remote machines - theMachineBroker->shutdown(); - } - - // - // mpi clean up - // - - fprintf(stderr, "Process Terminating %d\n", OPS_rank); - - if (theMachineBroker != 0) - delete theMachineBroker; - - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_AppInit -- - * - * This procedure performs application-specific initialization. - * Most applications, especially those that incorporate additional - * packages, will have their own version of this procedure. - * - * Results: - * Returns a standard Tcl completion code, and leaves an error - * message in the interp's result if an error occurs. - * - * Side effects: - * Depends on the startup script. - * - *---------------------------------------------------------------------- - */ - - -int Tcl_AppInit(Tcl_Interp *interp) -{ - if (Tcl_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } - -#ifdef TCL_TEST -#ifdef TCL_XT_TEST - if (Tclxttest_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } -#endif - if (Tcltest_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } - Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, - (Tcl_PackageInitProc *) NULL); - if (TclObjTest_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } -#ifdef TCL_THREADS - if (TclThread_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } -#endif - if (Procbodytest_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } - Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init, - Procbodytest_SafeInit); -#endif /* TCL_TEST */ - - /* - * Call the init procedures for included packages. Each call should - * look like this: - * - * if (Mod_Init(interp) == TCL_ERROR) { - * return TCL_ERROR; - * } - * - * where "Mod" is the name of the module. - */ - - /* - * Call Tcl_CreateCommand for application-specific commands, if - * they weren't already created by the init procedures called above. - */ - - if (OpenSeesAppInit(interp) < 0) - return TCL_ERROR; - - /* - * Specify a user-specific startup file to invoke if the application - * is run interactively. Typically the startup file is "~/.apprc" - * where "app" is the name of the application. If this line is deleted - * then no user-specific startup file will be run under any conditions. - */ - - Tcl_SetVar(interp, "tcl_rcFileName", "~/.tclshrc", TCL_GLOBAL_ONLY); - return TCL_OK; -} - - diff --git a/SRC/runtime/commands/parallel/parallel_commands.cpp b/SRC/runtime/commands/parallel/parallel_commands.cpp deleted file mode 100644 index 2804def62a..0000000000 --- a/SRC/runtime/commands/parallel/parallel_commands.cpp +++ /dev/null @@ -1,355 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// OpenSees - Open System for Earthquake Engineering Simulation -// -//===----------------------------------------------------------------------===// -// -// -#include -#include -#include -#include -#include - -#define _PARALLEL_MP - -#ifdef _PARALLEL_SP -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include - -# define MPIPP_H -# include -# include - -// MachineBroker *theMachineBroker = 0; - int OPS_PARALLEL_SP = 0; - int OPS_NUM_SUBDOMAINS = 0; - bool OPS_PARTITIONED = false; - bool OPS_USING_MAIN_DOMAIN = false; - bool setMPIDSOEFlag = false; - int OPS_MAIN_DOMAIN_PARTITION_ID = 0; - PartitionedDomain theDomain; - DomainPartitioner *OPS_DOMAIN_PARTITIONER = nullptr; - GraphPartitioner *OPS_GRAPH_PARTITIONER = nullptr; - LoadBalancer *OPS_BALANCER = nullptr; - TclPackageClassBroker *OPS_OBJECT_BROKER = nullptr; - MachineBroker *OPS_MACHINE = nullptr; - Channel **OPS_theChannels = nullptr; - -# elif defined(_PARALLEL_MP) - - bool setMPIDSOEFlag = false; - - // parallel analysis - #include - -// Domain theDomain; -#endif - -int getPID(ClientData, Tcl_Interp *, int, TCL_Char ** const argv); -int getNP( ClientData, Tcl_Interp *, int, TCL_Char ** const argv); -int opsBarrier(ClientData, Tcl_Interp *, int, TCL_Char ** const argv); -int opsSend(ClientData, Tcl_Interp *, int, TCL_Char ** const argv); -int opsRecv(ClientData, Tcl_Interp *, int,TCL_Char ** const argv); -int opsPartition(ClientData, Tcl_Interp *, int, TCL_Char ** const argv); -int wipePP(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv); - -void Init_Parallel(Tcl_Interp* interp) -{ - MachineBroker* theMachineBroker = new MPI_MachineBroker(nullptr, 0, nullptr); - Tcl_CreateCommand(interp, "getNP", &getNP, (ClientData)theMachineBroker, (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateCommand(interp, "getPID", &getPID, (ClientData)theMachineBroker, (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateCommand(interp, "send", &opsSend, (ClientData)theMachineBroker, (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateCommand(interp, "recv", &opsRecv, (ClientData)theMachineBroker, (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateCommand(interp, "barrier", &opsBarrier, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); - Tcl_CreateCommand(interp, "partition", &opsPartition, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL); -} - - -int -getPID(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - int pid = 0; - - MachineBroker* theMachineBroker = (MachineBroker*)clientData; - - if (theMachineBroker != nullptr) - pid = theMachineBroker->getPID(); - - // now we copy the value to the tcl string that is returned - char buffer[30]; - sprintf(buffer, "%d", pid); - Tcl_SetResult(interp, buffer, TCL_VOLATILE); - - return TCL_OK; -} - -int -getNP(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - int np = 1; - MachineBroker* theMachineBroker = (MachineBroker*)clientData; - - if (theMachineBroker != nullptr) - np = theMachineBroker->getNP(); - - // now we copy the value to the tcl string that is returned - char buffer[30]; - sprintf(buffer, "%d", np); - Tcl_SetResult(interp, buffer, TCL_VOLATILE); - - return TCL_OK; -} - - -#ifdef _PARALLEL_SP -static int -partitionModel(int eleTag) -{ - if (OPS_PARTITIONED == true) - return 0; - - int result = 0; - - if (OPS_theChannels != 0) - delete[] OPS_theChannels; - - OPS_theChannels = new Channel *[OPS_NUM_SUBDOMAINS]; - - // create some subdomains - for (int i = 1; i <= OPS_NUM_SUBDOMAINS; i++) { - if (i != OPS_MAIN_DOMAIN_PARTITION_ID) { - ShadowSubdomain *theSubdomain = - new ShadowSubdomain(i, *OPS_MACHINE, *OPS_OBJECT_BROKER); - theDomain.addSubdomain(theSubdomain); - OPS_theChannels[i - 1] = theSubdomain->getChannelPtr(); - } - } - - // create a partitioner & partition the domain - if (OPS_DOMAIN_PARTITIONER == nullptr) { - // OPS_BALANCER = new ShedHeaviest(); - OPS_GRAPH_PARTITIONER = new Metis; - // OPS_DOMAIN_PARTITIONER = new DomainPartitioner(*OPS_GRAPH_PARTITIONER, - // *OPS_BALANCER); - OPS_DOMAIN_PARTITIONER = new DomainPartitioner(*OPS_GRAPH_PARTITIONER); - theDomain.setPartitioner(OPS_DOMAIN_PARTITIONER); - } - - result = theDomain.partition(OPS_NUM_SUBDOMAINS, OPS_USING_MAIN_DOMAIN, - OPS_MAIN_DOMAIN_PARTITION_ID, eleTag); - - if (result < 0) - return result; - - OPS_PARTITIONED = true; - - DomainDecompositionAnalysis *theSubAnalysis; - SubdomainIter &theSubdomains = theDomain.getSubdomains(); - Subdomain *theSub = 0; - - // create the appropriate domain decomposition analysis - while ((theSub = theSubdomains()) != 0) { - if (the_static_analysis != 0) { - theSubAnalysis = new StaticDomainDecompositionAnalysis( - *theSub, *theHandler, *theNumberer, *the_analysis_model, *theAlgorithm, - *theSOE, *theStaticIntegrator, theTest, false); - - } else { - theSubAnalysis = new TransientDomainDecompositionAnalysis( - *theSub, *theHandler, *theNumberer, *the_analysis_model, *theAlgorithm, - *theSOE, *theTransientIntegrator, theTest, false); - } - theSub->setDomainDecompAnalysis(*theSubAnalysis); - } - - return result; -} -#endif - - -int -opsBarrier(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ -#ifdef _PARALLEL_MP - return MPI_Barrier(MPI_COMM_WORLD); -#endif - return TCL_OK; -} - -int -opsSend(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - if (argc < 2) - return TCL_OK; - - int otherPID = -1; - MachineBroker* theMachineBroker = (MachineBroker*)clientData; - int myPID = theMachineBroker->getPID(); - int np = theMachineBroker->getNP(); - const char *dataToSend = argv[argc - 1]; - int msgLength = strlen(dataToSend) + 1; - - const char *gMsg = dataToSend; - // strcpy(gMsg, dataToSend); - - if (strcmp(argv[1], "-pid") == 0 && argc > 3) { - - if (Tcl_GetInt(interp, argv[2], &otherPID) != TCL_OK) { - opserr << "send -pid pid? data? - pid: " << argv[2] << " invalid\n"; - return TCL_ERROR; - } - - if (otherPID > -1 && otherPID != myPID && otherPID < np) { - - MPI_Send((void *)(&msgLength), 1, MPI_INT, otherPID, 0, MPI_COMM_WORLD); - MPI_Send((void *)gMsg, msgLength, MPI_CHAR, otherPID, 1, MPI_COMM_WORLD); - - } else { - opserr << "send -pid pid? data? - pid: " << otherPID << " invalid\n"; - return TCL_ERROR; - } - - } else { - if (myPID == 0) { - MPI_Bcast((void *)(&msgLength), 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast((void *)gMsg, msgLength, MPI_CHAR, 0, MPI_COMM_WORLD); - } else { - opserr << "send data - only process 0 can do a broadcast - you may need " - "to kill the application"; - return TCL_ERROR; - } - } - return TCL_OK; -} - -int -opsRecv(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ -#ifdef _PARALLEL_MP - MachineBroker* theMachineBroker = (MachineBroker*)clientData; - if (argc < 2) - return TCL_OK; - - int otherPID = 0; - int myPID = theMachineBroker->getPID(); - int np = theMachineBroker->getNP(); - TCL_Char *varToSet = argv[argc - 1]; - - int msgLength = 0; - char *gMsg = 0; - - if (strcmp(argv[1], "-pid") == 0 && argc > 3) { - - bool fromAny = false; - - if ((strcmp(argv[2], "ANY") == 0) || (strcmp(argv[2], "ANY_SOURCE") == 0) || - (strcmp(argv[2], "MPI_ANY_SOURCE") == 0)) { - fromAny = true; - } else { - if (Tcl_GetInt(interp, argv[2], &otherPID) != TCL_OK) { - opserr << "recv -pid pid? data? - pid: " << argv[2] << " invalid\n"; - return TCL_ERROR; - } - } - - if (otherPID > -1 && otherPID < np) { - MPI_Status status; - - if (fromAny == false) - if (myPID != otherPID) - MPI_Recv((void *)(&msgLength), 1, MPI_INT, otherPID, 0, - MPI_COMM_WORLD, &status); - else { - opserr << "recv -pid pid? data? - " << otherPID - << " cant receive from self!\n"; - return TCL_ERROR; - } - else { - MPI_Recv((void *)(&msgLength), 1, MPI_INT, MPI_ANY_SOURCE, 0, - MPI_COMM_WORLD, &status); - otherPID = status.MPI_SOURCE; - } - - if (msgLength > 0) { - gMsg = new char[msgLength]; - - MPI_Recv((void *)gMsg, msgLength, MPI_CHAR, otherPID, 1, MPI_COMM_WORLD, - &status); - - Tcl_SetVar(interp, varToSet, gMsg, TCL_LEAVE_ERR_MSG); - } - - } else { - opserr << "recv -pid pid? data? - " << otherPID << " invalid\n"; - return TCL_ERROR; - } - } else { - if (myPID != 0) { - MPI_Bcast((void *)(&msgLength), 1, MPI_INT, 0, MPI_COMM_WORLD); - - if (msgLength > 0) { - gMsg = new char[msgLength]; - - MPI_Bcast((void *)gMsg, msgLength, MPI_CHAR, 0, MPI_COMM_WORLD); - - Tcl_SetVar(interp, varToSet, gMsg, TCL_LEAVE_ERR_MSG); - } - - } else { - opserr << "recv data - only process 0 can do a broadcast - you may need " - "to kill the application"; - return TCL_ERROR; - } - } -#endif - - return TCL_OK; -} - - -int -opsPartition(ClientData clientData, Tcl_Interp *interp, int argc, - TCL_Char ** const argv) -{ -#ifdef _PARALLEL_SP - int eleTag; - if (argc == 2) { - if (Tcl_GetInt(interp, argv[1], &eleTag) != TCL_OK) { - ; - } - } - partitionModel(eleTag); -#endif - return TCL_OK; -} - -int -wipePP(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv) -{ - -#ifdef _PARALLEL_SP - if (OPS_PARTITIONED == true && OPS_NUM_SUBDOMAINS > 1) { - SubdomainIter &theSubdomains = theDomain.getSubdomains(); - Subdomain *theSub =0; - - // create the appropriate domain decomposition analysis - while ((theSub = theSubdomains()) != 0) - theSub->wipeAnalysis(); - } -#endif - return TCL_OK; -} - diff --git a/SRC/runtime/commands/parallel/partition.cpp b/SRC/runtime/commands/parallel/partition.cpp new file mode 100644 index 0000000000..b99f3412ac --- /dev/null +++ b/SRC/runtime/commands/parallel/partition.cpp @@ -0,0 +1,166 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + struct PartitionRuntime { + MachineBroker *machine = nullptr; + FEM_ObjectBroker *broker = nullptr; + DomainPartitioner *DOMAIN_partitioner = nullptr; + GraphPartitioner *GRAPH_partitioner = nullptr; + Channel **channels = nullptr; + int num_subdomains = 0; + bool partitioned = false; + bool using_main_domain = false; + bool setMPIDSOEFlag = false; + int main_partition = 0; + PartitionedDomain theDomain; + }; + + +static int partitionModel(PartitionRuntime& part, int eleTag); +static Tcl_CmdProc opsPartition; +static Tcl_CmdProc wipePP; +extern Tcl_CmdProc TclCommand_specifyModel; + +void +Init_PartitionRuntime(Tcl_Interp* interp, MachineBroker* theMachineBroker, FEM_ObjectBroker* theBroker) +{ + PartitionRuntime *part = new PartitionRuntime{theMachineBroker, theBroker}; + + // + // set some global parameters + // + if (theMachineBroker->getPID() == 0) { + + // always use p0 even if ODD number of partitions + part->num_subdomains = theMachineBroker->getNP(); + part->using_main_domain = true; + part->main_partition = 1; + + } else { + part->using_main_domain = false; + part->num_subdomains = 0; + part->partitioned = false; + + } + + + Tcl_CreateCommand(interp, "partition", &opsPartition, (ClientData)part, (Tcl_CmdDeleteProc *)NULL); + Tcl_CreateCommand(interp, "wipePP", &wipePP, (ClientData)part, (Tcl_CmdDeleteProc *)NULL); + Tcl_CreateCommand(interp, "model", &TclCommand_specifyModel, (ClientData)&part->theDomain, (Tcl_CmdDeleteProc *)NULL); +} + + + +int +opsPartition(ClientData clientData, Tcl_Interp *interp, int argc, + TCL_Char ** const argv) +{ + PartitionRuntime& part = *static_cast(clientData); + + int eleTag; + if (argc == 2) { + if (Tcl_GetInt(interp, argv[1], &eleTag) != TCL_OK) { + ; + } + } + partitionModel(part, eleTag); + return TCL_OK; +} + +static int +partitionModel(PartitionRuntime& part, int eleTag) +{ + if (part.partitioned == true) + return 0; + + int result = 0; + + if (part.channels != nullptr) + delete[] part.channels; + + part.channels = new Channel *[part.num_subdomains]; + + // create some subdomains + for (int i = 1; i <= part.num_subdomains; i++) { + if (i != part.main_partition) { + ShadowSubdomain *theSubdomain = + new ShadowSubdomain(i, *part.machine, *part.broker); + part.theDomain.addSubdomain(theSubdomain); + part.channels[i - 1] = theSubdomain->getChannelPtr(); + } + } + + // create a partitioner & partition the domain + if (part.DOMAIN_partitioner == nullptr) { + // part.balancer = new ShedHeaviest(); + // OPS_DOMAIN_partitioner = new DomainPartitioner(*OPS_GRAPH_partitioner, *part.balancer); + part.GRAPH_partitioner = new Metis; + part.DOMAIN_partitioner = new DomainPartitioner(*part.GRAPH_partitioner); + part.theDomain.setPartitioner(part.DOMAIN_partitioner); + } + + result = part.theDomain.partition(part.num_subdomains, part.using_main_domain, + part.main_partition, eleTag); + + if (result < 0) + return result; + + part.partitioned = true; + + DomainDecompositionAnalysis *theSubAnalysis; + SubdomainIter &theSubdomains = part.theDomain.getSubdomains(); + Subdomain *theSub = nullptr; + + void* the_static_analysis = nullptr; + + return result; +} + + +static int +wipePP(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv) +{ + PartitionRuntime& part = *static_cast(clientData); + + if (part.partitioned == true && part.num_subdomains > 1) { + SubdomainIter &theSubdomains = part.theDomain.getSubdomains(); + Subdomain *theSub =nullptr; + + // create the appropriate domain decomposition analysis + while ((theSub = theSubdomains()) != nullptr) + theSub->wipeAnalysis(); + } + return TCL_OK; +} + diff --git a/SRC/runtime/commands/parallel/sequential.cpp b/SRC/runtime/commands/parallel/sequential.cpp index 9fcbba337f..06b34dc996 100644 --- a/SRC/runtime/commands/parallel/sequential.cpp +++ b/SRC/runtime/commands/parallel/sequential.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -69,52 +78,3 @@ opsRecvSequential(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char return TCL_OK; } - - -#if 0 -int -opsSendSequential(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char ** const argv) -{ - if (argc < 2) - return TCL_OK; - - int otherPID = -1; - int myPID = theMachineBroker->getPID(); - int np = theMachineBroker->getNP(); - const char *dataToSend = argv[argc - 1]; - int msgLength = strlen(dataToSend) + 1; - - const char *gMsg = dataToSend; - // strcpy(gMsg, dataToSend); - - if (strcmp(argv[1], "-pid") == 0 && argc > 3) { - - if (Tcl_GetInt(interp, argv[2], &otherPID) != TCL_OK) { - opserr << "send -pid pid? data? - pid: " << argv[2] << " invalid\n"; - return TCL_ERROR; - } - - if (otherPID > -1 && otherPID != myPID && otherPID < np) { - - MPI_Send((void *)(&msgLength), 1, MPI_INT, otherPID, 0, MPI_COMM_WORLD); - MPI_Send((void *)gMsg, msgLength, MPI_CHAR, otherPID, 1, MPI_COMM_WORLD); - - } else { - opserr << "send -pid pid? data? - pid: " << otherPID << " invalid\n"; - return TCL_ERROR; - } - - } else { - if (myPID == 0) { - MPI_Bcast((void *)(&msgLength), 1, MPI_INT, 0, MPI_COMM_WORLD); - MPI_Bcast((void *)gMsg, msgLength, MPI_CHAR, 0, MPI_COMM_WORLD); - } else { - opserr << "send data - only process 0 can do a broadcast - you may need " - "to kill the application"; - return TCL_ERROR; - } - } - return TCL_OK; -} - -#endif diff --git a/SRC/runtime/commands/pragma.cpp b/SRC/runtime/commands/pragma.cpp index a442e832ad..5514f13444 100644 --- a/SRC/runtime/commands/pragma.cpp +++ b/SRC/runtime/commands/pragma.cpp @@ -1,17 +1,27 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// // #include #include -#include +#include + +class Domain; int TclObjCommand_pragma([[maybe_unused]] ClientData clientData, - Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) + Tcl_Interp *interp, Tcl_Size objc, Tcl_Obj *const objv[]) { if (objc == 1) return TCL_OK; @@ -29,6 +39,7 @@ TclObjCommand_pragma([[maybe_unused]] ClientData clientData, "proc system {args} {}\n" "proc test {args} {}\n" "proc algorithm {args} {}\n" + "proc sensitivityAlgorithm {args} {}\n" "proc integrator {args} {}\n" "proc analysis {args} {}\n" "proc analyze {args} {return 0}\n" @@ -36,7 +47,24 @@ TclObjCommand_pragma([[maybe_unused]] ClientData clientData, "namespace eval opensees::pragma {set analysis off}\n" ); return TCL_OK; - } + } else if (argi < objc && strcmp(Tcl_GetString(objv[argi]), "on") == 0) { + Tcl_Eval(interp, + "proc loadConst {args} {return 0}\n" + "proc wipeAnalysis {args} {return 0}\n" + "proc constraints {args} {return 0}\n" + "proc numberer {args} {return 0}\n" + "proc system {args} {return 0}\n" + "proc test {args} {return 0}\n" + "proc algorithm {args} {return 0}\n" + "proc sensitivityAlgorithm {args} {return 0}\n" + "proc integrator {args} {return 0}\n" + "proc analysis {args} {return 0}\n" + "proc analyze {args} {}\n" + "proc eigen {args} {}\n" + "namespace eval opensees::pragma {set analysis on}\n" + ); + return TCL_OK; + } } else if (strcmp(pragma, "openseespy") == 0) { if (argi < objc && strcmp(Tcl_GetString(objv[argi]), "off") == 0) { diff --git a/SRC/runtime/commands/strings.cpp b/SRC/runtime/commands/strings.cpp index cf3bf6ea67..9d9bfb7c63 100644 --- a/SRC/runtime/commands/strings.cpp +++ b/SRC/runtime/commands/strings.cpp @@ -1,31 +1,18 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// // -#if 0 -static const char* -classic_banner = R"( - - OpenSees -- Open System For Earthquake Engineering Simulation - Pacific Earthquake Engineering Research Center - Version 3.4.0 64-Bit - - (c) Copyright 1999-2022 The Regents of the University of California - All Rights Reserved - (Copyright and Disclaimer @ http://www.berkeley.edu/OpenSees/copyright.html) - -)"; - -static const char* -peer_banner = R"( - OpenSees -- Open System For Earthquake Engineering Simulation - ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - Pacific Earthquake Engineering Research Center -)"; -#endif static const char* unicode_banner diff --git a/SRC/runtime/commands/utilities/formats.cpp b/SRC/runtime/commands/utilities/formats.cpp index c636aed84a..455c6fb001 100644 --- a/SRC/runtime/commands/utilities/formats.cpp +++ b/SRC/runtime/commands/utilities/formats.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -11,7 +20,8 @@ #include #include #include -#include +#include +#include extern int binaryToText(const char *inputFile, const char *outputFile); extern int textToBinary(const char *inputFile, const char *outputFile); diff --git a/SRC/runtime/commands/utilities/linalg.hh b/SRC/runtime/commands/utilities/linalg.h similarity index 87% rename from SRC/runtime/commands/utilities/linalg.hh rename to SRC/runtime/commands/utilities/linalg.h index d398e05697..5674718228 100644 --- a/SRC/runtime/commands/utilities/linalg.hh +++ b/SRC/runtime/commands/utilities/linalg.h @@ -1,7 +1,52 @@ - +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// const char *linalg[] = {R"END( -# https://wiki.tcl-lang.org/page/range +namespace eval OpenSees { +namespace export verify + +proc verify {cmd {value ""} {reference ""} {tolerance 1e-12} {about ""}} { + if {$cmd == "error"} { + set check [expr abs(($value - $reference)/$reference)] + if {$check > $tolerance} { + puts " \033\[31mFAIL\033\[0m: | $value - $reference | = $check > $tolerance" + error "$about" + } else { + puts " \033\[32mPASS\033\[0m "; # " $value $reference $about" + } + + } elseif {$cmd == "value"} { + if {abs($value - $reference) > $tolerance} { + set check [expr abs($value - $reference)] + puts " \033\[31mFAIL\033\[0m($about): | $value - $reference | = $check > $tolerance" + error "$about" + } else { + puts " \033\[32mPASS\033\[0m "; # "$value $reference $about" + } + } else { + # value or "about" + puts " $value" + } +} + +}; # namespace OpenSees + +namespace import OpenSees::verify + proc range args { + # https://wiki.tcl-lang.org/page/range foreach {start stop step} [switch -exact -- [llength $args] { 1 {concat 0 $args 1} 2 {concat $args 1} @@ -17,8 +62,9 @@ proc range args { return $range } -# https://opensource.apple.com/source/tcl/tcl-118.50.1/tcl_ext/tklib/tklib/examples/plotchart/rosenbrock.tcl.auto.htm proc linspace {min max num} { + # https://opensource.apple.com/source/tcl/tcl-118.50.1/tcl_ext/tklib/tklib/examples/plotchart/rosenbrock.tcl.auto.htm + #set opts { # {min.arg 0.0 "the minimum value in the range"} # {max.arg 1.0 "the maximum value in the range"} diff --git a/SRC/runtime/commands/utilities/progress.cpp b/SRC/runtime/commands/utilities/progress.cpp index 2920c37679..f9d96620ff 100644 --- a/SRC/runtime/commands/utilities/progress.cpp +++ b/SRC/runtime/commands/utilities/progress.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // diff --git a/SRC/runtime/commands/utilities/sdofResponse.cpp b/SRC/runtime/commands/utilities/sdofResponse.cpp index 42e6c246b5..4c9bb8156c 100644 --- a/SRC/runtime/commands/utilities/sdofResponse.cpp +++ b/SRC/runtime/commands/utilities/sdofResponse.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // diff --git a/SRC/runtime/commands/utilities/txt2bin.cpp b/SRC/runtime/commands/utilities/txt2bin.cpp index c5a3ac4ad5..b29076c636 100644 --- a/SRC/runtime/commands/utilities/txt2bin.cpp +++ b/SRC/runtime/commands/utilities/txt2bin.cpp @@ -1,3 +1,18 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// #include #include #include diff --git a/SRC/runtime/commands/utilities/utilities.cpp b/SRC/runtime/commands/utilities/utilities.cpp index 4fc3633ccb..6333d0ecd8 100644 --- a/SRC/runtime/commands/utilities/utilities.cpp +++ b/SRC/runtime/commands/utilities/utilities.cpp @@ -1,5 +1,20 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// #include -#include "utilities/linalg.hh" +#include "utilities/linalg.h" int init_g3_tcl_utils(Tcl_Interp* interp) { diff --git a/SRC/runtime/executable/CMakeLists.txt b/SRC/runtime/executable/CMakeLists.txt new file mode 100644 index 0000000000..e94194f1b2 --- /dev/null +++ b/SRC/runtime/executable/CMakeLists.txt @@ -0,0 +1,23 @@ +#============================================================================== +# +# OpenSees -- Open System For Earthquake Engineering Simulation +# Pacific Earthquake Engineering Research Center +# +#============================================================================== + +add_executable(xara_repl main.cpp) +set_target_properties(xara_repl PROPERTIES + OUTPUT_NAME "xara" +) +if (WIN32) + target_link_libraries(xara_repl PRIVATE Netapi32.lib) + target_link_libraries(xara_repl PRIVATE ${TCL_LIBRARIES} OpenSeesRT) +else() + target_link_libraries(xara_repl PRIVATE ${TCL_LIBRARY} OpenSeesRT) +endif() + +add_executable(xara_static static.cpp) +set_target_properties(xara_static PROPERTIES + OUTPUT_NAME "xaras" +) +target_link_libraries(xara_static PUBLIC ${TCL_LIBRARY} OpenSeesRT_Static OPS_Runtime) \ No newline at end of file diff --git a/SRC/runtime/executable/main.cpp b/SRC/runtime/executable/main.cpp new file mode 100644 index 0000000000..f8f9d2e630 --- /dev/null +++ b/SRC/runtime/executable/main.cpp @@ -0,0 +1,320 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +#include +#include +#include + +#ifndef _WIN32 +# include +#endif + +#ifdef USE_TCL_STUBS +#undef USE_TCL_STUBS +#endif + +extern "C" { +#include +#include + #ifdef _TCL85 + #define TclFormatInt(buf, n) sprintf((buf),"%ld", (long)(n)) + #else + EXTERN int TclFormatInt _ANSI_ARGS_((char *buffer, long n)); + #endif + EXTERN int TclObjCommandComplete _ANSI_ARGS_((Tcl_Obj *cmdPtr)); +} + + +# undef TCL_STORAGE_CLASS +# define TCL_STORAGE_CLASS DLLEXPORT + + +/* + * Declarations for various library procedures and variables (don't want + * to include tclPort.h here, because people might copy this file out of + * the Tcl source directory to make their own modified versions). + * Note: "exit" should really be declared here, but there's no way to + * declare it without causing conflicts with other definitions elsewher + * on some systems, so it's better just to leave it out. + */ + +#ifdef _WIN32 +extern "C" int isatty _ANSI_ARGS_((int fd)); +//extern "C" char * strcpy _ANSI_ARGS_((char *dst, CONST char *src)) throw(); +#endif + +static int +LoadOpenSeesRT(Tcl_Interp* interp) +{ + char* path = getenv("OPENSEESRT_LIB"); + if (path) { + std::string path_string{path}; + std::string statement = std::string("import ") + path_string; + int status = Tcl_Eval(interp, statement.c_str()); + + if (status == TCL_OK) { + // Library was loaded, now set variable in interpreter + Tcl_Eval(interp, ( + std::string("set OPENSEESRT_LIB ") + path_string + ).c_str() + ); + return status; + } + } else { + return TCL_ERROR; + } + + return TCL_OK; +} + + +static char *tclStartupScriptFileName = NULL; + +void +TclSetStartupScriptFileName(char *fileName) +{ + tclStartupScriptFileName = fileName; +} + +char * +TclGetStartupScriptFileName() +{ + return tclStartupScriptFileName; +} + +/* + *---------------------------------------------------------------------- + * + * Main program for the xara interactive shell. + * + *---------------------------------------------------------------------- + */ + +static bool OPS_showHeader = false; + +int +main(int argc, char **argv) +{ + Tcl_Obj *resultPtr; + Tcl_Obj *commandPtr = NULL; + char buffer[1000], *args; + int code, gotPartial, tty, length; + int exitCode = 0; + Tcl_Channel inChannel, outChannel, errChannel; + Tcl_Interp *interp; + Tcl_DString argString; + + interp = Tcl_CreateInterp(); + if (Tcl_InitStubs(interp, "8.5-10", 0) == NULL) { + fprintf(stderr, "Tcl_InitStubs failed: %s\n", Tcl_GetStringResult(interp)); + exit(1); + } + + + if (OPS_showHeader) { + fprintf(stderr,"\n\n"); + fprintf(stderr," OpenSees -- Open System For Earthquake Engineering Simulation\n"); + fprintf(stderr," Pacific Earthquake Engineering Research Center\n"); + + fprintf(stderr," (c) Copyright 1999-2025 The Regents of the University of California\n"); + fprintf(stderr," All Rights Reserved\n"); + fprintf(stderr," (Copyright and Disclaimer @ http://www.berkeley.edu/OpenSees/copyright.html)\n\n\n"); + } + + + Tcl_Eval(interp, "rename load import;"); + Tcl_Eval(interp, "interp alias {} load {} import;"); + + /* + * Make command-line arguments available in the Tcl variables "argc" + * and "argv". If the first argument doesn't start with a "-" then + * strip it off and use it as the name of a script file to process. + */ + tclStartupScriptFileName = argv[1]; + if (tclStartupScriptFileName == NULL) { + if ((argc > 1) && (argv[1][0] != '-')) { + tclStartupScriptFileName = argv[1]; + argc--; + argv++; + } + } + + args = Tcl_Merge(argc-1, argv+1); + Tcl_ExternalToUtfDString(NULL, args, -1, &argString); + Tcl_SetVar(interp, "argv", Tcl_DStringValue(&argString), TCL_GLOBAL_ONLY); + Tcl_DStringFree(&argString); + ckfree(args); + + + if (tclStartupScriptFileName == NULL) { + Tcl_ExternalToUtfDString(NULL, argv[0], -1, &argString); + } else { + tclStartupScriptFileName = Tcl_ExternalToUtfDString(NULL, + tclStartupScriptFileName, -1, &argString); + } + + /* + * Set the "tcl_interactive" variable. + */ + + tty = isatty(0); + char one[2] = "1"; + char zero[2] = "0"; + + Tcl_SetVar(interp, "tcl_interactive", + ((tclStartupScriptFileName == NULL) && tty) ? one : zero, + TCL_GLOBAL_ONLY); + + // + // Load the OpenSeesRT library + // + if (LoadOpenSeesRT(interp) != TCL_OK) { + fprintf(stderr, "Error loading OpenSeesRT library: %s\n", + Tcl_GetStringResult(interp)); + } + + + /* + * If a script file was specified then just source that file + * and quit. + */ + + if (tclStartupScriptFileName != NULL) { + + code = Tcl_EvalFile(interp, tclStartupScriptFileName); + + if (code != TCL_OK) { + errChannel = Tcl_GetStdChannel(TCL_STDERR); + if (errChannel) { + // + // The following statement guarantees that the errorInfo + // variable is set properly. + // + Tcl_AddErrorInfo(interp, ""); + Tcl_WriteObj(errChannel, Tcl_GetVar2Ex(interp, "errorInfo", + NULL, TCL_GLOBAL_ONLY)); + Tcl_WriteChars(errChannel, "\n", 1); + } + exitCode = 1; + } + goto done; + } + + /* + * Process commands from stdin until there's an end-of-file. Note + * that we need to fetch the standard channels again after every + * eval, since they may have been changed. + */ + commandPtr = Tcl_NewObj(); + Tcl_IncrRefCount(commandPtr); + + inChannel = Tcl_GetStdChannel(TCL_STDIN); + outChannel = Tcl_GetStdChannel(TCL_STDOUT); + gotPartial = 0; + + while (true) { + if (tty) { + Tcl_Obj *promptCmdPtr; + + char one[12] = "tcl_prompt1"; + char two[12] = "tcl_prompt2"; + promptCmdPtr = Tcl_GetVar2Ex(interp, + (gotPartial ? one : two), + NULL, TCL_GLOBAL_ONLY); + if (promptCmdPtr == NULL) { + defaultPrompt: + if (!gotPartial && outChannel) { + Tcl_WriteChars(outChannel, "OpenSees > ", 11); + } + } else { + + code = Tcl_EvalObjEx(interp, promptCmdPtr, 0); + + inChannel = Tcl_GetStdChannel(TCL_STDIN); + outChannel = Tcl_GetStdChannel(TCL_STDOUT); + errChannel = Tcl_GetStdChannel(TCL_STDERR); + if (code != TCL_OK) { + if (errChannel) { + Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); + Tcl_WriteChars(errChannel, "\n", 1); + } + Tcl_AddErrorInfo(interp, + "\n (script that generates prompt)"); + goto defaultPrompt; + } + } + if (outChannel) + Tcl_Flush(outChannel); + } + if (!inChannel) + goto done; + + length = Tcl_GetsObj(inChannel, commandPtr); + if (length < 0) + goto done; + + if ((length == 0) && Tcl_Eof(inChannel) && (!gotPartial)) + goto done; + + + /* + * Add the newline removed by Tcl_GetsObj back to the string. + */ + + Tcl_AppendToObj(commandPtr, "\n", 1); + + gotPartial = 0; + code = Tcl_RecordAndEvalObj(interp, commandPtr, 0); + inChannel = Tcl_GetStdChannel(TCL_STDIN); + outChannel = Tcl_GetStdChannel(TCL_STDOUT); + errChannel = Tcl_GetStdChannel(TCL_STDERR); + Tcl_DecrRefCount(commandPtr); + commandPtr = Tcl_NewObj(); + Tcl_IncrRefCount(commandPtr); + if (code != TCL_OK) { + if (errChannel) { + Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); + Tcl_WriteChars(errChannel, "\n", 1); + } + } else if (tty) { + resultPtr = Tcl_GetObjResult(interp); + Tcl_GetStringFromObj(resultPtr, &length); + if ((length > 0) && outChannel) { + Tcl_WriteObj(outChannel, resultPtr); + Tcl_WriteChars(outChannel, "\n", 1); + } + } + } + +done: + + if (commandPtr != NULL) + Tcl_DecrRefCount(commandPtr); + +#if defined(_PARALLEL_PROCESSING) || defined( _PARALLEL_INTERPRETERS) + return; +#endif + + /* + * Rather than calling exit, invoke the "exit" command so that + * users can replace "exit" with some other command to do additional + * cleanup on exit. The Tcl_Eval call should never return. + */ + Tcl_Eval(interp, buffer); + + Tcl_Eval(interp, "quit"); + + return exitCode; +} diff --git a/SRC/runtime/executable/static.cpp b/SRC/runtime/executable/static.cpp new file mode 100644 index 0000000000..89c0c559be --- /dev/null +++ b/SRC/runtime/executable/static.cpp @@ -0,0 +1,303 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +#include +#include +#include + +#ifndef _WIN32 +# include +#endif + +#ifdef USE_TCL_STUBS +#undef USE_TCL_STUBS +#endif + +extern "C" { +#include +#include + #ifdef _TCL85 + #define TclFormatInt(buf, n) sprintf((buf),"%ld", (long)(n)) + #else + EXTERN int TclFormatInt _ANSI_ARGS_((char *buffer, long n)); + #endif + EXTERN int TclObjCommandComplete _ANSI_ARGS_((Tcl_Obj *cmdPtr)); +} + +extern "C" int +#ifdef _WIN32 +__declspec(dllexport) +#endif +Openseesrt_Init(Tcl_Interp *interp); + +# undef TCL_STORAGE_CLASS +# define TCL_STORAGE_CLASS DLLEXPORT + + +/* + * Declarations for various library procedures and variables (don't want + * to include tclPort.h here, because people might copy this file out of + * the Tcl source directory to make their own modified versions). + * Note: "exit" should really be declared here, but there's no way to + * declare it without causing conflicts with other definitions elsewher + * on some systems, so it's better just to leave it out. + */ + +#ifdef _WIN32 +extern "C" int isatty _ANSI_ARGS_((int fd)); +//extern "C" char * strcpy _ANSI_ARGS_((char *dst, CONST char *src)) throw(); +#endif + +static char *tclStartupScriptFileName = NULL; + +void +TclSetStartupScriptFileName(char *fileName) +{ + tclStartupScriptFileName = fileName; +} + +char * +TclGetStartupScriptFileName() +{ + return tclStartupScriptFileName; +} + +/* + *---------------------------------------------------------------------- + * + * Main program for the xara interactive shell. + * + *---------------------------------------------------------------------- + */ + + +int +main(int argc, char **argv) +{ + Tcl_Obj *resultPtr; + Tcl_Obj *commandPtr = NULL; + char buffer[1000], *args; + int code, gotPartial, tty, length; + int exitCode = 0; + Tcl_Channel inChannel, outChannel, errChannel; + Tcl_DString argString; + static bool OPS_showHeader = false; + + Tcl_Interp *interp = Tcl_CreateInterp(); + if (Tcl_InitStubs(interp, "8.5-10", 0) == NULL) { + fprintf(stderr, "Tcl_InitStubs failed: %s\n", Tcl_GetStringResult(interp)); + exit(1); + } + + + if (OPS_showHeader) { + fprintf(stderr,"\n\n"); + fprintf(stderr," OpenSees -- Open System For Earthquake Engineering Simulation\n"); + fprintf(stderr," Pacific Earthquake Engineering Research Center\n"); + + fprintf(stderr," (c) Copyright 1999-2025 The Regents of the University of California\n"); + fprintf(stderr," All Rights Reserved\n"); + fprintf(stderr," (Copyright and Disclaimer @ http://www.berkeley.edu/OpenSees/copyright.html)\n\n\n"); + } + + Tcl_Eval(interp, "rename load import;"); + Tcl_Eval(interp, "interp alias {} load {} import;"); + + +#ifdef TCL_MEM_DEBUG + Tcl_InitMemory(interp); +#endif + + /* + * Make command-line arguments available in the Tcl variables "argc" + * and "argv". If the first argument doesn't start with a "-" then + * strip it off and use it as the name of a script file to process. + */ + tclStartupScriptFileName = argv[1]; + if (tclStartupScriptFileName == NULL) { + if ((argc > 1) && (argv[1][0] != '-')) { + tclStartupScriptFileName = argv[1]; + argc--; + argv++; + } + } + + args = Tcl_Merge(argc-1, argv+1); + Tcl_ExternalToUtfDString(NULL, args, -1, &argString); + Tcl_SetVar(interp, "argv", Tcl_DStringValue(&argString), TCL_GLOBAL_ONLY); + Tcl_DStringFree(&argString); + ckfree(args); + + + if (tclStartupScriptFileName == NULL) { + Tcl_ExternalToUtfDString(NULL, argv[0], -1, &argString); + } else { + tclStartupScriptFileName = Tcl_ExternalToUtfDString(NULL, + tclStartupScriptFileName, -1, &argString); + } + + /* + * Set the "tcl_interactive" variable. + */ + + tty = isatty(0); + char one[2] = "1"; + char zero[2] = "0"; + + Tcl_SetVar(interp, "tcl_interactive", + ((tclStartupScriptFileName == NULL) && tty) ? one : zero, + TCL_GLOBAL_ONLY); + + // + // Load the OpenSeesRT library + // + if (Openseesrt_Init(interp) != TCL_OK) { + fprintf(stderr, "Error loading OpenSeesRT library: %s\n", + Tcl_GetStringResult(interp)); + } + + /* + * If a script file was specified then just source that file + * and quit. + */ + + if (tclStartupScriptFileName != NULL) { + + code = Tcl_EvalFile(interp, tclStartupScriptFileName); + + if (code != TCL_OK) { + errChannel = Tcl_GetStdChannel(TCL_STDERR); + if (errChannel) { + // + // The following statement guarantees that the errorInfo + // variable is set properly. + // + Tcl_AddErrorInfo(interp, ""); + Tcl_WriteObj(errChannel, Tcl_GetVar2Ex(interp, "errorInfo", + NULL, TCL_GLOBAL_ONLY)); + Tcl_WriteChars(errChannel, "\n", 1); + } + exitCode = 1; + } + goto done; + } + /* + * Process commands from stdin until there's an end-of-file. Note + * that we need to fetch the standard channels again after every + * eval, since they may have been changed. + */ + + commandPtr = Tcl_NewObj(); + Tcl_IncrRefCount(commandPtr); + + inChannel = Tcl_GetStdChannel(TCL_STDIN); + outChannel = Tcl_GetStdChannel(TCL_STDOUT); + gotPartial = 0; + + while (true) { + if (tty) { + Tcl_Obj *promptCmdPtr; + + char one[12] = "tcl_prompt1"; + char two[12] = "tcl_prompt2"; + promptCmdPtr = Tcl_GetVar2Ex(interp, + (gotPartial ? one : two), + NULL, TCL_GLOBAL_ONLY); + if (promptCmdPtr == NULL) { + defaultPrompt: + if (!gotPartial && outChannel) { + Tcl_WriteChars(outChannel, "OpenSees > ", 11); + } + } else { + + code = Tcl_EvalObjEx(interp, promptCmdPtr, 0); + + inChannel = Tcl_GetStdChannel(TCL_STDIN); + outChannel = Tcl_GetStdChannel(TCL_STDOUT); + errChannel = Tcl_GetStdChannel(TCL_STDERR); + if (code != TCL_OK) { + if (errChannel) { + Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); + Tcl_WriteChars(errChannel, "\n", 1); + } + Tcl_AddErrorInfo(interp, + "\n (script that generates prompt)"); + goto defaultPrompt; + } + } + if (outChannel) { + Tcl_Flush(outChannel); + } + } + if (!inChannel) { + goto done; + } + length = Tcl_GetsObj(inChannel, commandPtr); + if (length < 0) { + goto done; + } + if ((length == 0) && Tcl_Eof(inChannel) && (!gotPartial)) { + goto done; + } + + /* + * Add the newline removed by Tcl_GetsObj back to the string. + */ + + Tcl_AppendToObj(commandPtr, "\n", 1); + + gotPartial = 0; + code = Tcl_RecordAndEvalObj(interp, commandPtr, 0); + inChannel = Tcl_GetStdChannel(TCL_STDIN); + outChannel = Tcl_GetStdChannel(TCL_STDOUT); + errChannel = Tcl_GetStdChannel(TCL_STDERR); + Tcl_DecrRefCount(commandPtr); + commandPtr = Tcl_NewObj(); + Tcl_IncrRefCount(commandPtr); + if (code != TCL_OK) { + if (errChannel) { + Tcl_WriteObj(errChannel, Tcl_GetObjResult(interp)); + Tcl_WriteChars(errChannel, "\n", 1); + } + } else if (tty) { + resultPtr = Tcl_GetObjResult(interp); + Tcl_GetStringFromObj(resultPtr, &length); + if ((length > 0) && outChannel) { + Tcl_WriteObj(outChannel, resultPtr); + Tcl_WriteChars(outChannel, "\n", 1); + } + } + } + +done: + + if (commandPtr != NULL) + Tcl_DecrRefCount(commandPtr); + +#if defined(_PARALLEL_PROCESSING) || defined( _PARALLEL_INTERPRETERS) + return; +#endif + + /* + * Rather than calling exit, invoke the "exit" command so that + * users can replace "exit" with some other command to do additional + * cleanup on exit. The Tcl_Eval call should never return. + */ + Tcl_Eval(interp, buffer); + + Tcl_Eval(interp, "quit"); + + return exitCode; +} diff --git a/SRC/runtime/logging/AnsiColors.h b/SRC/runtime/logging/AnsiColors.h new file mode 100644 index 0000000000..395a532cd0 --- /dev/null +++ b/SRC/runtime/logging/AnsiColors.h @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//----------------------------------------------------------------------------// +// +// Description: This file defines macros that expand into ANSI escape sequences +// for colored output +// +// References: +// +// ANSI X3.64 (ISO/IEC 6429). +// + +// Regular text +#define BLK "\033[0;30m" +#define RED "\033[0;31m" +#define GRN "\033[0;32m" +#define YEL "\033[0;33m" +#define BLU "\033[0;34m" +#define MAG "\033[0;35m" +#define CYN "\033[0;36m" +#define WHT "\033[0;37m" + +// Regular bold text +#define BBLK "\033[1;30m" +#define BRED "\033[1;31m" +#define BGRN "\033[1;32m" +#define BYEL "\033[1;33m" +#define BBLU "\033[1;34m" +#define BMAG "\033[1;35m" +#define BCYN "\033[1;36m" +#define BWHT "\033[1;37m" + +// Regular underline text +#define UBLK "\033[4;30m" +#define URED "\033[4;31m" +#define UGRN "\033[4;32m" +#define UYEL "\033[4;33m" +#define UBLU "\033[4;34m" +#define UMAG "\033[4;35m" +#define UCYN "\033[4;36m" +#define UWHT "\033[4;37m" + +// Regular background +#define BLKB "\033[40m" +#define REDB "\033[41m" +#define GRNB "\033[42m" +#define YELB "\033[43m" +#define BLUB "\033[44m" +#define MAGB "\033[45m" +#define CYNB "\033[46m" +#define WHTB "\033[47m" + +// High intensty background +#define BLKHB "\033[0;100m" +#define REDHB "\033[0;101m" +#define GRNHB "\033[0;102m" +#define YELHB "\033[0;103m" +#define BLUHB "\033[0;104m" +#define MAGHB "\033[0;105m" +#define CYNHB "\033[0;106m" +#define WHTHB "\033[0;107m" + +// High intensty text +#define HBLK "\033[0;90m" +#define HRED "\033[0;91m" +#define HGRN "\033[0;92m" +#define HYEL "\033[0;93m" +#define HBLU "\033[0;94m" +#define HMAG "\033[0;95m" +#define HCYN "\033[0;96m" +#define HWHT "\033[0;97m" + +// Bold high intensity text +#define BHBLK "\033[1;90m" +#define BHRED "\033[1;91m" +#define BHGRN "\033[1;92m" +#define BHYEL "\033[1;93m" +#define BHBLU "\033[1;94m" +#define BHMAG "\033[1;95m" +#define BHCYN "\033[1;96m" +#define BHWHT "\033[1;97m" + +// Reset +#define COLOR_RESET "\033[0m" + + diff --git a/SRC/runtime/logging/CMakeLists.txt b/SRC/runtime/logging/CMakeLists.txt new file mode 100644 index 0000000000..9ef7beb197 --- /dev/null +++ b/SRC/runtime/logging/CMakeLists.txt @@ -0,0 +1,17 @@ +#===================================================================== +# +# OpenSees -- Open System For Earthquake Engineering Simulation +# Pacific Earthquake Engineering Research Center +# +#===================================================================== + +target_include_directories(OPS_Logging PUBLIC ${CMAKE_CURRENT_LIST_DIR}) + +target_sources(OPS_Logging + PRIVATE + "logging.cpp" + PUBLIC + "Logging.h" + "AnsiColors.h" +) + diff --git a/SRC/runtime/logging/Logging.h b/SRC/runtime/logging/Logging.h new file mode 100644 index 0000000000..bf98f936aa --- /dev/null +++ b/SRC/runtime/logging/Logging.h @@ -0,0 +1,62 @@ +#pragma once +#include +#include + +class OPS_Stream; +namespace OpenSees { + extern OPS_Stream *opserrPtr; + extern OPS_Stream *opslogPtr; + extern OPS_Stream *opswrnPtr; + extern OPS_Stream *opsdbgPtr; +} + + +#define opsdbg (*OpenSees::opsdbgPtr) +#define opswrn ((*OpenSees::opswrnPtr) << G3_WARN_PROMPT) +#define opslog (*OpenSees::opslogPtr) +#ifndef opserr +# define opserr (*OpenSees::opserrPtr) +# define endln "\n" +#endif +#define LOG_TEST ":: " +#define LOG_ITERATE BLU " ITERATE" COLOR_RESET " :: " +#define LOG_FAILURE RED " FAILURE" COLOR_RESET " :: " +#define LOG_SUCCESS GRN " SUCCESS" COLOR_RESET " :: " +#define LOG_CONTINUE "\n " + + + +class G3_Runtime; + +extern const char *G3_WARN_PROMPT; +extern const char *G3_DEBUG_PROMPT; + +namespace OpenSees { +// NOTE: These are defined in logging.cpp + + // maybe change "Prompt" to "Signal" + extern const char * SignalMessageEnd; + extern const char * PromptParseError; + extern const char * PromptValueError; + extern const char * PromptModelError; + extern const char * SignalWarning; + extern const char * PromptAnalysisFailure; + extern const char * PromptAnalysisSuccess; + extern const char * PromptAnalysisIterate; +}; + + +enum G3_Stream { + G3_StdOut, G3_StdIn, G3_StdErr, G3_Null +}; + +enum G3_StreamLevel { + G3_LevelError, + G3_LevelDebug, + G3_LevelLog, + G3_LevelWarn +}; + +int G3_SetStreamColor(G3_Runtime* rt, int strm, int flag); +int G3_SetStreamLevel(int stream, bool on); + diff --git a/SRC/runtime/logging/logging.cpp b/SRC/runtime/logging/logging.cpp new file mode 100644 index 0000000000..96008c332b --- /dev/null +++ b/SRC/runtime/logging/logging.cpp @@ -0,0 +1,108 @@ +#include +#include +#include +class G3_Runtime; + + +#include +#include +#include + + +#include "Logging.h" + + +namespace OpenSees { + +StandardStream sserr; +DummyStream ssnul; +OPS_Stream *opserrPtr = &sserr; +OPS_Stream *opsdbgPtr = &ssnul; +OPS_Stream *opslogPtr = &ssnul; +OPS_Stream *opswrnPtr = &sserr; + +namespace Internal { + const char * WarnPromptColor = RED "WARNING " COLOR_RESET; + const char * WarnPromptNoColor = "WARNING "; + + const char * ErrorPromptColor = BRED "ERROR " COLOR_RESET; + const char * ErrorPromptNoColor = "ERROR "; + + const char * DebugPromptColor = GRN "DEBUG " COLOR_RESET; + const char * DebugPromptNoColor = "DEBUG "; + + const char * AnalysisIterateColor = BLU " ITERATE" COLOR_RESET " :: "; + const char * AnalysisIterateNoColor = " ITERATE" " :: "; + + const char * AnalysisFailureColor = RED " FAILURE" COLOR_RESET " :: "; + const char * AnalysisFailureNoColor = " FAILURE" " :: "; + + const char * AnalysisSuccessColor = GRN " SUCCESS" COLOR_RESET " :: "; + const char * AnalysisSuccessNoColor = " SUCCESS" " :: "; + +} // namespace OpenSees::Internal + + // Default to no color + const char * SignalMessageEnd = "\n"; + const char * PromptParseError = Internal::ErrorPromptNoColor; + const char * PromptValueError = PromptParseError; + const char * PromptModelError = PromptParseError; + const char * SignalWarning = Internal::WarnPromptNoColor; + + const char * PromptDomainFailure = Internal::AnalysisFailureNoColor; + const char * PromptAnalysisFailure = Internal::AnalysisFailureNoColor; + const char * PromptAnalysisSuccess = Internal::AnalysisSuccessNoColor; + const char * PromptAnalysisIterate = Internal::AnalysisIterateNoColor; + +} // namespace OpenSees + +const char * G3_WARN_PROMPT = OpenSees::Internal::WarnPromptNoColor; +const char * G3_ERROR_PROMPT = OpenSees::Internal::ErrorPromptNoColor; +const char * G3_DEBUG_PROMPT = OpenSees::Internal::DebugPromptNoColor; + +int +G3_SetStreamLevel(int stream, bool on) +{ + + OPS_Stream **theStream; + switch (stream) { + case G3_LevelError: theStream = &OpenSees::opserrPtr; break; + case G3_LevelDebug: theStream = &OpenSees::opsdbgPtr; break; + case G3_LevelWarn : theStream = &OpenSees::opswrnPtr; break; + default: + return -1; + } + + if (on) { + *theStream = &OpenSees::sserr; + } else { + *theStream = &OpenSees::ssnul; + } + return 0; +} + +int G3_SetStreamColor(G3_Runtime* rt, int strm, int flag) +{ + if (flag == 1) { + G3_WARN_PROMPT = OpenSees::Internal::WarnPromptColor; + OpenSees::SignalWarning = OpenSees::Internal::WarnPromptColor; + G3_DEBUG_PROMPT = OpenSees::Internal::DebugPromptColor; + OpenSees::PromptParseError = OpenSees::Internal::ErrorPromptColor; + OpenSees::PromptValueError = OpenSees::Internal::ErrorPromptColor; + OpenSees::PromptModelError = OpenSees::Internal::ErrorPromptColor; + OpenSees::PromptAnalysisFailure = OpenSees::Internal::AnalysisFailureColor; + OpenSees::PromptAnalysisSuccess = OpenSees::Internal::AnalysisSuccessColor; + OpenSees::PromptAnalysisIterate = OpenSees::Internal::AnalysisIterateColor; + + } else if (flag == 0) { + G3_WARN_PROMPT = OpenSees::Internal::WarnPromptNoColor; + OpenSees::SignalWarning = OpenSees::Internal::WarnPromptNoColor; + G3_DEBUG_PROMPT = OpenSees::Internal::DebugPromptNoColor; + OpenSees::PromptParseError = OpenSees::Internal::ErrorPromptNoColor; + OpenSees::PromptAnalysisFailure = OpenSees::Internal::AnalysisFailureNoColor; + OpenSees::PromptAnalysisSuccess = OpenSees::Internal::AnalysisSuccessNoColor; + OpenSees::PromptAnalysisIterate = OpenSees::Internal::AnalysisIterateNoColor; + } + + return 0; +} diff --git a/SRC/runtime/parsing/ArgumentTracker.h b/SRC/runtime/parsing/ArgumentTracker.h index e84ab557c9..1d8b3e3b88 100644 --- a/SRC/runtime/parsing/ArgumentTracker.h +++ b/SRC/runtime/parsing/ArgumentTracker.h @@ -1,7 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation -// This file is not yet licensed. +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // diff --git a/SRC/runtime/parsing/CMakeLists.txt b/SRC/runtime/parsing/CMakeLists.txt new file mode 100644 index 0000000000..98e15ab310 --- /dev/null +++ b/SRC/runtime/parsing/CMakeLists.txt @@ -0,0 +1,9 @@ +#============================================================================== +# +# OpenSees -- Open System For Earthquake Engineering Simulation +# Pacific Earthquake Engineering Research Center +# +#============================================================================== + +target_sources(OPS_Runtime PRIVATE InterpreterAPI.cpp) + diff --git a/SRC/runtime/parsing/InputAPI.h b/SRC/runtime/parsing/InputAPI.h index 0b4a288c64..9e1931adc1 100644 --- a/SRC/runtime/parsing/InputAPI.h +++ b/SRC/runtime/parsing/InputAPI.h @@ -1,10 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// #ifndef G3PARSE_H #define G3PARSE_H #ifndef G3_RUNTIME_H #include #define G3_RUNTIME_H #endif - +#include #define G3_Char TCL_Char diff --git a/SRC/runtime/parsing/InterpreterAPI.cpp b/SRC/runtime/parsing/InterpreterAPI.cpp index c1518c986c..40c8842779 100644 --- a/SRC/runtime/parsing/InterpreterAPI.cpp +++ b/SRC/runtime/parsing/InterpreterAPI.cpp @@ -1,9 +1,17 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// // #include #include @@ -11,12 +19,10 @@ #include #include #include -#include +#include #include #include -#include -#include -#include +#include #include #include @@ -26,10 +32,10 @@ #include #include -#include -#include #include +#include +#include static Tcl_Interp *theInterp = nullptr; static TCL_Char **currentArgv = nullptr; @@ -75,24 +81,11 @@ OPS_ResetCurrentInputArg(int cArg) } -// extern "C" -#if 0 -int -OPS_ResetInput(ClientData clientData, Tcl_Interp *interp, int cArg, int mArg, - TCL_Char ** const argv, void*, void*) -{ - currentArgv = argv; - currentArg = cArg; - maxArg = mArg; - return 0; -} -#endif - - extern "C" int OPS_ResetInputNoBuilder(ClientData clientData, Tcl_Interp *interp, int cArg, int mArg, TCL_Char ** const argv, Domain *domain) { + theInterp = interp; currentArgv = argv; currentArg = cArg; maxArg = mArg; @@ -175,31 +168,31 @@ OPS_GetStringCopy(char **arrayData) extern "C" int OPS_GetDoubleListInput(int* size, Vector* data) { - TCL_Char** strings; + TCL_Char** strings; - if (Tcl_SplitList(theInterp, currentArgv[currentArg], - size, &strings) != TCL_OK) { - opserr << "ERROR problem splitting list " << currentArgv[currentArg] << " \n"; - return -1; - } + if (Tcl_SplitList(theInterp, currentArgv[currentArg], + size, &strings) != TCL_OK) { + opserr << "ERROR problem splitting list " << currentArgv[currentArg] << " \n"; + return -1; + } - data->resize(*size); - for (int i = 0; i < *size; i++) { - double value; - if (Tcl_GetDouble(theInterp, strings[i], &value) != TCL_OK) { - opserr << "ERROR problem reading data value " << strings[i] << " \n"; - // free up the array of strings .. see tcl man pages as to why - Tcl_Free((char*)strings); - return -1; - } - (*data)(i) = value; - } - // free up the array of strings .. see tcl man pages as to why - Tcl_Free((char*)strings); + data->resize(*size); + for (int i = 0; i < *size; i++) { + double value; + if (Tcl_GetDouble(theInterp, strings[i], &value) != TCL_OK) { + opserr << "ERROR problem reading data value " << strings[i] << " \n"; + // free up the array of strings .. see tcl man pages as to why + Tcl_Free((char*)strings); + return -1; + } + (*data)(i) = value; + } + // free up the array of strings .. see tcl man pages as to why + Tcl_Free((char*)strings); - currentArg++; + currentArg++; - return 0; + return 0; } extern "C" @@ -309,7 +302,7 @@ G3_setModelBuilder(G3_Runtime *rt, BasicModelBuilder* builder) { theModelBuilder = builder; rt->m_builder = builder; - return 1; + return 0; } BasicModelBuilder * @@ -346,13 +339,10 @@ TimeSeries *G3_getTimeSeries(G3_Runtime *rt, int tag) BasicModelBuilder *builder = G3_getSafeBuilder(rt); if (builder) { series = builder->getTypedObject(tag); - // TODO -#if 1 if (series) return series->getCopy(); else return nullptr; -#endif } else { return nullptr; } @@ -376,7 +366,10 @@ G3_getSectionForceDeformation(G3_Runtime* rt, int tag) { BasicModelBuilder* builder = G3_getSafeBuilder(rt); assert(builder); - SectionForceDeformation* theSection = builder->getTypedObject(tag); + SectionForceDeformation* theSection = nullptr; + + if (builder->getNDM() == 3) + theSection = builder->getTypedObject(tag); if (theSection != nullptr) return theSection; @@ -393,7 +386,8 @@ G3_getUniaxialMaterialInstance(G3_Runtime *rt, int tag) return builder->getTypedObject(tag); } -int G3_addUniaxialMaterial(G3_Runtime *rt, UniaxialMaterial *mat) { +int +G3_addUniaxialMaterial(G3_Runtime *rt, UniaxialMaterial *mat) { BasicModelBuilder* builder = G3_getSafeBuilder(rt); assert(builder != nullptr); assert(mat != nullptr); @@ -444,106 +438,52 @@ OPS_GetFEDatastore() {return theDatabase;} const char * OPS_GetInterpPWD() {return getInterpPWD(theInterp);} -#if 0 -EquiSolnAlgo ** -OPS_GetAlgorithm(void) {return &theAlgorithm;} - -EigenSOE ** -OPS_GetEigenSOE(void) {return &theEigenSOE;} - -LinearSOE ** -OPS_GetSOE(void) {return &theSOE;} -StaticAnalysis ** -OPS_GetStaticAnalysis(void) {return &theStaticAnalysis;} -#endif - -#if 0 && !defined(OPS_USE_RUNTIME) - -modelState theModelState; - -UniaxialMaterial * -OPS_GetUniaxialMaterial(int matTag) -{ - return OPS_getUniaxialMaterial(matTag); -} - -Domain * -OPS_GetDomain(void) {return theDomain;} - -AnalysisModel ** -OPS_GetAnalysisModel(void){return &theAnalysisModel;} - -CrdTransf * -OPS_GetCrdTransf(int crdTag) {return OPS_getCrdTransf(crdTag);} - -StaticIntegrator ** -OPS_GetStaticIntegrator(void) {return &theStaticIntegrator;} - -TransientIntegrator ** -OPS_GetTransientIntegrator(void) {return &theTransientIntegrator;} - -DirectIntegrationAnalysis ** -OPS_GetTransientAnalysis(void) {return &theTransientAnalysis;} - -ConvergenceTest ** -OPS_GetTest(void) {return &theTest;} - -ConstraintHandler ** -OPS_GetHandler(void) {return &theHandler;} - -DOF_Numberer ** -OPS_GetNumberer(void) {return &theGlobalNumberer;} - -extern "C" int -OPS_InvokeMaterialDirectly2(matObject *theMat, modelState *model, - double *strain, double *stress, double *tang, - int *isw) -{ - int error = 0; - if (theMat != nullptr) - theMat->matFunctPtr(theMat, model, strain, tang, stress, isw, &error); - else - error = -1; - - return error; -} -static void -OPS_InvokeMaterialObject(struct matObject *theMat, modelState *theModel, - double *strain, double *tang, double *stress, int *isw, - int *result) -{ - int matType = (int)theMat->theParam[0]; - - if (matType == 1) { - // UniaxialMaterial *theMaterial = theUniaxialMaterials[matCount]; - UniaxialMaterial *theMaterial = (UniaxialMaterial *)theMat->matObjectPtr; - if (theMaterial == 0) { - *result = -1; - return; - } - - if (*isw == ISW_COMMIT) { - *result = theMaterial->commitState(); - return; - } else if (*isw == ISW_REVERT) { - *result = theMaterial->revertToLastCommit(); - return; - } else if (*isw == ISW_REVERT_TO_START) { - *result = theMaterial->revertToStart(); - return; - } else if (*isw == ISW_FORM_TANG_AND_RESID) { - double matStress = 0.0; - double matTangent = 0.0; - int res = theMaterial->setTrial(strain[0], matStress, matTangent); - stress[0] = matStress; - tang[0] = matTangent; - *result = res; - return; +namespace OpenSees { + namespace Parsing { + + int + GetDoubleParam(Tcl_Interp *interp, Domain& domain, const char* arg, double* value, Parameter* ¶m) + { + if (Tcl_GetDouble(interp, arg, value) == TCL_OK) + return TCL_OK; + + // something like "parameter tag value" + int tag, argc; + const char **argv; + if (Tcl_SplitList(interp, arg, &argc, &argv) != TCL_OK) + return TCL_ERROR; + + if (argc != 3) { + Tcl_Free((char*)argv); + return TCL_ERROR; + } + + if (strcmp(argv[0], "Parameter") != 0) { + Tcl_Free((char*)argv); + return TCL_ERROR; + } + + if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { + Tcl_Free((char*)argv); + return TCL_ERROR; + } + + if (Tcl_GetDouble(interp, argv[2], value) != TCL_OK) { + Tcl_Free((char*)argv); + return TCL_ERROR; + } + + Tcl_Free((char*)argv); + + param = domain.getParameter(tag); + + if (param == nullptr) { + opserr << OpenSees::PromptValueError << "parameter with tag " << tag << " not found\n"; + return TCL_ERROR; + } + + return TCL_OK; } } - - return; -} - -#endif +} \ No newline at end of file diff --git a/SRC/runtime/parsing/Parsing.h b/SRC/runtime/parsing/Parsing.h index 39d087e826..88f59106e1 100644 --- a/SRC/runtime/parsing/Parsing.h +++ b/SRC/runtime/parsing/Parsing.h @@ -1,15 +1,38 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +#pragma once +#include #ifndef TCL_Char typedef const char TCL_Char; #endif #ifndef G3_Char -// #define G3_Char const char typedef const char G3_Char; #endif #include "InputAPI.h" + +// As suggested by https://core.tcl-lang.org/tcl/wiki?name=Migrating+C+extensions+to+Tcl+9 +#ifndef TCL_SIZE_MAX +typedef int Tcl_Size; +#define TCL_SIZE_MAX INT_MAX +#endif + +class Parameter; +namespace OpenSees { +namespace Parsing { +int +GetDoubleParam(Tcl_Interp *, Domain& , const char* arg, double* value, Parameter*&); +} +} \ No newline at end of file diff --git a/SRC/runtime/python/OpenSeesPyRT.cpp b/SRC/runtime/python/OpenSeesPyRT.cpp index 2050406330..c351fa5c97 100644 --- a/SRC/runtime/python/OpenSeesPyRT.cpp +++ b/SRC/runtime/python/OpenSeesPyRT.cpp @@ -1,9 +1,10 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara // //===----------------------------------------------------------------------===// -// +// https://xara.so +//===----------------------------------------------------------------------===// // Author: cmp // #include @@ -29,9 +30,6 @@ namespace py = pybind11; // // ANALYSIS // -#include -#include -#include #include #include @@ -45,16 +43,6 @@ namespace py = pybind11; #define ARRAY_FLAGS py::array::c_style|py::array::forcecast -#if 0 -std::unique_ptr -getRuntime(py::object interpaddr) { - void *interp_addr; - interp_addr = (void*)PyLong_AsVoidPtr(interpaddr.ptr()); - return std::unique_ptr(G3_getRuntime((Tcl_Interp*)interp_addr)); -} // , py::return_value_policy::reference -#endif - - std::unique_ptr get_builder(py::object interpaddr) { void *interp_addr; @@ -507,21 +495,6 @@ init_obj_module(py::module &m) py::class_(m, "_Runtime") ; - py::class_(m, "_StaticAnalysis") - .def (py::init([](G3_Runtime *runtime, G3_Config conf) { - return *((StaticAnalysis*)runtime->newStaticAnalysis(conf)); - })) - .def ("analyze", &StaticAnalysis::analyze) - ; - - py::class_(m, "_DirectIntegrationAnalysis") - .def (py::init([](G3_Runtime *runtime, G3_Config conf) { - return *((DirectIntegrationAnalysis*)runtime->newTransientAnalysis(conf)); - })) - .def ("analyze", &DirectIntegrationAnalysis::analyze) - ; - // // Module-Level Functions // diff --git a/SRC/runtime/runtime/BasicAnalysisBuilder.cpp b/SRC/runtime/runtime/BasicAnalysisBuilder.cpp index 50038a815e..59c8703adc 100644 --- a/SRC/runtime/runtime/BasicAnalysisBuilder.cpp +++ b/SRC/runtime/runtime/BasicAnalysisBuilder.cpp @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -9,23 +18,22 @@ #include #include #include - +#include "BasicModelBuilder.h" #include "BasicAnalysisBuilder.h" #include -#include +#include // Abstract classes #include #include #include #include -#include -#include -#include +#include #include #include #include #include #include +#include // For eigen() #include @@ -52,29 +60,32 @@ #include -static std::unordered_map SolveFailedMessage { +static std::unordered_map AnalyzeFailedMessage { {SolutionAlgorithm::BadFormResidual, "Failed to form residual\n"}, {SolutionAlgorithm::BadFormTangent, "Failed to form tangent\n"}, {SolutionAlgorithm::BadLinearSolve, "Failed to solve system, tangent may be singular\n"}, // {SolutionAlgorithm::TestFailed, ""},// no output; information will have been printed by the test {SolutionAlgorithm::BadTestStart, "Failed to initialize the convergence test\n"}, + {SolutionAlgorithm::BadStepUpdate, "Failed to update the model\n"} }; -BasicAnalysisBuilder::BasicAnalysisBuilder(Domain* domain) +BasicAnalysisBuilder::BasicAnalysisBuilder(BasicModelBuilder& context) : - theDomain(domain), + context(context), + theDomain(context.getDomain()), theHandler(nullptr), theNumberer(nullptr), + theAnalysisModel(new AnalysisModel()), theAlgorithm(nullptr), theSOE(nullptr), theEigenSOE(nullptr), theStaticIntegrator(nullptr), theTransientIntegrator(nullptr), theTest(nullptr), - theVariableTimeStepTransientAnalysis(nullptr), - CurrentAnalysisFlag(EMPTY_ANALYSIS) + CurrentAnalysisFlag(EMPTY_ANALYSIS), + domainStamp(0) { - theAnalysisModel = new AnalysisModel(); + } BasicAnalysisBuilder::~BasicAnalysisBuilder() @@ -100,16 +111,16 @@ BasicAnalysisBuilder::wipe() theStaticIntegrator = nullptr; } if ((theTransientIntegrator != nullptr) && freeTI) { - delete theTransientIntegrator; - theTransientIntegrator = nullptr; + delete theTransientIntegrator; + theTransientIntegrator = nullptr; } if ((theSOE != nullptr) && freeSOE) { - delete theSOE; - theSOE = nullptr; + delete theSOE; + theSOE = nullptr; } if (theNumberer != nullptr) { - delete theNumberer; - theNumberer = nullptr; + delete theNumberer; + theNumberer = nullptr; } if (theHandler != nullptr) { delete theHandler; @@ -127,14 +138,14 @@ BasicAnalysisBuilder::wipe() delete theAnalysisModel; theAnalysisModel = new AnalysisModel(); } - theVariableTimeStepTransientAnalysis = nullptr; } + void BasicAnalysisBuilder::setLinks(CurrentAnalysis flag) { - if (theSOE && theAnalysisModel) - theSOE->setLinks(*theAnalysisModel); + // if (theSOE && theAnalysisModel) + // theSOE->setLinks(*theAnalysisModel); if (theDomain && theHandler && theAnalysisModel) theAnalysisModel->setLinks(*theDomain, *theHandler); @@ -147,51 +158,51 @@ BasicAnalysisBuilder::setLinks(CurrentAnalysis flag) switch (flag) { - case EMPTY_ANALYSIS: - break; + case EMPTY_ANALYSIS: + break; - case TRANSIENT_ANALYSIS: - if (theDomain && theAnalysisModel && theTransientIntegrator && theHandler) - theHandler->setLinks(*theDomain, *theAnalysisModel, *theTransientIntegrator); + case TRANSIENT_ANALYSIS: + if (theDomain && theAnalysisModel && theTransientIntegrator && theHandler) + theHandler->setLinks(*theDomain, *theAnalysisModel); - if (theAnalysisModel && theTransientIntegrator && theSOE && theTest && theAlgorithm) - theAlgorithm->setLinks(*theAnalysisModel, *theTransientIntegrator, *theSOE, theTest); + if (theTransientIntegrator && theSOE && theTest && theAlgorithm) + theAlgorithm->setLinks(*theTransientIntegrator, *theSOE, theTest); - if (theAnalysisModel && theSOE && theTest && theTransientIntegrator) { - theTransientIntegrator->setLinks(*theAnalysisModel, *theSOE, theTest); - } - // if (theTransientIntegrator && domainStamp != 0) - // theTransientIntegrator->domainChanged(); - // this->domainChanged(); + if (theAnalysisModel && theSOE && theTest && theTransientIntegrator) { + theTransientIntegrator->setLinks(*theAnalysisModel, *theSOE, theTest); + } + // if (theTransientIntegrator && domainStamp != 0) + // theTransientIntegrator->domainChanged(); + // this->domainChanged(); - // domainStamp = 0; - break; + // domainStamp = 0; + break; - case STATIC_ANALYSIS: - // opserr << "setLinks(STATIC)\n"; - if (theDomain && theAnalysisModel && theStaticIntegrator && theHandler) - theHandler->setLinks(*theDomain, *theAnalysisModel, *theStaticIntegrator); + case STATIC_ANALYSIS: + if (theDomain && theAnalysisModel && theStaticIntegrator && theHandler) + theHandler->setLinks(*theDomain, *theAnalysisModel); - if (theAnalysisModel && theSOE && theTest && theStaticIntegrator) - theStaticIntegrator->setLinks(*theAnalysisModel, *theSOE, theTest); + if (theAnalysisModel && theSOE && theTest && theStaticIntegrator) + theStaticIntegrator->setLinks(*theAnalysisModel, *theSOE, theTest); - if (theAnalysisModel && theStaticIntegrator && theSOE && theTest && theAlgorithm) - theAlgorithm->setLinks(*theAnalysisModel, *theStaticIntegrator, *theSOE, theTest); + if (theStaticIntegrator && theSOE && theTest && theAlgorithm) + theAlgorithm->setLinks(*theStaticIntegrator, *theSOE, theTest); - // domainStamp = 0; - break; + // domainStamp = 0; + break; } } int -BasicAnalysisBuilder::initialize(void) +BasicAnalysisBuilder::initialize() { // check if domain has undergone change int stamp = theDomain->hasDomainChanged(); if (stamp != domainStamp) { domainStamp = stamp; if (this->domainChanged() < 0) { - opserr << G3_ERROR_PROMPT << "initialize - domainChanged() failed\n"; + opserr << OpenSees::PromptValueError + << "initialize - domainChanged() failed\n"; return -1; } } @@ -202,17 +213,17 @@ BasicAnalysisBuilder::initialize(void) case STATIC_ANALYSIS: if (theStaticIntegrator->initialize() < 0) { - opserr << G3_WARN_PROMPT << "integrator initialize() failed\n"; - return -2; - } else + return -2; + } + else theStaticIntegrator->commit(); break; case TRANSIENT_ANALYSIS: if (theTransientIntegrator->initialize() < 0) { - opserr << "integrator initialize() failed\n"; - return -2; - } else + return -2; + } + else theTransientIntegrator->commit(); break; } @@ -222,7 +233,7 @@ BasicAnalysisBuilder::initialize(void) } int -BasicAnalysisBuilder::domainChanged(void) +BasicAnalysisBuilder::domainChanged() { Domain *domain = this->getDomain(); int stamp = domain->hasDomainChanged(); @@ -230,17 +241,18 @@ BasicAnalysisBuilder::domainChanged(void) opsdbg << G3_DEBUG_PROMPT << "Domain changed\n"; + theAnalysisModel->clearAll(); if (theHandler != nullptr) { theHandler->clearAll(); - // Invoke handle() on the constraint handler which - // causes the creation of FE_Element and DOF_Group objects - // and their addition to the AnalysisModel. + // Create FE_Element and DOF_Group objects + // and add to the AnalysisModel. if (theHandler->handle() < 0) { opserr << "BasicAnalysisBuilder::domainChange() - ConstraintHandler::handle() failed\n"; return -1; } + // Invoke number() on the numberer which causes // equation numbers to be assigned to all the DOFs in the // AnalysisModel. @@ -261,7 +273,7 @@ BasicAnalysisBuilder::domainChanged(void) if (theSOE != nullptr) { if (theSOE->setSize(theGraph) < 0) { - opserr << "BasicAnalysisBuilder::domainChange() - LinearSOE::setSize() failed\n"; + opserr << "BasicAnalysisBuilder::domainChange - LinearSOE::setSize() failed\n"; return -3; } } @@ -275,26 +287,25 @@ BasicAnalysisBuilder::domainChanged(void) theAnalysisModel->clearDOFGraph(); - // finally we invoke domainChanged on the Integrator and Algorithm - // objects .. informing them that the model has changed + // finally invoke domainChanged on the Integrator and Algorithm + // informing them that the model has changed switch (this->CurrentAnalysisFlag) { + case STATIC_ANALYSIS: + if (theStaticIntegrator->domainChanged() < 0) { + opserr << "BasicAnalysisBuilder::domainChange - Integrator::domainChanged() failed\n"; + return -4; + } + break; - case STATIC_ANALYSIS: - if (theStaticIntegrator->domainChanged() < 0) { - opserr << "BasicAnalysisBuilder::domainChange - Integrator::domainChanged() failed\n"; - return -4; - } - break; - - case TRANSIENT_ANALYSIS: + case TRANSIENT_ANALYSIS: - if (theTransientIntegrator->domainChanged() < 0) { - opserr << "BasicAnalysisBuilder::domainChange - Integrator::domainChanged() failed\n"; - return -4; - } - break; - default: - break; + if (theTransientIntegrator->domainChanged() < 0) { + opserr << "BasicAnalysisBuilder: Integrator failed in domainChanged()\n"; + return -4; + } + break; + default: + break; } // if (theAlgorithm && theAlgorithm->domainChanged() < 0) { @@ -306,80 +317,101 @@ BasicAnalysisBuilder::domainChanged(void) } int -BasicAnalysisBuilder::analyze(int num_steps, double size_steps) +BasicAnalysisBuilder::analyze(int num_steps, double size_steps, int flag) { - + int status = -1; switch (this->CurrentAnalysisFlag) { case STATIC_ANALYSIS: - return this->analyzeStatic(num_steps); + status = this->analyzeStatic(num_steps, flag); break; case TRANSIENT_ANALYSIS: { - // TODO: Set global timestep variable + // TODO: Need to remove global timestep variable; ops_Dt = size_steps; - return this->analyzeTransient(num_steps, size_steps); + status = this->analyzeTransient(num_steps, size_steps); break; } default: - opserr << G3_ERROR_PROMPT << "No Analysis type has been specified \n"; + opserr << OpenSees::PromptValueError << "No Analysis type has been specified \n"; return -1; } + + // TODO: This should be done when exact compatibility with upstream is needed; + // add an environment variable or flag to control it. + // theDomain->flushRecorders(); + return status; } int -BasicAnalysisBuilder::analyzeStatic(int numSteps) +BasicAnalysisBuilder::analyzeStatic(int numSteps, int flag) { int result = 0; for (int i=0; ianalysisStep(0.0); + if (result < 0) { + opserr << "The AnalysisModel failed\n"; + opserr << " at step: " << i << " with domain at load factor "; + opserr << theDomain->getCurrentTime() << "\n"; + theDomain->revertToLastCommit(); + return -2; + } - result = theAnalysisModel->analysisStep(); + // Check for change in Domain since last step. As a change can + // occur in a commit() in a domain decomp with load balancing + // this must now be inside the loop + int stamp = theDomain->hasDomainChanged(); + if (stamp != domainStamp) { + domainStamp = stamp; + result = this->domainChanged(); if (result < 0) { - opserr << "StaticAnalysis::analyze - the AnalysisModel failed\n"; - opserr << " at step: " << i << " with domain at load factor "; - opserr << theDomain->getCurrentTime() << "\n"; - theDomain->revertToLastCommit(); - return -2; - } - - // Check for change in Domain since last step. As a change can - // occur in a commit() in a domaindecomp with load balancing - // this must now be inside the loop - int stamp = theDomain->hasDomainChanged(); - - if (stamp != domainStamp) { - domainStamp = stamp; - result = this->domainChanged(); - if (result < 0) { - opserr << "domainChanged failed"; - opserr << " at step " << i << " of " << numSteps << "\n"; - return -1; - } + opserr << "domainChanged failed"; + opserr << " at step " << i << " of " << numSteps << "\n"; + return -1; } + } + if (flag & Increment) { result = theStaticIntegrator->newStep(); if (result < 0) { opserr << "The Integrator failed at step: " << i - << " with domain at load factor " << theDomain->getCurrentTime() << "\n"; + << " with domain at load factor " << theDomain->getCurrentTime() << "\n"; theDomain->revertToLastCommit(); theStaticIntegrator->revertToLastStep(); return -2; } + } + if (flag & Iterate) { result = theAlgorithm->solveCurrentStep(); if (result < 0) { // Print error message if we have one - if (SolveFailedMessage.find(result) != SolveFailedMessage.end()) { - opserr << OpenSees::PromptAnalysisFailure << SolveFailedMessage[result]; + if (AnalyzeFailedMessage.find(result) != AnalyzeFailedMessage.end()) { + opserr << OpenSees::PromptAnalysisFailure << AnalyzeFailedMessage[result]; } theDomain->revertToLastCommit(); theStaticIntegrator->revertToLastStep(); return -3; } + } + if (theStaticIntegrator->shouldComputeAtEachStep()) { + result = theStaticIntegrator->computeSensitivities(); + if (result < 0) { + opserr << "StaticAnalysis::analyze() - the SensitivityAlgorithm failed"; + opserr << " at step: " << i << " with domain at load factor "; + opserr << theDomain->getCurrentTime() << "\n"; + theDomain->revertToLastCommit(); + theStaticIntegrator->revertToLastStep(); + return -5; + } + } + + if (flag & Commit) { result = theStaticIntegrator->commit(); if (result < 0) { opserr << "StaticAnalysis::analyze - "; @@ -391,11 +423,14 @@ BasicAnalysisBuilder::analyzeStatic(int numSteps) theStaticIntegrator->revertToLastStep(); return -4; } + } } return 0; } + + int BasicAnalysisBuilder::analyzeTransient(int numSteps, double dT) { @@ -437,6 +472,7 @@ BasicAnalysisBuilder::analyzeSubLevel(int level, double dT) return result; } + // analyze a transient step int BasicAnalysisBuilder::analyzeStep(double dT) @@ -469,14 +505,24 @@ BasicAnalysisBuilder::analyzeStep(double dT) result = theAlgorithm->solveCurrentStep(); if (result < 0) { - if (SolveFailedMessage.find(result) != SolveFailedMessage.end()) { - opserr << OpenSees::PromptAnalysisFailure << SolveFailedMessage[result]; + if (AnalyzeFailedMessage.find(result) != AnalyzeFailedMessage.end()) { + opserr << OpenSees::PromptAnalysisFailure << AnalyzeFailedMessage[result]; } theDomain->revertToLastCommit(); theTransientIntegrator->revertToLastStep(); return -3; } + if (theTransientIntegrator->shouldComputeAtEachStep()) { + result = theTransientIntegrator->computeSensitivities(); + if (result < 0) { + opserr << "TransientAnalysis::analyze() - the SensitivityAlgorithm failed"; + opserr << " at time " << theDomain->getCurrentTime() << "\n"; + theDomain->revertToLastCommit(); + theTransientIntegrator->revertToLastStep(); + return -5; + } + } result = theTransientIntegrator->commit(); if (result < 0) { @@ -492,6 +538,121 @@ BasicAnalysisBuilder::analyzeStep(double dT) } +static double +determineDt(double dT, + double dtMin, + double dtMax, + int Jd, + ConvergenceTest *theTest) +{ + double newDt = dT; + + // get the number of trial steps in the last solveCurrentStep() + double numLastIter = 1.0; + if (theTest != 0) + numLastIter = theTest->getNumTests(); + + + // determine new dT based on last dT and Jd and #iter of last step + double factor = Jd/numLastIter; + newDt *= factor; + + // ensure: dtMin <~~ dT <= dtMax + if (newDt < dtMin) + newDt = dtMin - DBL_EPSILON; // to ensure we get out of the analysis + // loop if can't converge on next step + else if (newDt > dtMax) + newDt = dtMax; + + return newDt; +} + + +int +BasicAnalysisBuilder::analyzeVariable(int numSteps, double dT, double dtMin, double dtMax, int Jd) +{ + + // set some variables + int result = 0; + double totalTimeIncr = numSteps * dT; + double currentTimeIncr = 0.0; + double currentDt = dT; + + // loop until analysis has performed the total time incr requested + while (currentTimeIncr < totalTimeIncr) { + + if (theAnalysisModel->analysisStep(currentDt) < 0) { + opserr << "DirectIntegrationAnalysis::analyze() - the AnalysisModel failed in newStepDomain"; + opserr << " at time " << theDomain->getCurrentTime() << "\n"; + theDomain->revertToLastCommit(); + return -2; + } + + // check if domain has undergone change + int stamp = theDomain->hasDomainChanged(); + if (stamp != domainStamp) { + domainStamp = stamp; + if (this->domainChanged() < 0) { + opserr << "DirectIntegrationAnalysis::analyze() - domainChanged() failed\n"; + return -1; + } + } + + // + // do newStep(), solveCurrentStep() and commit() as in regular + // DirectINtegrationAnalysis - difference is we do not return + // if a failure - we stop the analysis & resize time step if failure + // + + if (theTransientIntegrator->newStep(currentDt) < 0) { + result = -2; + } + + + if (result >= 0) { + result = theAlgorithm->solveCurrentStep(); + if (result < 0) + result = -3; + } + + if (result >= 0) { + result = theTransientIntegrator->commit(); + if (result < 0) + result = -4; + } + + // if the time step was successful increment delta T for the analysis + // otherwise revert the Domain to last committed state & see if can go on + + if (result >= 0) + currentTimeIncr += currentDt; + + else { + + // invoke the revertToLastCommit + theDomain->revertToLastCommit(); + theTransientIntegrator->revertToLastStep(); + + // if last dT was <= min specified the analysis FAILS - return FAILURE + if (currentDt <= dtMin) { + opserr << "VariableTimeStepDirectIntegrationAnalysis::analyze() - "; + opserr << " failed at time " << theDomain->getCurrentTime() << endln; + return result; + } + + + // if still here reset result for next loop + result = 0; + } + + // now we determine a new delta T for next loop + currentDt = determineDt(currentDt, dtMin, dtMax, Jd, theTest); + } + + + return 0; +} + void BasicAnalysisBuilder::set(ConstraintHandler* obj) @@ -550,7 +711,6 @@ BasicAnalysisBuilder::set(LinearSOE* obj, bool free) if (theEigenSOE != nullptr) theEigenSOE->setLinearSOE(*theSOE); - domainStamp = 0; } @@ -613,7 +773,7 @@ BasicAnalysisBuilder::set(ConvergenceTest* obj) void BasicAnalysisBuilder::set(EigenSOE &theNewSOE) { - // invoke the destructor on the old one if not the same! + // destroy the old one if not the same type if (theEigenSOE != nullptr) { if (theEigenSOE->getClassTag() != theNewSOE.getClassTag()) { delete theEigenSOE; @@ -625,10 +785,8 @@ BasicAnalysisBuilder::set(EigenSOE &theNewSOE) theEigenSOE = &theNewSOE; theEigenSOE->setLinks(*theAnalysisModel); theEigenSOE->setLinearSOE(*theSOE); - domainStamp = 0; } - } void @@ -654,7 +812,7 @@ BasicAnalysisBuilder::fillDefaults(BasicAnalysisBuilder::CurrentAnalysis flag) theTest = new CTestNormUnbalance(1.0e-6, 25, ConvergenceTest::PrintFailure); if (theAlgorithm == nullptr) - theAlgorithm = new NewtonRaphson(*theTest); + theAlgorithm = new NewtonRaphson(CURRENT_TANGENT, CURRENT_TANGENT, 0.0, 1.0); if (theHandler == nullptr) { @@ -671,8 +829,7 @@ BasicAnalysisBuilder::fillDefaults(BasicAnalysisBuilder::CurrentAnalysis flag) if (theSOE == nullptr) // TODO: CHANGE TO MORE GENERAL SOE - theSOE = new ProfileSPDLinSOE(*(new ProfileSPDLinDirectSolver())); - + theSOE = new ProfileSPDLinSOE(*(new ProfileSPDLinDirectSolver())); } @@ -702,11 +859,11 @@ BasicAnalysisBuilder::setTransientAnalysis() int BasicAnalysisBuilder::newTransientAnalysis() { - assert(theDomain != nullptr); + assert(theDomain != nullptr); - this->fillDefaults(TRANSIENT_ANALYSIS); + this->fillDefaults(TRANSIENT_ANALYSIS); - return 1; + return 1; } @@ -718,11 +875,11 @@ BasicAnalysisBuilder::newEigenAnalysis(int typeSolver, double shift) if (theHandler == nullptr) theHandler = new TransformationConstraintHandler(); - // this->CurrentAnalysisFlag = TRANSIENT_ANALYSIS; if (this->CurrentAnalysisFlag == EMPTY_ANALYSIS) this->CurrentAnalysisFlag = TRANSIENT_ANALYSIS; - this->fillDefaults(this->CurrentAnalysisFlag); //TRANSIENT_ANALYSIS); - this->setLinks(this->CurrentAnalysisFlag); //TRANSIENT_ANALYSIS); + + this->fillDefaults(this->CurrentAnalysisFlag); + this->setLinks(this->CurrentAnalysisFlag); // create a new eigen system and solver if (theEigenSOE != nullptr) { @@ -754,6 +911,7 @@ BasicAnalysisBuilder::newEigenAnalysis(int typeSolver, double shift) } // theEigenSOE == 0 } + int BasicAnalysisBuilder::eigen(int numMode, bool generalized, bool findSmallest) { @@ -766,7 +924,7 @@ BasicAnalysisBuilder::eigen(int numMode, bool generalized, bool findSmallest) Domain *the_Domain = this->getDomain(); // for parallel processing, want all analysis doing an eigenvalue analysis - result = theAnalysisModel->eigenAnalysis(numMode, generalized, findSmallest); + result = the_Domain->eigenAnalysis(numMode, generalized, findSmallest); int stamp = the_Domain->hasDomainChanged(); @@ -856,8 +1014,8 @@ BasicAnalysisBuilder::eigen(int numMode, bool generalized, bool findSmallest) // Solve for the eigen values & vectors // if (theEigenSOE->solve(numMode, generalized, findSmallest) < 0) { - opserr << G3_WARN_PROMPT << "EigenSOE failed in solve()\n"; - return -4; + opserr << G3_WARN_PROMPT << "EigenSOE failed in solve()\n"; + return -4; } // @@ -881,8 +1039,8 @@ BasicAnalysisBuilder::getDomain() return theDomain; } -EquiSolnAlgo* -BasicAnalysisBuilder::getAlgorithm() +const EquiSolnAlgo* +BasicAnalysisBuilder::getAlgorithm() const { return theAlgorithm; } @@ -894,8 +1052,8 @@ BasicAnalysisBuilder::getStaticIntegrator() } TransientIntegrator* -BasicAnalysisBuilder::getTransientIntegrator() { - +BasicAnalysisBuilder::getTransientIntegrator() +{ return theTransientIntegrator; } @@ -908,12 +1066,55 @@ BasicAnalysisBuilder::getConvergenceTest() int BasicAnalysisBuilder::formUnbalance() { - if (theStaticIntegrator != nullptr) - return theStaticIntegrator->formUnbalance(); + if (theStaticIntegrator != nullptr) + return theStaticIntegrator->formUnbalance(); - else if (theTransientIntegrator != nullptr) - return theTransientIntegrator->formUnbalance(); + else if (theTransientIntegrator != nullptr) + return theTransientIntegrator->formUnbalance(); - return -1; + return -1; } + +int +BasicAnalysisBuilder::analyzeGradient() +{ + switch (this->CurrentAnalysisFlag) { + case EMPTY_ANALYSIS: + return -1; + + case STATIC_ANALYSIS: + if (theStaticIntegrator->computeSensitivities() < 0) { + return -2; + } + case TRANSIENT_ANALYSIS: + if (theTransientIntegrator->computeSensitivities() < 0) { + return -2; + } + } + return 0; +} + +int +BasicAnalysisBuilder::setGradientType(int flag) +{ + switch (this->CurrentAnalysisFlag) { + case EMPTY_ANALYSIS: + return -1; + + case STATIC_ANALYSIS: + if (theStaticIntegrator->setGradientType(flag) < 0) { + return -2; + } + theStaticIntegrator->activateSensitivity(); + break; + + case TRANSIENT_ANALYSIS: + if (theTransientIntegrator->setGradientType(flag) < 0) { + return -2; + } + theTransientIntegrator->activateSensitivity(); + break; + } + return 0; +} \ No newline at end of file diff --git a/SRC/runtime/runtime/BasicAnalysisBuilder.h b/SRC/runtime/runtime/BasicAnalysisBuilder.h index 30187c7469..9609ab6d11 100644 --- a/SRC/runtime/runtime/BasicAnalysisBuilder.h +++ b/SRC/runtime/runtime/BasicAnalysisBuilder.h @@ -1,9 +1,18 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// -// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// // BasicAnalysisBuilder is an aggregate class which manages the analysis // objects: // @@ -28,6 +37,7 @@ #define BasicAnalysisBulider_h class Domain; +class BasicModelBuilder; class G3_Table; class ConstraintHandler; class DOF_Numberer; @@ -38,12 +48,11 @@ class EigenSOE; class StaticIntegrator; class TransientIntegrator; class ConvergenceTest; -class VariableTimeStepDirectIntegrationAnalysis; class BasicAnalysisBuilder { public: - BasicAnalysisBuilder(Domain* domain); + BasicAnalysisBuilder(BasicModelBuilder&); ~BasicAnalysisBuilder(); enum CurrentAnalysis { @@ -52,6 +61,12 @@ class BasicAnalysisBuilder TRANSIENT_ANALYSIS }; + enum Perform : int { + Increment = 1<<0, + Iterate = 1<<1, + Commit = 1<<2 + }; + void set(ConstraintHandler* obj); void set(DOF_Numberer* obj); void set(EquiSolnAlgo* obj); @@ -64,6 +79,8 @@ class BasicAnalysisBuilder LinearSOE* getLinearSOE(); Domain* getDomain(); + const BasicModelBuilder& getContext() const { return context; } + int initialize(); int newTransientAnalysis(); @@ -77,25 +94,29 @@ class BasicAnalysisBuilder int formUnbalance(); - VariableTimeStepDirectIntegrationAnalysis* getVariableTimeStepDirectIntegrationAnalysis() { - return theVariableTimeStepTransientAnalysis; - } - - EquiSolnAlgo* getAlgorithm(); + const EquiSolnAlgo* getAlgorithm() const; StaticIntegrator* getStaticIntegrator(); TransientIntegrator* getTransientIntegrator(); + + // for getCTestIter command ConvergenceTest* getConvergenceTest(); int domainChanged(); // Performing analysis - int analyze(int num_steps, double size_steps=0.0); - int analyzeStatic(int num_steps); + int analyze(int num_steps, double size_steps, int flag=Increment|Iterate|Commit); + int analyzeStatic(int num_steps, int flag); int analyzeTransient(int numSteps, double dT); + int analyzeVariable(int numSteps, double dT, double dtMin, double dtMax, int Jd); +private: int analyzeStep(double dT); int analyzeSubLevel(int level, double dT); +public: + int analyzeGradient(); + int setGradientType(int flag); + void wipe(); @@ -105,6 +126,7 @@ class BasicAnalysisBuilder void setLinks(CurrentAnalysis flag = EMPTY_ANALYSIS); void fillDefaults(enum CurrentAnalysis flag); + BasicModelBuilder& context; Domain *theDomain; ConstraintHandler *theHandler; DOF_Numberer *theNumberer; @@ -115,7 +137,6 @@ class BasicAnalysisBuilder StaticIntegrator *theStaticIntegrator; TransientIntegrator *theTransientIntegrator; ConvergenceTest *theTest; - VariableTimeStepDirectIntegrationAnalysis *theVariableTimeStepTransientAnalysis; int domainStamp; int numEigen = 0; diff --git a/SRC/runtime/runtime/BasicModelBuilder.cpp b/SRC/runtime/runtime/BasicModelBuilder.cpp index 7b1ec8f82c..35ecb469af 100644 --- a/SRC/runtime/runtime/BasicModelBuilder.cpp +++ b/SRC/runtime/runtime/BasicModelBuilder.cpp @@ -1,13 +1,21 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // -// Description: This file contains the class definition for BasicModelBuilder. -// A BasicModelBuilder adds the commands to create the model for the standard -// models that can be generated using the elements released with the g3 -// framework. +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// A BasicModelBuilder stores intermediate "reference" objects like +// materials and sections that are used +// to construct other objects like elements. // // Written: cmp // @@ -32,31 +40,30 @@ #include // For TCL_OK/ERROR -// -// CLASS CONSTRUCTOR & DESTRUCTOR -// -BasicModelBuilder::BasicModelBuilder(Domain &domain, Tcl_Interp *interp, - int NDM, int NDF) - : ndm(NDM), ndf(NDF), theInterp(interp), - section_builder_is_set(false), - theDomain(&domain), - tclEnclosingPattern(nullptr), - next_node_load(0), - next_elem_load(0) +BasicModelBuilder::BasicModelBuilder(Domain &domain, + Tcl_Interp *interp, + int NDM, int NDF) + : ndm(NDM), ndf(NDF), theInterp(interp), + section_builder_is_set(false), + theDomain(&domain), + tclEnclosingPattern(nullptr), + next_node_load(0) + // , next_elem_load(0) { - static int ncmd = sizeof(tcl_char_cmds)/sizeof(char_cmd); + using namespace OpenSees; + + static int ncmd = sizeof(ModelBuilderCommands)/sizeof(decltype(ModelBuilderCommands[0])); // CommandTableEntry); Tcl_CreateCommand(interp, "wipe", TclCommand_wipeModel, (ClientData)this, nullptr); for (int i = 0; i < ncmd; i++) Tcl_CreateCommand(interp, - tcl_char_cmds[i].name, - tcl_char_cmds[i].func, + ModelBuilderCommands[i].name, + ModelBuilderCommands[i].func, (ClientData) this, nullptr); - + tclEnclosingPattern = nullptr; - // theTclMultiSupportPattern = 0; Tcl_SetAssocData(interp, "OPS::theTclBuilder", NULL, (ClientData)this); Tcl_SetAssocData(interp, "OPS::theBasicModelBuilder", NULL, (ClientData)this); @@ -74,44 +81,66 @@ BasicModelBuilder::~BasicModelBuilder() // set the pointers to 0 theDomain = nullptr; -//theTclBuilder = nullptr; tclEnclosingPattern = nullptr; - static int ncmd = sizeof(tcl_char_cmds)/sizeof(char_cmd); + using namespace OpenSees; + + static int ncmd = sizeof(ModelBuilderCommands)/sizeof(decltype(ModelBuilderCommands[0])); for (int i = 0; i < ncmd; i++) - Tcl_DeleteCommand(theInterp, tcl_char_cmds[i].name); + Tcl_DeleteCommand(theInterp, ModelBuilderCommands[i].name); } int -BasicModelBuilder::buildFE_Model() {return 0;} +BasicModelBuilder::buildFE_Model() +{ + return 0; +} -int -BasicModelBuilder::getNDM() const {return ndm;} int -BasicModelBuilder::getNDF() const {return ndf;} +BasicModelBuilder::getNDM() const +{ + return ndm; +} -LoadPattern* -BasicModelBuilder::getCurrentLoadPattern() +int +BasicModelBuilder::getNDF() const { - return m_current_load_pattern; + return ndf; } void -BasicModelBuilder::letClobber(bool let_clobber) { +BasicModelBuilder::letClobber(bool let_clobber) +{ no_clobber = !let_clobber; } bool -BasicModelBuilder::canClobber() { +BasicModelBuilder::canClobber() +{ return !no_clobber; } -int BasicModelBuilder::incrNodalLoadTag(){return ++next_node_load;}; -int BasicModelBuilder::decrNodalLoadTag(){return --next_node_load;}; -int BasicModelBuilder::getNodalLoadTag() {return next_node_load;}; +int +BasicModelBuilder::incrNodalLoadTag() +{ + return ++next_node_load; +} + +int +BasicModelBuilder::decrNodalLoadTag() +{ + return --next_node_load; +} + +int +BasicModelBuilder::getNodalLoadTag() +{ + return next_node_load; +} + int BasicModelBuilder::addSP_Constraint(int axisDirn, double axisValue, const ID &fixityCodes, double tol) @@ -159,28 +188,31 @@ BasicModelBuilder::getDomain() const int BasicModelBuilder::printRegistry(const char *partition, OPS_Stream& stream, int flag) const { - int count = 0; - auto iter = m_registry.find(partition); - if (iter == m_registry.end()) { - return count; - } + int count = 0; + auto iter = m_registry.find(partition); + if (iter == m_registry.end()) { + return count; + } - for (auto const& [key, val] : iter->second) { - if (count != 0) - stream << ",\n"; + for (auto const& [key, val] : iter->second) { + if (count != 0) + stream << ",\n"; - val->Print(stream, flag); - count++; - } + val->Print(stream, flag); + count++; + } - return count; + return count; } void* -BasicModelBuilder::getRegistryObject(const char* partition, int tag, int flags) const +BasicModelBuilder::getRegistryObject(const char* type, const char* specialize, int tag, int flags) const { + std::string partition = std::string{type}; + if (specialize) + partition += std::string{specialize}; - auto iter = m_registry.find(std::string{partition}); + auto iter = m_registry.find(partition); if (iter == m_registry.end()) { if (flags == 0) opserr << "No objects of type \"" << partition @@ -191,20 +223,22 @@ BasicModelBuilder::getRegistryObject(const char* partition, int tag, int flags) auto iter_objs = iter->second.find(tag) ; if (iter_objs == iter->second.end()) { if (flags == 0) - opserr << "No object with tag \"" << tag << "\"in partition \"" + opserr << "No object with tag \"" << tag << "\" in partition \"" << partition << "\"\n"; return nullptr; } return (void*)iter_objs->second; - } int -BasicModelBuilder::addRegistryObject(const char* partition, int tag, void *obj) +BasicModelBuilder::addRegistryObject(const char* type, const char* specialize, int tag, void *obj) { - // TODO: Change void* obj to TaggedObject* - m_registry[std::string{partition}][tag] = (TaggedObject*)obj; + std::string partition = std::string{type}; + if (specialize) + partition += std::string{specialize}; + + m_registry[partition][tag] = (TaggedObject*)obj; return TCL_OK; } diff --git a/SRC/runtime/runtime/BasicModelBuilder.h b/SRC/runtime/runtime/BasicModelBuilder.h index b30f030631..e2a8291b71 100644 --- a/SRC/runtime/runtime/BasicModelBuilder.h +++ b/SRC/runtime/runtime/BasicModelBuilder.h @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -51,28 +60,23 @@ class BasicModelBuilder { int getCurrentSectionBuilder(int&); void setCurrentSectionBuilder(int); - LoadPattern *getCurrentLoadPattern(); LoadPattern* getEnclosingPattern(); int setEnclosingPattern(LoadPattern*); int incrNodalLoadTag(); int decrNodalLoadTag(); int getNodalLoadTag(); - // newCount - // getCount - // // Managing tagged objects // template int addTypedObject(int tag, T* obj) { - return addRegistryObject(typeid(T).name(), tag, obj); + return addRegistryObject(typeid(T).name(), nullptr, tag, obj); } - template int addTaggedObject(T& obj) { + template int addTaggedObject(T& obj) { int tag = obj.getTag(); -// m_registry[typeid(T).name()][tag] = &obj; - return addRegistryObject(typeid(T).name(), tag, &obj); + return addRegistryObject(typeid(T).name(), specialize, tag, &obj); } constexpr static int SilentLookup = 1; @@ -81,11 +85,13 @@ class BasicModelBuilder { return printRegistry(typeid(T).name(), stream, flag); } - template T* getTypedObject(int tag, int flags=0) const { - return (T*)getRegistryObject(typeid(T).name(), tag, flags); + template T* + getTypedObject(int tag, int flags=0) const { + return (T*)getRegistryObject(typeid(T).name(), specialize, tag, flags); } - template int removeObject(int tag, int flags=0) { + template int + removeObject(int tag, int flags=0) { return removeRegistryObject(typeid(T).name(), tag, flags); } @@ -100,15 +106,13 @@ class BasicModelBuilder { int buildFE_Model(); -// +// private: - // find/remove/insert - // TODO: make private - int addRegistryObject(const char*, int tag, void* obj); - void* getRegistryObject(const char*, int tag, int flags) const; + int addRegistryObject(const char*, const char*, int tag, void* obj); + void* getRegistryObject(const char*, const char*, int tag, int flags) const; int removeRegistryObject(const char*, int tag, int flags); int findFreeTag(const char*, int& tag) const; - int printRegistry(const char *, OPS_Stream& stream, int flag) const ; + int printRegistry(const char *, OPS_Stream& stream, int flag) const ; int ndm; // space dimension of the mesh @@ -117,17 +121,14 @@ class BasicModelBuilder { Tcl_Interp *theInterp; Domain *theDomain = nullptr; -//int eleArgStart = 0; int next_node_load = 0; - int next_elem_load = 0; // Options bool no_clobber = true; -// previously extern variables + // previously extern variables LoadPattern *tclEnclosingPattern = nullptr; - LoadPattern* m_current_load_pattern = nullptr; - MultiSupportPattern *theTclMultiSupportPattern = nullptr; +//MultiSupportPattern *theTclMultiSupportPattern = nullptr; bool section_builder_is_set = false; int current_section_builder = 0; diff --git a/SRC/runtime/runtime/CMakeLists.txt b/SRC/runtime/runtime/CMakeLists.txt index 28e1713c69..b4ea5cea8a 100644 --- a/SRC/runtime/runtime/CMakeLists.txt +++ b/SRC/runtime/runtime/CMakeLists.txt @@ -17,7 +17,7 @@ target_sources(OPS_Runtime TclPackageClassBroker.h ) -add_subdirectory(SectionBuilder) -add_subdirectory(Renderer) +add_subdirectory(modeling/section) +add_subdirectory(legacy/Renderer) diff --git a/SRC/runtime/runtime/G3_Runtime.cpp b/SRC/runtime/runtime/G3_Runtime.cpp deleted file mode 100644 index 6e045a079a..0000000000 --- a/SRC/runtime/runtime/G3_Runtime.cpp +++ /dev/null @@ -1,143 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// OpenSees - Open System for Earthquake Engineering Simulation -// -//===----------------------------------------------------------------------===// -// -// written: cmp -// -#include -#include -#include "G3_Runtime.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// DEFAULTS -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class StaticIntegrator; - -#define G3Config_keyExists(conf, key) ((conf).find((key)) != (conf).end()) - -template -using G3_Parse = T* (*)(G3_Runtime*, int, const char **const); - - -// Wrap a function with signature -// T* G3Parse_newT(G3_Runtime*, int argc, G3_Char** argv) -// so that it works with a std::vector -template -T* G3Object_newParsed(G3_Runtime *rt, G3_Char* command, std::vector args) { - std::vector cstrs; - cstrs.reserve(args.size()+1); - cstrs.push_back(command); - for (auto &s : args) - cstrs.push_back(const_cast(s.c_str())); - return (*fn)(rt, cstrs.size(), cstrs.data()); -} - - - -void * -G3_Runtime::newStaticAnalysis(G3_Config conf) -{ - StaticIntegrator* sintegrator = new LoadControl(1, 1, 1, 1); - - // CONVERGENCE TEST - ConvergenceTest* test = new CTestNormUnbalance(1.0e-6,25,0); - - // ALGORITHM - EquiSolnAlgo* the_algorithm = new NewtonRaphson(*test); - - // NUMBERER - DOF_Numberer* the_numberer = new DOF_Numberer(*(new RCM(false))); - - // CONSTRAINT HANDLER - ConstraintHandler *the_handler = new TransformationConstraintHandler(); - - // LINEAR SYSTEM - LinearSOE* the_soe = new ProfileSPDLinSOE(*new ProfileSPDLinDirectSolver()); - - - if (m_analysis_model == nullptr) - m_analysis_model = new AnalysisModel(); - - return new StaticAnalysis(*m_domain, - *the_handler, - *the_numberer, - *m_analysis_model, - *the_algorithm, - *the_soe, - *sintegrator, - test); -} -#if 1 -void * -G3_Runtime::newTransientAnalysis(G3_Config conf) -{ - // NUMBERER - DOF_Numberer* the_numberer = new DOF_Numberer(*(new RCM(false))); - - // CONSTRAINT HANDLER - ConstraintHandler *the_handler = new TransformationConstraintHandler(); - - // CONVERGENCE TEST - ConvergenceTest *test = new CTestNormUnbalance(1.0e-6,25,0); - - // ALGORITHM - EquiSolnAlgo* the_algorithm = new NewtonRaphson(*test); - - // LINEAR SYSTEM - LinearSOE* the_soe = new ProfileSPDLinSOE(*new ProfileSPDLinDirectSolver()); - - - // ANALYSIS MODEL - if (m_analysis_model == nullptr) - m_analysis_model = new AnalysisModel(); - - TransientIntegrator* tintegrator = new Newmark(0.5, 0.25); - - - if (G3Config_keyExists(conf, "analysis")) { - if (!conf["analysis"].empty() && (conf["analysis"][0] == "Variable")) - return new VariableTimeStepDirectIntegrationAnalysis( - *m_domain, - *the_handler, - *the_numberer, - *m_analysis_model, - *the_algorithm, - *the_soe, - *tintegrator, - test); - } - return new DirectIntegrationAnalysis( - *m_domain, - *the_handler, - *the_numberer, - *m_analysis_model, - *the_algorithm, - *the_soe, - *tintegrator, - test); -} - -#endif diff --git a/SRC/runtime/runtime/G3_Runtime.h b/SRC/runtime/runtime/G3_Runtime.h index 115298a059..1c5002b787 100644 --- a/SRC/runtime/runtime/G3_Runtime.h +++ b/SRC/runtime/runtime/G3_Runtime.h @@ -1,20 +1,23 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // // written: cmp // +#pragma once #include -#include -#include -#include - #include -#include - -typedef std::unordered_map> G3_Config; class Domain; class BasicModelBuilder; @@ -24,9 +27,6 @@ class ConstraintHandler; class LinearSOE; class EigenSOE; class DOF_Numberer; -class ConvergenceTest; -class StaticIntegrator; -class TransientIntegrator; class G3_Runtime { @@ -37,25 +37,14 @@ class G3_Runtime { // MODEL BUILDING BasicModelBuilder *m_builder = nullptr; Domain *m_domain = nullptr; - bool model_is_built=false; // ANALYSIS AnalysisModel *m_analysis_model = nullptr; AnalysisModel **m_analysis_model_ptr = &m_analysis_model; - - void *newStaticAnalysis(G3_Config); - void *newTransientAnalysis(G3_Config); - // IO FILE* streams[3] = {stdin,stdout,stderr}; }; -class G3_ParallelRuntime : public G3_Runtime { - bool is_partitioned=false; - int num_subdomains = 0; - bool flag_MPID_SOE = false; -}; - diff --git a/SRC/runtime/runtime/MeshModelBuilder.h b/SRC/runtime/runtime/MeshModelBuilder.h deleted file mode 100644 index 339c8a255d..0000000000 --- a/SRC/runtime/runtime/MeshModelBuilder.h +++ /dev/null @@ -1,5 +0,0 @@ -// -// -// added commands: -// material -// diff --git a/SRC/runtime/runtime/SectionBuilder/FiberSectionBuilder.h b/SRC/runtime/runtime/SectionBuilder/FiberSectionBuilder.h deleted file mode 100644 index 8661a5f481..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/FiberSectionBuilder.h +++ /dev/null @@ -1,110 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// OpenSees - Open System for Earthquake Engineering Simulation -// -//===----------------------------------------------------------------------===// -// -// Written: cmp -// -#ifndef FiberSectionBuilder_h -#define FiberSectionBuilder_h - -#include -#include -#include -#include -#include - -#include - -// Inherit tagged object so that the model builder can delete -class SectionBuilder: public TaggedObject { -public: - SectionBuilder(int tag) : TaggedObject(tag) {} - - virtual int addFiber(int tag, int mat, double area, const Vector& cPos) =0; - virtual int addHFiber(int tag, int mat, double area, const Vector& cPos)=0; - - int addPatch(const Patch& patch) { - Cell** cells = patch.getCells(); - const int nc = patch.getNumCells(); - const int mat = patch.getMaterialID(); - for(int j=0; jgetArea(); - const Vector& cPos = cells[j]->getCentroidPosition(); - - if (this->addFiber(j, mat, area, cPos) != 0) - return -1; - } - return 0; - } - - int addLayer(const ReinfLayer& layer) { - - int numReinfBars = layer.getNumReinfBars(); - ReinfBar* reinfBar = layer.getReinfBars(); - int mat = layer.getMaterialID(); - - for(int j=0; jaddFiber(j, mat, area, cPos) != 0) - return -1; - } - return 0; - } - -}; - -template -class FiberSectionBuilder : public SectionBuilder { -public: - FiberSectionBuilder(BasicModelBuilder& builder_, SecT& section_) - : SectionBuilder(section_.getTag()), builder(builder_), section(section_) {} - - virtual int addHFiber(int tag, int mat, double area, const Vector& cPos); - int addFiber(int tag, int mat, double area, const Vector& cPos) { - - MatT * theMaterial = builder.getTypedObject(mat); - if (theMaterial == nullptr) { - opserr << "no material with tag " << mat << " for fiber " << tag << "\n"; - return -1; - } - - if constexpr (ndm==2) { - section.addFiber(*theMaterial, area, cPos(0)); - - } else { - section.addFiber(*theMaterial, area, cPos(0), cPos(1)); - } - return 0; - } - -private: - BasicModelBuilder& builder; - SecT& section; -}; - -template <> int -FiberSectionBuilder<2, UniaxialMaterial, FiberSection2dInt>::addHFiber(int tag, int mat, double area, const Vector& cPos) { - - UniaxialMaterial * theMaterial = builder.getTypedObject(mat); - if (theMaterial == nullptr) { - opserr << G3_ERROR_PROMPT << "no material with tag " << mat << " for fiber " << tag << "\n"; - return -1; - } - - section.addHFiber(*theMaterial, area, cPos(0)); - return 0; -} - -template int -FiberSectionBuilder::addHFiber(int tag, int mat, double area, const Vector& cPos) { - opserr << G3_ERROR_PROMPT << "section does not support H fibers\n"; - return -1; -} - -#endif - diff --git a/SRC/runtime/runtime/SectionBuilder/cell/CircSectionCell.cpp b/SRC/runtime/runtime/SectionBuilder/cell/CircSectionCell.cpp deleted file mode 100644 index fdc970ae98..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/cell/CircSectionCell.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ - -// Written: fmk -// March 2014 - -#include -#include -#include - -#include - -CircSectionCell::CircSectionCell(double R1, double R2, double Alpha, double Theta, double offX, double offY) - :r1(R1), r2(R2), alpha(Alpha), theta(Theta), A(0.0), Centroid(2), offsetX(offX), offsetY(offY) -{ - - double a = alpha/2.0; - - double At = a*r2*r2; - double ct = 2.0*r2*sin(a)/(3.0*a); - double A1 = a*r1*r1; - double c1 = 2.0*r1*sin(a)/(3.0*a); - - A = At - A1; - double c = (At*ct - A1*c1)/A; - - Centroid(0) = cos(Theta)*c + offX; - Centroid(1) = sin(Theta)*c + offY; -} - - -CircSectionCell::~CircSectionCell() -{ - -} - -double CircSectionCell::getArea (void) const -{ - return A; -} - -double CircSectionCell::getdValue (void) const -{ - return 1.0; // TODO: Should be something meaningful -- MHS -} - -const Vector & -CircSectionCell::getCentroidPosition(void) -{ - return Centroid; -} - - - -void CircSectionCell::Print(OPS_Stream &s, int flag) const -{ - s << "\nCell Type: CircSectionCell"; - s << "\n\tr1: " << r1 << " r2: " << r2 << " alpha: " << alpha << " theta: " << theta << endln; -} - - -OPS_Stream &operator<<(OPS_Stream &s, const CircSectionCell &cell) -{ - cell.Print(s); - return s; -} - diff --git a/SRC/runtime/runtime/SectionBuilder/cell/CircSectionCell.h b/SRC/runtime/runtime/SectionBuilder/cell/CircSectionCell.h deleted file mode 100644 index 07c66c8d15..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/cell/CircSectionCell.h +++ /dev/null @@ -1,69 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ - -#ifndef CircSectionCell_h -#define CircSectionCell_h - -#include -#include - -class Matrix; -class Vector; - - -class CircSectionCell: public Cell -{ - public: - - CircSectionCell(); - CircSectionCell(double r2, double r1, double alpha, double theta, double centerX, double centerY); - - ~CircSectionCell(); - - // edition functions - - void setVertCoords (const Matrix &vertexCoords); - - // reinforcing bar inquiring functions - - double getArea (void) const; - double getdValue (void) const; - const Matrix &getVertCoords (void) const; - const Vector &getCentroidPosition (void); - - void Print(OPS_Stream &s, int flag =0) const; - friend OPS_Stream &operator<<(OPS_Stream &s, const CircSectionCell &quadCell); - - protected: - - private: - double r1, r2; // r1 inner and r2 outer radii - double alpha; // inner angle of section - double theta; // angle of centerline about z axis - - double A; - Vector Centroid; - double offsetX, offsetY; -// double area; -}; - - -#endif - diff --git a/SRC/runtime/runtime/SectionBuilder/cell/QuadCell.cpp b/SRC/runtime/runtime/SectionBuilder/cell/QuadCell.cpp deleted file mode 100644 index 6c9324bb50..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/cell/QuadCell.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ - -// $Revision: 1.3 $ -// $Date: 2003/05/02 18:34:56 $ -// $Source: /usr/local/cvs/OpenSees/SRC/material/section/repres/cell/QuadCell.cpp,v $ - - -// File: QuadCell.C -// Written by Remo M. de Souza -// December 1998 - -#include -#include - -#include - - -QuadCell::QuadCell(void): - vertCoord(4,2), Centroid(2) -{ - -} - - -QuadCell::QuadCell(const Matrix &vertexCoords): - vertCoord(vertexCoords), Centroid(2) -{ - -} - - -QuadCell::~QuadCell() -{ - -} - -const Matrix & -QuadCell::getVertCoords (void) const -{ - return vertCoord; -} - -double QuadCell::getdValue (void) const -{ - double dVa = vertCoord(0,0); - return dVa; -} - -void QuadCell::setVertCoords (const Matrix &vertexCoords) -{ - vertCoord = vertexCoords; -} - - -double QuadCell::getArea (void) const -{ - double area; - double x0, y0, x1, y1, x2, y2, x3, y3; - -// opserr << "cell vertCoord: " << vertCoord; - - x0 = vertCoord(0,0); - y0 = vertCoord(0,1); - x1 = vertCoord(1,0); - y1 = vertCoord(1,1); - x2 = vertCoord(2,0); - y2 = vertCoord(2,1); - x3 = vertCoord(3,0); - y3 = vertCoord(3,1); - - area = ((x2-x1)*(y0-y1) - (x0-x1)*(y2-y1) + - (x0-x3)*(y2-y3) - (x2-x3)*(y0-y3)) / 2.0; - -// opserr << "area1=" << area; - - int i, i1; - double yi, zi, yi1, zi1; - area = 0; - - for (i = 0; i < 4; i++) - { - i1 = (i+1)%4; - yi = vertCoord(i,0); - zi = vertCoord(i,1); - yi1 = vertCoord(i1,0); - zi1 = vertCoord(i1,1); - - area += (zi1 - zi) * (yi1 + yi); - } - area /= 2.0; - -// opserr << "area2= " << area << endln; - - return area; - -} - - -const Vector & -QuadCell::getCentroidPosition(void) -{ - int i, i1; - double yi, zi, yi1, zi1, dyi, dzi; - double area, integ; - double CGy = 0.0, CGz = 0.0; - - area = this->getArea(); - - for (i = 0; i < 4; i++) - { - i1 = (i+1)%4; - - yi = vertCoord(i,0); - zi = vertCoord(i,1); - yi1 = vertCoord(i1,0); - zi1 = vertCoord(i1,1); - - dyi = yi1 - yi; - dzi = zi1 - zi; - - integ = yi*zi + (yi*dzi + zi*dyi)/2.0 + dyi*dzi/3.0; - - CGy -= dyi * integ; - CGz += dzi * integ; - } - - CGy /= area; - CGz /= area; - - Centroid(0) = CGy; - Centroid(1) = CGz; - -// opserr << "\narea : " << area << " centroid: " << Centroid; - - return Centroid; -} - - - -void QuadCell::Print(OPS_Stream &s, int flag) const -{ - s << "\nCell Type: QuadCell"; - s << "\nVertex Coordinates: " << vertCoord; -} - - -OPS_Stream &operator<<(OPS_Stream &s, const QuadCell &quadCell) -{ - quadCell.Print(s); - return s; -} - diff --git a/SRC/runtime/runtime/SectionBuilder/patch/CircPatch.cpp b/SRC/runtime/runtime/SectionBuilder/patch/CircPatch.cpp deleted file mode 100644 index e8f3b70aa8..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/patch/CircPatch.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ****************************************************************** */ -// -// File: CircPatch.C -// Written by Remo M. de Souza -// December 1998 -// -#include -#include -#include -#include -#include -#include - - - -CircPatch::CircPatch(int materialID, int numSubdivCircunf, int numSubdivRadial, - const VectorND<2> ¢erPosition, double internRadius, - double externRadius, double initialAngle, double finalAngle): - matID(materialID), - nDivCirc(numSubdivCircunf), nDivRad(numSubdivRadial), - centerPosit(centerPosition), - intRad(internRadius), extRad(externRadius), - initAng(initialAngle), finalAng(finalAngle) -{ - -} - - -CircPatch::~CircPatch() -{ - -} - -void CircPatch::setMaterialID(int materialID) -{ - matID = materialID; -} - - -void CircPatch::setDiscretization(int numSubdivCircunf, int numSubdivRadial) -{ - nDivRad = numSubdivRadial; - nDivCirc = numSubdivCircunf; -} - - -void CircPatch::setRadii(double internRadius, double externRadius) -{ - intRad = internRadius; - extRad = externRadius; -} - -void CircPatch::setAngles(double initialAngle, double finalAngle) -{ - initAng = initialAngle; - finalAng = finalAngle; -} - - -int CircPatch::getMaterialID(void) const -{ - return matID; -} - -void CircPatch::getDiscretization(int &numSubdivCircunf, int &numSubdivRadial) const -{ - numSubdivCircunf = nDivCirc; - numSubdivRadial = nDivRad; -} - -void CircPatch::getRadii(double &internRadius, double &externRadius) const -{ - internRadius = intRad; - externRadius = extRad; -} - -void CircPatch::getAngles(double &initialAngle, double &finalAngle) const -{ - initialAngle = initAng; - finalAngle = finalAng; -} - -VectorND<2> -CircPatch::getCenterPosition() const -{ - return centerPosit; -} - -int CircPatch::getNumCells() const -{ - return nDivCirc * nDivRad; -} - -Cell ** -CircPatch::getCells() const -{ - double pi = acos(-1.0); - double deltaRad, deltaTheta; - double initAngRadians, finalAngRadians; - double rad_j, rad_j1, theta_i, theta_i1; - Matrix cellVertCoord(4,2); - - int numCells; - Cell **cells; - - if (nDivRad > 0 && nDivCirc > 0) - { - numCells = this->getNumCells(); - - cells = new Cell* [numCells]; - - initAngRadians = pi * initAng / 180.0; - finalAngRadians = pi * finalAng / 180.0; - - deltaRad = (extRad - intRad) / nDivRad; - deltaTheta = (finalAngRadians - initAngRadians) / nDivCirc; - - int k = 0; - for (int j = 0; j < nDivRad; j++) - { - rad_j = intRad + deltaRad*j; - rad_j1 = rad_j + deltaRad; - - for (int i = 0; i < nDivCirc; i++) - { - // compute coordinates - - theta_i = initAngRadians + deltaTheta*i; - - /* - theta_i1 = theta_i + deltaTheta; - cellVertCoord(0,0) = centerPosit(0) + rad_j * cos(theta_i1); - cellVertCoord(0,1) = centerPosit(1) + rad_j * sin(theta_i1); - cellVertCoord(1,0) = centerPosit(0) + rad_j * cos(theta_i); - cellVertCoord(1,1) = centerPosit(1) + rad_j * sin(theta_i); - cellVertCoord(2,0) = centerPosit(0) + rad_j1 * cos(theta_i); - cellVertCoord(2,1) = centerPosit(1) + rad_j1 * sin(theta_i); - cellVertCoord(3,0) = centerPosit(0) + rad_j1 * cos(theta_i1); - cellVertCoord(3,1) = centerPosit(1) + rad_j1 * sin(theta_i1); - - cells[k] = new QuadCell(cellVertCoord); - */ - - theta_i1 = theta_i + deltaTheta/2.0; - cells[k] = new CircSectionCell(rad_j, rad_j1, deltaTheta, theta_i1, centerPosit(0), centerPosit(1)); - - k++; - } - } - } - else - return 0; - - return cells; -} - - -Patch * -CircPatch::getCopy() const -{ - CircPatch *theCopy = new CircPatch (matID, nDivCirc, nDivRad, - centerPosit, intRad, extRad, - initAng, finalAng); - return theCopy; -} - -void CircPatch::Print(OPS_Stream &s, int flag) const -{ - s << "\nPatch Type: CircPatch"; - s << "\nMaterial Id: " << matID; - s << "\nNumber of subdivisions in the radial direction: " << nDivRad; - s << "\nNumber of subdivisions in the circunferential direction: " << nDivCirc; -// s << "\nCenter Position: " << Vector(centerPosit); - s << "\nInternal Radius: " << intRad << "\tExternal Radius: " << extRad; - s << "\nInitial Angle: " << initAng << "\tFinal Angle: " << finalAng; -} - diff --git a/SRC/runtime/runtime/SectionBuilder/patch/CircPatch.h b/SRC/runtime/runtime/SectionBuilder/patch/CircPatch.h deleted file mode 100644 index c19abe08c3..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/patch/CircPatch.h +++ /dev/null @@ -1,65 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ****************************************************************** */ -// -// File: CircPatch.h -// Written by Remo M. de Souza -// December 1998 -// -#ifndef CircPatch_h -#define CircPatch_h - -#include -#include -#include -using OpenSees::VectorND; - -class Cell; -class Matrix; - -class CircPatch: public Patch -{ - public: - - CircPatch(int materialID, int numSubdivCircunf, int numSubdivRadial, - const VectorND<2> ¢erPosition, double internRadius, - double externRadius, double initialAngle, double finalAngle); - - ~CircPatch(); - - // edition functions - - void setMaterialID (int materialID); - void setDiscretization (int numSubdivCircunf, int numSubdivRadial); - void setRadii (double internRadius, double externRadius); - void setAngles (double initialAngle, double finalAngle); - - // reinforcing bar inquiring functions - - int getMaterialID () const; - int getNumCells () const; - Cell **getCells () const; - Patch *getCopy () const; - - void getDiscretization (int &numSubdivCircunf, int &numSubdivRadial) const; - void getRadii (double &internRadius, double &externRadius) const; - void getAngles (double &initialAngle, double &finalAngle) const; - VectorND<2> getCenterPosition () const; - - void Print(OPS_Stream &s, int flag =0) const; - - protected: - - private: - int matID; - int nDivCirc, nDivRad; - const VectorND<2> centerPosit; - double intRad, extRad; - double initAng, finalAng; -}; - - -#endif - - diff --git a/SRC/runtime/runtime/SectionBuilder/patch/QuadPatch.cpp b/SRC/runtime/runtime/SectionBuilder/patch/QuadPatch.cpp deleted file mode 100644 index 64a10788bc..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/patch/QuadPatch.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ -// -// File: QuadPatch.C -// Written by Remo M. de Souza -// December 1998 -// -#include -#include -#include -#include -#include - -void * OPS_ADD_RUNTIME_VPV(OPS_QuadPatch) -{ - if(OPS_GetNumRemainingInputArgs() < 11) { - opserr<<"insufficient arguments for QuadPatch\n"; - return 0; - } - - // get idata - int numData = 3; - int idata[3]; - if(OPS_GetIntInput(&numData,&idata[0]) < 0) return 0; - - // get data - static Matrix vertexCoords(4,2); - double data[8]; - numData = 8; - if(OPS_GetDoubleInput(&numData,&data[0]) < 0) return 0; - for(int i=0; i<4; i++) { - for(int j=0; j<2; j++) { - vertexCoords(i,j) = data[i*2+j]; - } - } - - return new QuadPatch(idata[0],idata[1],idata[2],vertexCoords); -} - -void * OPS_ADD_RUNTIME_VPV(OPS_RectPatch) -{ - if(OPS_GetNumRemainingInputArgs() < 7) { - opserr<<"insufficient arguments for RectPatch\n"; - return 0; - } - - // get idata - int numData = 3; - int idata[3]; - if(OPS_GetIntInput(&numData,&idata[0]) < 0) return 0; - - // get data - static Matrix vertexCoords(4,2); - double data[4]; - numData = 4; - if(OPS_GetDoubleInput(&numData,&data[0]) < 0) return 0; - vertexCoords(0,0) = data[0]; - vertexCoords(0,1) = data[1]; - vertexCoords(1,0) = data[2]; - vertexCoords(1,1) = data[1]; - vertexCoords(2,0) = data[2]; - vertexCoords(2,1) = data[3]; - vertexCoords(3,0) = data[0]; - vertexCoords(3,1) = data[3]; - - return new QuadPatch(idata[0],idata[1],idata[2],vertexCoords); -} - - -QuadPatch::QuadPatch(): - matID(0), nDivIJ(1), nDivJK(1), vertCoord(4,2) -{ - -} - - -QuadPatch::QuadPatch(int materialID, int numSubdivIJ, int numSubdivJK, - const Matrix &vertexCoords): - matID(materialID), - nDivIJ(numSubdivIJ), nDivJK(numSubdivJK), - vertCoord(vertexCoords) - -{ - -} - - -QuadPatch::~QuadPatch() -{ - -} - -void QuadPatch::setMaterialID(int materialID) -{ - matID = materialID; -} - - -void QuadPatch::setDiscretization(int numSubdivIJ, int numSubdivJK) -{ - nDivIJ = numSubdivIJ; - nDivJK = numSubdivJK; -} - -void QuadPatch::setVertCoords(const Matrix &vertexCoords) -{ - vertCoord = vertexCoords; -} - -int QuadPatch::getMaterialID(void) const -{ - return matID; -} - -void QuadPatch::getDiscretization(int &numSubdivIJ, int &numSubdivJK) const -{ - numSubdivIJ = nDivIJ; - numSubdivJK = nDivJK; -} - -const Matrix & QuadPatch::getVertCoords (void) const -{ - return vertCoord; -} - -int QuadPatch::getNumCells (void) const -{ - return nDivIJ * nDivJK; -} - -Cell ** -QuadPatch::getCells (void) const -{ - double deltaXi; - double deltaEta; - Matrix cellVertCoord(4,2); - Vector N(4); - double xi, eta; - int i, j, k, r, s; - int numCells; - Cell **cells; - - if (nDivIJ > 0 && nDivJK > 0) - { - numCells = this->getNumCells(); - - cells = new Cell* [numCells]; - - if (!cells) - return 0; - - deltaXi = 2.0 / nDivIJ; - deltaEta = 2.0 / nDivJK; - - k = 0; - for (j = 0; j < nDivJK; j++) - for (i = 0; i < nDivIJ; i++) - { - // compute natural coordinates - - cellVertCoord(0,0) = -1.0 + deltaXi * i; - cellVertCoord(0,1) = -1.0 + deltaEta * j; - cellVertCoord(1,0) = -1.0 + deltaXi * (i+1); - cellVertCoord(1,1) = cellVertCoord(0,1); - cellVertCoord(2,0) = cellVertCoord(1,0); - cellVertCoord(2,1) = -1.0 + deltaEta * (j+1); - cellVertCoord(3,0) = cellVertCoord(0,0); - cellVertCoord(3,1) = cellVertCoord(2,1); - - // map to cartesian coordinates using bilinear - // shape functions - - for (r = 0; r < 4; r++) - { - xi = cellVertCoord(r,0); - eta = cellVertCoord(r,1); - - N(0) = (1.0 - xi)*(1.0 - eta)/4.0; - N(1) = (1.0 + xi)*(1.0 - eta)/4.0; - N(2) = (1.0 + xi)*(1.0 + eta)/4.0; - N(3) = (1.0 - xi)*(1.0 + eta)/4.0; - - cellVertCoord(r,0) = 0.0; - cellVertCoord(r,1) = 0.0; - - for (s = 0; s < 4; s++) - { - cellVertCoord(r,0) += N(s) * vertCoord(s,0); - cellVertCoord(r,1) += N(s) * vertCoord(s,1); - } - } - - cells[k] = new QuadCell(cellVertCoord); - //opserr << "\ncreating cells Cell " << k << " :" << cells[k]; - k++; - } - } - else - return 0; - - return cells; -} - - -Patch * -QuadPatch::getCopy (void) const -{ - QuadPatch *theCopy = new QuadPatch (matID, nDivIJ, nDivJK, vertCoord); - return theCopy; -} - -void QuadPatch::Print(OPS_Stream &s, int flag) const -{ - s << "\nPatch Type: QuadPatch"; - s << "\nMaterial Id: " << matID; - s << "\nNumber of subdivisions in the IJ direction: " << nDivIJ; - s << "\nNumber of subdivisions in the JK direction: " << nDivJK; - s << "\nVertex Coordinates: " << vertCoord; -} - - -OPS_Stream &operator<<(OPS_Stream &s, QuadPatch &quadPatch) -{ - quadPatch.Print(s); - return s; -} diff --git a/SRC/runtime/runtime/SectionBuilder/reinfLayer/CircReinfLayer.cpp b/SRC/runtime/runtime/SectionBuilder/reinfLayer/CircReinfLayer.cpp deleted file mode 100644 index 05d112e73a..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/reinfLayer/CircReinfLayer.cpp +++ /dev/null @@ -1,241 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ - -// $Revision: 1.3 $ -// $Date: 2003-02-14 23:01:37 $ -// $Source: /usr/local/cvs/OpenSees/SRC/material/section/repres/reinfLayer/CircReinfLayer.cpp,v $ - - -// File: CircReinfLayer.C -// Written by Remo M. de Souza -// December 1998 - -#include -#include -#include - -#include -#include -#include - -void * OPS_ADD_RUNTIME_VPV(OPS_CircReinfLayer) -{ - if(OPS_GetNumRemainingInputArgs() < 6) { - opserr<<"insufficient arguments for CircReinfLayer\n"; - return 0; - } - - // get idata - int numData = 2; - int idata[2]; - if(OPS_GetIntInput(&numData,&idata[0]) < 0) return 0; - - // get data - double data[6] = {0,0,0,0,0,0}; - numData = OPS_GetNumRemainingInputArgs(); - if(numData > 6) numData = 6; - if(OPS_GetDoubleInput(&numData,&data[0]) < 0) return 0; - static Vector cpos(2); - cpos(0) = data[1]; - cpos(1) = data[2]; - - if(numData < 6) { - return new CircReinfLayer(idata[0],idata[1],data[0], - cpos,data[3]); - } else { - return new CircReinfLayer(idata[0],idata[1],data[0], - cpos,data[3],data[4],data[5]); - } -} - - -CircReinfLayer::CircReinfLayer(void): - nReinfBars(0), matID(0), barDiam(0.0), - area(0.0), centerPosit(2), arcRad(0.0), - initAng(0.0), finalAng(0.0) -{ -} - - -CircReinfLayer::CircReinfLayer(int materialID, int numReinfBars, - double reinfBarArea, - const Vector ¢erPosition, - double arcRadius, double initialAngle, - double finalAngle): - nReinfBars(numReinfBars), - matID(materialID), area(reinfBarArea), - barDiam(0.0),centerPosit(centerPosition), - arcRad(arcRadius),initAng(initialAngle), - finalAng(finalAngle) -{ -} - -CircReinfLayer::CircReinfLayer(int materialID, int numReinfBars, double reinfBarArea, - const Vector ¢erPosition, double radius): -nReinfBars(numReinfBars), matID(materialID), area(reinfBarArea), -barDiam(0.0), centerPosit(centerPosition), arcRad(radius), -initAng(0.0), finalAng(0.0) -{ - // Figure out final angle so that complete circle does not put - // two bars at the same location - if (nReinfBars > 0) - finalAng = 360.0 - 360.0/nReinfBars; -} - -CircReinfLayer::~CircReinfLayer() -{ - -} - - -void CircReinfLayer::setNumReinfBars(int numReinfBars) -{ - nReinfBars = numReinfBars; -} - -void CircReinfLayer::setMaterialID (int materialID) -{ - matID = materialID; -} - -void CircReinfLayer::setReinfBarDiameter (double reinfBarDiameter) -{ - barDiam = reinfBarDiameter; - double pi = acos(-1.0); - area = pi * barDiam*barDiam/4.0; -} - -void CircReinfLayer::setReinfBarArea(double reinfBarArea) -{ - area = reinfBarArea; -} - - -int CircReinfLayer::getNumReinfBars (void) const -{ - return nReinfBars; -} - -int CircReinfLayer::getMaterialID (void) const -{ - return matID; -} - -double CircReinfLayer::getReinfBarDiameter (void) const -{ - return barDiam; -} - -double CircReinfLayer::getReinfBarArea (void) const -{ - return area; -} - -ReinfBar * -CircReinfLayer::getReinfBars (void) const -{ - double theta, dtheta; - static Vector barPosit(2); - int i; - ReinfBar *reinfBars; - double pi = acos(-1.0); - double initAngRad, finalAngRad; - - if (nReinfBars > 0) - { - initAngRad = pi * initAng / 180.0; - finalAngRad = pi * finalAng / 180.0; - - if (nReinfBars > 1) - dtheta = (finalAngRad - initAngRad) /(nReinfBars - 1); - else - dtheta = 0.0; // Doesn't really matter what this is - - reinfBars = new ReinfBar [nReinfBars]; - - for (i = 0; i < nReinfBars; i++) - { - theta = initAngRad + dtheta * i; - barPosit(0) = centerPosit(0) + arcRad*cos(theta); - barPosit(1) = centerPosit(1) + arcRad*sin(theta); - - reinfBars[i].setPosition(barPosit); - reinfBars[i].setArea(this->area); - } - } - else - return 0; - - return reinfBars; -} - - -const Vector & -CircReinfLayer::getCenterPosition(void) const -{ - return centerPosit; -} - -double CircReinfLayer::getArcRadius(void) const -{ - return arcRad; -} - -double CircReinfLayer::getInitAngle(void) const -{ - return initAng; -} - -double CircReinfLayer::getFinalAngle(void) const -{ - return finalAng; -} - - -ReinfLayer * -CircReinfLayer::getCopy (void) const -{ - CircReinfLayer *theCopy = new CircReinfLayer (matID, nReinfBars, area, - centerPosit, arcRad, - initAng, finalAng); - return theCopy; -} - - - -void CircReinfLayer::Print(OPS_Stream &s, int flag) const -{ - s << "\nReinforcing Layer type: Circ"; - s << "\nMaterial ID: " << matID; - s << "\nReinf. bar diameter: " << barDiam; - s << "\nReinf. bar area: " << area; - s << "\nCenter Position: " << centerPosit; - s << "\nArc Radius: " << arcRad; - s << "\nInitial angle: " << initAng; - s << "\nFinal angle: " << finalAng; -} - - -OPS_Stream &operator<<(OPS_Stream &s, const CircReinfLayer &CircReinfLayer) -{ - CircReinfLayer.Print(s); - return s; -} - diff --git a/SRC/runtime/runtime/SectionBuilder/reinfLayer/CircReinfLayer.h b/SRC/runtime/runtime/SectionBuilder/reinfLayer/CircReinfLayer.h deleted file mode 100644 index c905859e29..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/reinfLayer/CircReinfLayer.h +++ /dev/null @@ -1,103 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ - -// $Revision: 1.3 $ -// $Date: 2003-02-14 23:01:37 $ -// $Source: /usr/local/cvs/OpenSees/SRC/material/section/repres/reinfLayer/CircReinfLayer.h,v $ - - -// File: CircReinfLayer.h -// Written by Remo M. de Souza -// December 1998 - - -#ifndef CircReinfLayer_h -#define CircReinfLayer_h - -#include -#include - -class ReinfBar; - -class CircReinfLayer : public ReinfLayer -{ - public: - - CircReinfLayer(); - // Constructor for an arc - CircReinfLayer(int materialID, int numReinfBars, double reinfBarArea, - const Vector ¢erPosition, double arcRadius, double - initialAngle, double finalAngle); - // Constructor for full circle - CircReinfLayer(int materialID, int numReinfBars, double reinfBarArea, - const Vector ¢erPosition, double radius); - - ~CircReinfLayer(); - - // edition functions - - void setNumReinfBars (int numReinfBars); - void setMaterialID (int materialID); - void setReinfBarDiameter (double reinfBarDiameter); - void setReinfBarArea (double reinfBarArea); - - void setCenterPosition (const Vector ¢erPosition); - void setArcRadius (double arcRadius); - void setInitAngle (double initialAngle); - void setFinalAngle (double finalAngle); - - // inquiring functions - - int getNumReinfBars (void) const; - int getMaterialID (void) const; - double getReinfBarDiameter (void) const; - double getReinfBarArea (void) const; - ReinfBar *getReinfBars (void) const; - - - ReinfLayer *getCopy (void) const; - const Vector &getCenterPosition (void) const; - double getArcRadius (void) const; - double getInitAngle (void) const; - double getFinalAngle (void) const; - - - void Print(OPS_Stream &s, int flag =0) const; - friend OPS_Stream &operator<<(OPS_Stream &s, const CircReinfLayer &CircReinfLayer); - - protected: - - private: - int nReinfBars; - int matID; - double barDiam; - double area; - Vector centerPosit; - double arcRad; - double initAng; - double finalAng; -}; - - -#endif - - - - diff --git a/SRC/runtime/runtime/SectionBuilder/reinfLayer/ReinfLayer.h b/SRC/runtime/runtime/SectionBuilder/reinfLayer/ReinfLayer.h deleted file mode 100644 index ebfb366941..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/reinfLayer/ReinfLayer.h +++ /dev/null @@ -1,70 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ - -// $Revision: 1.3 $ -// $Date: 2003-02-14 23:01:37 $ -// $Source: /usr/local/cvs/OpenSees/SRC/material/section/repres/reinfLayer/ReinfLayer.h,v $ - - -// File: ReinfLayer.h -// Written by Remo M. de Souza -// December 1998 - -#ifndef ReinfLayer_h -#define ReinfLayer_h - -// #include - -class ReinfBar; -class OPS_Stream; - -class ReinfLayer -{ - public: - - ReinfLayer(); - virtual ~ReinfLayer(); - - // edition functions - - virtual void setNumReinfBars (int numReinfBars) = 0; - virtual void setMaterialID (int materialID) = 0; - virtual void setReinfBarDiameter (double reinfBarDiemater) = 0; - virtual void setReinfBarArea (double reinfBarArea) = 0; - - // reinforcing layer inquiring functions - - virtual int getNumReinfBars (void) const = 0; - virtual int getMaterialID (void) const = 0; - virtual double getReinfBarDiameter (void) const = 0; - virtual double getReinfBarArea (void) const = 0; - virtual ReinfLayer *getCopy (void) const = 0; - virtual ReinfBar *getReinfBars (void) const = 0; - - virtual void Print(OPS_Stream &s, int flag =0) const = 0; - friend OPS_Stream &operator<<(OPS_Stream &s, const ReinfLayer &ReinfLayer); - - protected: - - private: -}; - - -#endif diff --git a/SRC/runtime/runtime/SectionBuilder/reinfLayer/StraightReinfLayer.cpp b/SRC/runtime/runtime/SectionBuilder/reinfLayer/StraightReinfLayer.cpp deleted file mode 100644 index fe68a231ec..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/reinfLayer/StraightReinfLayer.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ -// -// File: StraightReinfLayer.C -// Written by Remo M. de Souza -// December 1998 -// -#include -#include -#include - -#include -#include -#include - - -StraightReinfLayer::StraightReinfLayer(int materialID, int numReinfBars, - double reinfBarArea, - const Vector &InitialPosition, - const Vector &FinalPosition): - nReinfBars(numReinfBars), - matID(materialID), - area(reinfBarArea), - barDiam(0.0), - initPosit(InitialPosition), - finalPosit(FinalPosition) -{ -} - - -StraightReinfLayer::~StraightReinfLayer() -{ - -} - - -void StraightReinfLayer::setNumReinfBars(int numReinfBars) -{ - nReinfBars = numReinfBars; -} - -void StraightReinfLayer::setMaterialID (int materialID) -{ - matID = materialID; -} - -void StraightReinfLayer::setReinfBarDiameter (double reinfBarDiameter) -{ - barDiam = reinfBarDiameter; - double pi = acos(-1.0); - area = pi * barDiam*barDiam/4.0; -} - -void StraightReinfLayer::setReinfBarArea(double reinfBarArea) -{ - area = reinfBarArea; -} - -void StraightReinfLayer::setInitialPosition (const Vector &initialPosition) -{ - initPosit = initialPosition; -} - -void StraightReinfLayer::setFinalPosition (const Vector &finalPosition) -{ - finalPosit = finalPosition; -} - - -int StraightReinfLayer::getNumReinfBars (void) const -{ - return nReinfBars; -} - -int StraightReinfLayer::getMaterialID (void) const -{ - return matID; -} - -double StraightReinfLayer::getReinfBarDiameter (void) const -{ - return barDiam; -} - -double StraightReinfLayer::getReinfBarArea (void) const -{ - return area; -} - -ReinfBar * -StraightReinfLayer::getReinfBars (void) const -{ - Vector barPosit(2); - ReinfBar *reinfBars; - - if (nReinfBars == 1) { - barPosit(0) = (initPosit(0) + finalPosit(0)) / 2; - barPosit(1) = (initPosit(1) + finalPosit(1)) / 2; - - reinfBars = new ReinfBar [1]; - - reinfBars[0].setPosition(barPosit); - reinfBars[0].setArea(this->area); - } - - else if (nReinfBars > 1) - { - double dy = (finalPosit(0) - initPosit(0))/(nReinfBars - 1); - double dz = (finalPosit(1) - initPosit(1))/(nReinfBars - 1); - - reinfBars = new ReinfBar [nReinfBars]; - - for (int i = 0; i < nReinfBars; i++) - { - barPosit(0) = initPosit(0) + dy * i; - barPosit(1) = initPosit(1) + dz * i; - - reinfBars[i].setPosition(barPosit); - reinfBars[i].setArea(this->area); - } - } - else - return 0; - - return reinfBars; -} - -const Vector & -StraightReinfLayer::getInitialPosition (void) const -{ - return initPosit; -} - -const Vector & -StraightReinfLayer::getFinalPosition (void) const -{ - return finalPosit; -} - - -ReinfLayer * -StraightReinfLayer::getCopy (void) const -{ - StraightReinfLayer *theCopy = new StraightReinfLayer (matID, - nReinfBars, area, - initPosit, finalPosit); - return theCopy; -} - - - -void StraightReinfLayer::Print(OPS_Stream &s, int flag) const -{ - s << "\nReinforcing Layer type: Straight"; - s << "\nMaterial ID: " << matID; - s << "\nReinf. bar diameter: " << barDiam; - s << "\nReinf. bar area: " << area; - s << "\nInitial Position: " << initPosit; - s << "\nFinal Position: " << finalPosit; -} - - -OPS_Stream &operator<<(OPS_Stream &s, const StraightReinfLayer &straightReinfLayer) -{ - straightReinfLayer.Print(s); - return s; -} - diff --git a/SRC/runtime/runtime/SectionBuilder/reinfLayer/StraightReinfLayer.h b/SRC/runtime/runtime/SectionBuilder/reinfLayer/StraightReinfLayer.h deleted file mode 100644 index 4205a45662..0000000000 --- a/SRC/runtime/runtime/SectionBuilder/reinfLayer/StraightReinfLayer.h +++ /dev/null @@ -1,82 +0,0 @@ -/* ****************************************************************** ** -** OpenSees - Open System for Earthquake Engineering Simulation ** -** Pacific Earthquake Engineering Research Center ** -** ** -** ** -** (C) Copyright 1999, The Regents of the University of California ** -** All Rights Reserved. ** -** ** -** Commercial use of this program without express permission of the ** -** University of California, Berkeley, is strictly prohibited. See ** -** file 'COPYRIGHT' in main directory for information on usage and ** -** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** -** ** -** Developed by: ** -** Frank McKenna (fmckenna@ce.berkeley.edu) ** -** Gregory L. Fenves (fenves@ce.berkeley.edu) ** -** Filip C. Filippou (filippou@ce.berkeley.edu) ** -** ** -** ****************************************************************** */ -// -// File: StraightReinfLayer.h -// Written by Remo M. de Souza -// December 1998 -// -#ifndef StraightReinfLayer_h -#define StraightReinfLayer_h - -#include -#include - -class ReinfBar; - -class StraightReinfLayer : public ReinfLayer -{ - public: - - StraightReinfLayer(int materialID, int numReinfBars, double reinfBarArea, - const Vector &initialPosition, - const Vector &finalPosition); - - ~StraightReinfLayer(); - - // edition functions - - void setNumReinfBars (int numReinfBars); - void setMaterialID (int materialID); - void setReinfBarDiameter (double reinfBarDiameter); - void setReinfBarArea (double reinfBarArea); - - void setInitialPosition (const Vector &initialPosition); - void setFinalPosition (const Vector &finalPosition); - - // inquiring functions - - int getNumReinfBars (void) const; - int getMaterialID (void) const; - double getReinfBarDiameter (void) const; - double getReinfBarArea (void) const; - ReinfBar *getReinfBars (void) const; - - - ReinfLayer *getCopy (void) const; - const Vector &getInitialPosition (void) const; - const Vector &getFinalPosition (void) const; - - void Print(OPS_Stream &s, int flag =0) const; - friend OPS_Stream &operator<<(OPS_Stream &s, const StraightReinfLayer &straightReinfLayer); - - protected: - - private: - int nReinfBars; - int matID; - double barDiam; - double area; - Vector initPosit; - Vector finalPosit; -}; - - -#endif - diff --git a/SRC/runtime/runtime/TclPackageClassBroker.cpp b/SRC/runtime/runtime/TclPackageClassBroker.cpp index 06ce284ba4..99e58f829e 100644 --- a/SRC/runtime/runtime/TclPackageClassBroker.cpp +++ b/SRC/runtime/runtime/TclPackageClassBroker.cpp @@ -1,10 +1,19 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so // //===----------------------------------------------------------------------===// // -// Purpose: This file contains the class definition for TclPackageClassBroker. +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +// +// Description: This file contains the class definition for TclPackageClassBroker. // TclPackageClassBroker is is an object broker class that is meant to become // a threadsafe replacement for the BrokerAllClasses class. // All methods are virtual to allow for subclasses; which can be @@ -21,10 +30,9 @@ #include using namespace OpenSees::Hash; using namespace OpenSees::Hash::literals; + #define DISPATCH(symbol) case hasher()(#symbol): return new symbol(); -// -// case hasher()(Truss::class_name): return new Truss(); -// + #include "packages.h" #include @@ -81,8 +89,8 @@ using namespace OpenSees::Hash::literals; #include "ModIMKPeakOriented.h" #include "snap/Clough.h" #include "limitState/LimitStateMaterial.h" -#include "InitStressMaterial.h" -#include "InitStrainMaterial.h" +#include "wrapper/InitStressMaterial.h" +#include "wrapper/InitStrainMaterial.h" #include "Bond_SP01.h" #include "SimpleFractureMaterial.h" #include "ConfinedConcrete01.h" @@ -115,14 +123,12 @@ using namespace OpenSees::Hash::literals; #include "drain/DrainClough1Material.h" #include "drain/DrainClough2Material.h" #include "drain/DrainPinch1Material.h" -#include "HyperbolicGapMaterial.h" +#include "abutment/HyperbolicGapMaterial.h" #include "ImpactMaterial.h" // Sections #include "ElasticSection2d.h" #include "ElasticSection3d.h" -#include "ElasticShearSection2d.h" -#include "ElasticShearSection3d.h" #include "GenericSection1d.h" //#include "GenericSectionNd.h" #include "SectionAggregator.h" @@ -130,7 +136,6 @@ using namespace OpenSees::Hash::literals; #include "FiberSection2d.h" #include "FiberSection3d.h" #include "FiberSectionAsym3d.h" //Xinlong Du -#include "ElasticPlateSection.h" #include "ElasticMembranePlateSection.h" #include "MembranePlateFiberSection.h" #include "Bidirectional.h" @@ -249,15 +254,15 @@ using namespace OpenSees::Hash::literals; #include "Shell/ShellMITC4.h" #include "Shell/ShellMITC9.h" -#include "Shell/ShellDKGQ.h" // Added by Lisha Wang, Xinzheng Lu, Linlin Xie, Song Cen & Quan Gu -#include "Shell/ShellNLDKGQ.h" // Added by Lisha Wang, Xinzheng Lu, Linlin Xie, Song Cen & Quan Gu -#include "Shell/ASDShellQ4.h" // Massimo Petracca +#include "Shell/ShellDKGQ.h" +#include "Shell/ShellNLDKGQ.h" +#include "Shell/ASDShellQ4.h" #include "Brick/Brick.h" #include "Brick/BbarBrick.h" #include "Brick/BrickUP.h" #include "Brick/BBarBrickUP.h" #include "Brick/Twenty_Eight_Node_BrickUP.h" -#include "Joint/Joint2D.h" // Arash +#include "Joint/Joint2D.h" #include "Link/TwoNodeLink.h" #include "Link/LinearElasticSpring.h" #include "Link/Inerter.h" @@ -287,10 +292,10 @@ using namespace OpenSees::Hash::literals; #include "Bearing/friction/frictionModel/VelNormalFrcDep.h" -#include "mvlem/MVLEM.h" // Kristijan Kolozvari -#include "mvlem/SFI_MVLEM.h" // Kristijan Kolozvari -#include "mvlem/MVLEM_3D.h" // Kristijan Kolozvari -#include "mvlem/SFI_MVLEM_3D.h" // Kristijan Kolozvari +#include "mvlem/MVLEM.h" +#include "mvlem/SFI_MVLEM.h" +#include "mvlem/MVLEM_3D.h" +#include "mvlem/SFI_MVLEM_3D.h" #include "Boundary/RockingBC.h" @@ -324,7 +329,7 @@ using namespace OpenSees::Hash::literals; #include "quadrature/Frame/MidDistanceBeamIntegration.h" #include "quadrature/Frame/CompositeSimpsonBeamIntegration.h" -// node header files +// Node header files #include "Node.h" #ifdef HEAP_NODE #include "HeapNode.h" @@ -389,25 +394,15 @@ using namespace OpenSees::Hash::literals; #include "LagrangeConstraintHandler.h" #include "TransformationConstraintHandler.h" -// dof numberer header files -#include "DOF_Numberer.h" -#include "PlainNumberer.h" - -// analysis model header files -#include "AnalysisModel.h" -// equi soln algo header files +// equi soln algo #include "EquiSolnAlgo.h" #include "Linear.h" #include "NewtonRaphson.h" #include "Broyden.h" #include "NewtonLineSearch.h" -#include "KrylovNewton.h" -#include "AcceleratedNewton.h" #include "ModifiedNewton.h" -#include "accelerator/KrylovAccelerator.h" -#include "accelerator/RaphsonAccelerator.h" #include "BisectionLineSearch.h" #include "InitialInterpolatedLineSearch.h" @@ -424,13 +419,8 @@ using namespace OpenSees::Hash::literals; #include "DistributedDisplacementControl.h" #endif #include "LoadControl.h" -// #include "StagedLoadControl.h" #include "TransientIntegrator.h" -#include "AlphaOS.h" -#include "AlphaOS_TP.h" -#include "AlphaOSGeneralized.h" -#include "AlphaOSGeneralized_TP.h" #include "CentralDifference.h" #include "CentralDifferenceAlternative.h" #include "CentralDifferenceNoDamping.h" @@ -455,7 +445,6 @@ using namespace OpenSees::Hash::literals; #include "KRAlphaExplicit.h" #include "KRAlphaExplicit_TP.h" #include "Newmark.h" -// #include "StagedNewmark.h" #include "NewmarkExplicit.h" #include "NewmarkHSFixedNumIter.h" #include "NewmarkHSIncrLimit.h" @@ -536,6 +525,7 @@ using namespace OpenSees::Hash::literals; # include "DistributedDiagonalSOE.h" #endif +using namespace OpenSees; typedef struct uniaxialPackage { int classTag; @@ -564,7 +554,7 @@ TclPackageClassBroker::getNewActor(int classTag, Channel *theChannel) default: opserr << "TclPackageClassBroker::getNewActor - "; opserr << " - no ActorType type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -582,7 +572,7 @@ TclPackageClassBroker::getPtrNewPartitionedModelBuilder(Subdomain &theSubdomain, default: opserr << "TclPackageClassBroker::getPtrNewPartitionedModelBuilder - "; opserr << " - no PartitionedModelBuilder type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -600,7 +590,7 @@ TclPackageClassBroker::getPtrNewGraphNumberer(int classTag) default: opserr << "TclPackageClassBroker::getPtrNewGraphNumberer - "; opserr << " - no GraphNumberer type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -616,19 +606,11 @@ TclPackageClassBroker::getNewElement(int classTag) { switch ((std::size_t)classTag) { - DISPATCH(Truss); DISPATCH(Truss2); DISPATCH(TrussSection); - DISPATCH(CorotTruss); DISPATCH(CorotTrussSection); DISPATCH(InertiaTruss); - // case ELE_TAG_ZeroLengthND: - // return new ZeroLengthND(); - - DISPATCH(FourNodeQuadUP); - DISPATCH(FourNodeQuad); - DISPATCH(Tri31); DISPATCH(ElasticBeam2d); DISPATCH(ModElasticBeam2d); DISPATCH(ModElasticBeam3d); @@ -643,6 +625,9 @@ TclPackageClassBroker::getNewElement(int classTag) DISPATCH(MixedBeamColumnAsym3d); // Quads + DISPATCH(FourNodeQuadUP); + DISPATCH(FourNodeQuad); + DISPATCH(Tri31); DISPATCH(EnhancedQuad); DISPATCH(NineNodeMixedQuad); DISPATCH(NineNodeQuad); @@ -661,7 +646,6 @@ TclPackageClassBroker::getNewElement(int classTag) DISPATCH(SSPbrickUP); #endif DISPATCH(PML2D); - DISPATCH(PML3D); // Bricks @@ -676,7 +660,7 @@ TclPackageClassBroker::getNewElement(int classTag) DISPATCH(ShellMITC9); DISPATCH(ShellDKGQ); DISPATCH(ShellNLDKGQ); - DISPATCH(ASDShellQ4); // Massimo Petracca + DISPATCH(ASDShellQ4); #if defined(OPSDEF_Elements_UW) DISPATCH(BeamContact2D); @@ -698,15 +682,15 @@ TclPackageClassBroker::getNewElement(int classTag) - DISPATCH(Joint2D); // Arash + DISPATCH(Joint2D); DISPATCH(TwoNodeLink); DISPATCH(LinearElasticSpring); DISPATCH(Inerter); - DISPATCH(MVLEM); // Kristijan Kolozvari - DISPATCH(SFI_MVLEM); // Kristijan Kolozvari - DISPATCH(MVLEM_3D); // Kristijan Kolozvari - DISPATCH(SFI_MVLEM_3D); // Kristijan Kolozvari + DISPATCH(MVLEM); + DISPATCH(SFI_MVLEM); + DISPATCH(MVLEM_3D); + DISPATCH(SFI_MVLEM_3D); DISPATCH(ElastomericBearingBoucWen2d); @@ -726,7 +710,6 @@ TclPackageClassBroker::getNewElement(int classTag) DISPATCH(SingleFPSimple3d); DISPATCH(TripleFrictionPendulum); - DISPATCH(RockingBC); DISPATCH(ASDEmbeddedNodeElement); DISPATCH(ASDAbsorbingBoundary2D); @@ -735,7 +718,7 @@ TclPackageClassBroker::getNewElement(int classTag) default: opserr << "TclPackageClassBroker::getNewElement - "; opserr << " - no Element type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -754,7 +737,7 @@ TclPackageClassBroker::getNewNode(int classTag) default: opserr << "TclPackageClassBroker::getNewNode - "; opserr << " - no Node type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -766,13 +749,13 @@ TclPackageClassBroker::getNewMP(int classTag) case CNSTRNT_TAG_MP_Constraint: return new MP_Constraint(classTag); - case CNSTRNT_TAG_MP_Joint2D: // Arash - return new MP_Joint2D(); // Arash + case CNSTRNT_TAG_MP_Joint2D: + return new MP_Joint2D(); default: opserr << "TclPackageClassBroker::getNewMP - "; opserr << " - no MP_Constraint type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -793,7 +776,7 @@ TclPackageClassBroker::getNewSP(int classTag) default: opserr << "TclPackageClassBroker::getNewSP - "; opserr << " - no SP_Constraint type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -808,7 +791,7 @@ TclPackageClassBroker::getNewPC(int classTag) default: opserr << "TclPackageClassBroker::getNewPC - "; opserr << " - no Pressure_Constraint type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -843,7 +826,7 @@ TclPackageClassBroker::getNewElementalLoad(int classTag) default: opserr << "TclPackageClassBroker::getNewNodalLoad - "; opserr << " - no NodalLoad type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } @@ -869,7 +852,7 @@ TclPackageClassBroker::getNewCrdTransf(int classTag) default: opserr << "TclPackageClassBroker::getCrdTransf - "; opserr << " - no CrdTransf type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -932,7 +915,7 @@ TclPackageClassBroker::getNewBeamIntegration(int classTag) default: opserr << "TclPackageClassBroker::getBeamIntegration - "; opserr << " - no BeamIntegration type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -966,6 +949,7 @@ TclPackageClassBroker::getNewUniaxialMaterial(int classTag) case MAT_TAG_ASD_SMA_3K: return new ASD_SMA_3K(); +// Concrete case MAT_TAG_Concrete01: return new Concrete01(); @@ -983,7 +967,7 @@ TclPackageClassBroker::getNewUniaxialMaterial(int classTag) case MAT_TAG_ConcretewBeta: return new ConcretewBeta(); - +// Steel case MAT_TAG_Steel01: return new Steel01(); @@ -1005,6 +989,7 @@ TclPackageClassBroker::getNewUniaxialMaterial(int classTag) case MAT_TAG_Hardening: return new HardeningMaterial(); +// Other case MAT_TAG_PySimple1: return new PySimple1(); @@ -1154,7 +1139,7 @@ TclPackageClassBroker::getNewUniaxialMaterial(int classTag) opserr << "TclPackageClassBroker::getNewUniaxialMaterial - "; opserr << " - no UniaxialMaterial type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1169,14 +1154,8 @@ TclPackageClassBroker::getNewSection(int classTag) case SEC_TAG_Elastic3d: return new ElasticSection3d(); - case SEC_TAG_ElasticShear2d: - return new ElasticShearSection2d(); - - case SEC_TAG_ElasticShear3d: - return new ElasticShearSection3d(); - - case SEC_TAG_Generic1d: - return new GenericSection1d(); + // case SEC_TAG_Generic1d: + // return new GenericSection1d(); // case SEC_TAG_GenericNd: // return new GenericSectionNd(); @@ -1196,9 +1175,6 @@ TclPackageClassBroker::getNewSection(int classTag) case SEC_TAG_FiberSectionAsym3d: return new FiberSectionAsym3d(); // Xinlong Du - case SEC_TAG_ElasticPlateSection: - return new ElasticPlateSection(); - case SEC_TAG_ElasticMembranePlateSection: return new ElasticMembranePlateSection(); @@ -1216,7 +1192,7 @@ TclPackageClassBroker::getNewSection(int classTag) default: opserr << "TclPackageClassBroker::getNewSection - "; opserr << " - no section type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1368,7 +1344,7 @@ TclPackageClassBroker::getNewNDMaterial(int classTag) default: opserr << "TclPackageClassBroker::getNewNDMaterial - "; opserr << " - no NDMaterial type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1380,7 +1356,7 @@ TclPackageClassBroker::getNewFiber(int classTag) default: opserr << "TclPackageClassBroker::getNewFiber - "; opserr << " - no Fiber type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1407,7 +1383,7 @@ TclPackageClassBroker::getNewFrictionModel(int classTag) default: opserr << "TclPackageClassBroker::getNewFrictionModel - "; opserr << " - no FrictionModel type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1443,7 +1419,7 @@ TclPackageClassBroker::getNewConvergenceTest(int classTag) default: opserr << "TclPackageClassBroker::getNewConvergenceTest - "; opserr << " - no ConvergenceTest type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1473,7 +1449,7 @@ TclPackageClassBroker::getNewLoadPattern(int classTag) default: opserr << "TclPackageClassBroker::getPtrLoadPattern - "; opserr << " - no Load type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1492,7 +1468,7 @@ TclPackageClassBroker::getNewGroundMotion(int classTag) default: opserr << "TclPackageClassBroker::getPtrGroundMotion - "; opserr << " - no Load type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1525,7 +1501,7 @@ TclPackageClassBroker::getNewTimeSeries(int classTag) default: opserr << "TclPackageClassBroker::getPtrTimeSeries - "; opserr << " - no Load type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1540,7 +1516,7 @@ TclPackageClassBroker::getNewTimeSeriesIntegrator(int classTag) default: opserr << "TclPackageClassBroker::getPtrTimeSeriesIntegrator - "; opserr << " - no Load type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1555,7 +1531,7 @@ TclPackageClassBroker::getPtrNewMatrix(int classTag, int noRows, int noCols) default: opserr << "TclPackageClassBroker::getPtrNewMatrix - "; opserr << " - no NodalLoad type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1570,7 +1546,7 @@ TclPackageClassBroker::getPtrNewVector(int classTag, int size) default: opserr << "TclPackageClassBroker::getPtrNewVector - "; opserr << " - no Vector type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1585,7 +1561,7 @@ TclPackageClassBroker::getPtrNewID(int classTag, int size) default: opserr << "TclPackageClassBroker::getPtrNewID - "; opserr << " - no ID type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1627,7 +1603,7 @@ TclPackageClassBroker::getPtrNewStream(int classTag) default: opserr << "TclPackageClassBroker::getPtrNewStream - "; opserr << " - no DataOutputHandler type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1666,7 +1642,7 @@ TclPackageClassBroker::getPtrNewRecorder(int classTag) default: opserr << "TclPackageClassBroker::getNewRecordr - "; opserr << " - no Recorder type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1696,7 +1672,7 @@ TclPackageClassBroker::getNewConstraintHandler(int classTag) default: opserr << "TclPackageClassBroker::getNewConstraintHandler - "; opserr << " - no ConstraintHandler type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1704,39 +1680,13 @@ TclPackageClassBroker::getNewConstraintHandler(int classTag) DOF_Numberer * TclPackageClassBroker::getNewNumberer(int classTag) { - switch (classTag) { - case NUMBERER_TAG_DOF_Numberer: - return new DOF_Numberer(); - - case NUMBERER_TAG_PlainNumberer: - return new PlainNumberer(); - -#ifdef _PARALLEL_PROCESSING - case NUMBERER_TAG_ParallelNumberer: - return new ParallelNumberer(); -#endif - - default: - opserr << "TclPackageClassBroker::getNewConstraintHandler - "; - opserr << " - no ConstraintHandler type exists for class tag "; - opserr << classTag << endln; - return 0; - } + return nullptr; } AnalysisModel * TclPackageClassBroker::getNewAnalysisModel(int classTag) { - switch (classTag) { - case AnaMODEL_TAGS_AnalysisModel: - return new AnalysisModel(); - - default: - opserr << "TclPackageClassBroker::getNewAnalysisModel - "; - opserr << " - no AnalysisModel type exists for class tag "; - opserr << classTag << endln; - return 0; - } + return nullptr; } EquiSolnAlgo * @@ -1752,12 +1702,6 @@ TclPackageClassBroker::getNewEquiSolnAlgo(int classTag) case EquiALGORITHM_TAGS_NewtonLineSearch: return new NewtonLineSearch(); - case EquiALGORITHM_TAGS_KrylovNewton: - return new KrylovNewton(); - - case EquiALGORITHM_TAGS_AcceleratedNewton: - return new AcceleratedNewton(); - case EquiALGORITHM_TAGS_ModifiedNewton: return new ModifiedNewton(CURRENT_TANGENT); @@ -1767,7 +1711,7 @@ TclPackageClassBroker::getNewEquiSolnAlgo(int classTag) default: opserr << "TclPackageClassBroker::getNewEquiSolnAlgo - "; opserr << " - no EquiSolnAlgo type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1776,16 +1720,10 @@ Accelerator * TclPackageClassBroker::getAccelerator(int classTag) { switch (classTag) { - - case ACCELERATOR_TAGS_Krylov: - return new KrylovAccelerator; - case ACCELERATOR_TAGS_Raphson: - return new RaphsonAccelerator; - default: opserr << "TclPackageClassBroker::getAccelerator - "; opserr << " - no EquiSolnAlgo type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1809,7 +1747,7 @@ TclPackageClassBroker::getLineSearch(int classTag) default: opserr << "TclPackageClassBroker::getNewEquiSolnAlgo - "; opserr << " - no EquiSolnAlgo type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1824,7 +1762,7 @@ TclPackageClassBroker::getNewDomainDecompAlgo(int classTag) default: opserr << "TclPackageClassBroker::getNewDomainDecompAlgo - "; opserr << " - no DomainDecompAlgo type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1835,10 +1773,6 @@ TclPackageClassBroker::getNewStaticIntegrator(int classTag) switch (classTag) { case INTEGRATOR_TAGS_LoadControl: return new LoadControl(1.0, 1, 1.0, .10); // must recvSelf -#if 0 - case INTEGRATOR_TAGS_StagedLoadControl: - return new StagedLoadControl(1.0, 1, 1.0, .10); // must recvSelf -#endif #ifdef _PARALLEL_PROCESSING case INTEGRATOR_TAGS_DistributedDisplacementControl: return new DistributedDisplacementControl(); // must recvSelf @@ -1850,7 +1784,7 @@ TclPackageClassBroker::getNewStaticIntegrator(int classTag) default: opserr << "TclPackageClassBroker::getNewStaticIntegrator - "; opserr << " - no StaticIntegrator type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1859,17 +1793,14 @@ TransientIntegrator * TclPackageClassBroker::getNewTransientIntegrator(int classTag) { switch (classTag) { - case INTEGRATOR_TAGS_AlphaOS: - return new AlphaOS(); - - case INTEGRATOR_TAGS_AlphaOS_TP: - return new AlphaOS_TP(); - - case INTEGRATOR_TAGS_AlphaOSGeneralized: - return new AlphaOSGeneralized(); - - case INTEGRATOR_TAGS_AlphaOSGeneralized_TP: - return new AlphaOSGeneralized_TP(); + // case INTEGRATOR_TAGS_AlphaOS: + // return new AlphaOS(); + // case INTEGRATOR_TAGS_AlphaOS_TP: + // return new AlphaOS_TP(); + // case INTEGRATOR_TAGS_AlphaOSGeneralized: + // return new AlphaOSGeneralized(); + // case INTEGRATOR_TAGS_AlphaOSGeneralized_TP: + // return new AlphaOSGeneralized_TP(); case INTEGRATOR_TAGS_CentralDifference: return new CentralDifference(); // must recvSelf @@ -1942,10 +1873,7 @@ TclPackageClassBroker::getNewTransientIntegrator(int classTag) case INTEGRATOR_TAGS_Newmark: return new Newmark(); -#if 0 - case INTEGRATOR_TAGS_StagedNewmark: - return new StagedNewmark(); -#endif + case INTEGRATOR_TAGS_NewmarkExplicit: return new NewmarkExplicit(); @@ -1957,10 +1885,7 @@ TclPackageClassBroker::getNewTransientIntegrator(int classTag) case INTEGRATOR_TAGS_NewmarkHSIncrReduct: return new NewmarkHSIncrReduct(); -#if 0 - case INTEGRATOR_TAGS_PFEMIntegrator: - return new PFEMIntegrator(); -#endif + case INTEGRATOR_TAGS_TRBDF2: return new TRBDF2(); @@ -1973,7 +1898,7 @@ TclPackageClassBroker::getNewTransientIntegrator(int classTag) default: opserr << "TclPackageClassBroker::getNewTransientIntegrator - "; opserr << " - no TransientIntegrator type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -1999,7 +1924,7 @@ TclPackageClassBroker::getNewIncrementalIntegrator(int classTag) default: opserr << "TclPackageClassBroker::getNewIncrementalIntegrator - "; opserr << " - no IncrementalIntegrator type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } @@ -2059,7 +1984,7 @@ TclPackageClassBroker::getNewLinearSOE(int classTagSOE) default: opserr << "TclPackageClassBroker::getNewLinearSOE - "; opserr << " - no LinearSOE type exists for class tag "; - opserr << classTagSOE << endln; + opserr << classTagSOE << "\n"; return 0; } } @@ -2071,20 +1996,16 @@ TclPackageClassBroker::getNewEigenSOE(int classTagSOE) switch (classTagSOE) { - case EigenSOE_TAGS_ArpackSOE: - theSOE = new ArpackSOE(); - return theSOE; - default: opserr << "TclPackageClassBroker::getNewEigenSOE - "; opserr << " - no EigenSOE type exists for class tag "; - opserr << classTagSOE << endln; + opserr << classTagSOE << "\n"; return 0; } } DomainSolver * -TclPackageClassBroker::getNewDomainSolver(void) +TclPackageClassBroker::getNewDomainSolver() { return lastDomainSolver; } @@ -2106,21 +2027,21 @@ TclPackageClassBroker::getPtrNewDDLinearSOE(int classTagSOE, } else { opserr << "TclPackageClassBroker::getNewLinearSOE - "; opserr << " - no ProfileSPD Domain Solver type exists for class tag "; - opserr << classTagDDSolver << endln; + opserr << classTagDDSolver << "\n"; return 0; } default: opserr << "TclPackageClassBroker::getNewLinearSOE - "; opserr << " - no LinearSOE type exists for class tag "; - opserr << classTagSOE << endln; + opserr << classTagSOE << "\n"; return 0; } } DomainDecompositionAnalysis * TclPackageClassBroker::getNewDomainDecompAnalysis(int classTag, - Subdomain &theSubdomain) + [[maybe_unused]] Subdomain &theSubdomain) { switch (classTag) { //case DomDecompANALYSIS_TAGS_DomainDecompositionAnalysis: @@ -2137,7 +2058,7 @@ TclPackageClassBroker::getNewDomainDecompAnalysis(int classTag, default: opserr << "TclPackageClassBroker::getNewDomainDecompAnalysis "; opserr << " - no DomainDecompAnalysis type exists for class tag "; - opserr << classTag << endln; + opserr << classTag << "\n"; return 0; } } diff --git a/SRC/runtime/runtime/TclPackageClassBroker.h b/SRC/runtime/runtime/TclPackageClassBroker.h index f36614949f..9e76082803 100644 --- a/SRC/runtime/runtime/TclPackageClassBroker.h +++ b/SRC/runtime/runtime/TclPackageClassBroker.h @@ -1,6 +1,15 @@ //===----------------------------------------------------------------------===// // -// OpenSees - Open System for Earthquake Engineering Simulation +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, OpenSees/Xara Developers +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause // //===----------------------------------------------------------------------===// // @@ -12,7 +21,6 @@ // method. All methods are virtual to allow for subclasses; which can be // used by programmers when introducing new subclasses of the main objects. // -// What: "@(#) TclPackageClassBroker.h, revA" #ifndef TclPackageClassBroker_h #define TclPackageClassBroker_h diff --git a/SRC/runtime/runtime/SectionBuilder/CMakeLists.txt b/SRC/runtime/runtime/modeling/section/CMakeLists.txt similarity index 78% rename from SRC/runtime/runtime/SectionBuilder/CMakeLists.txt rename to SRC/runtime/runtime/modeling/section/CMakeLists.txt index d1715ccf64..83c09d101c 100644 --- a/SRC/runtime/runtime/SectionBuilder/CMakeLists.txt +++ b/SRC/runtime/runtime/modeling/section/CMakeLists.txt @@ -8,8 +8,7 @@ add_library(OPS_Section_Repres OBJECT) target_include_directories(OPS_Section_Repres PUBLIC ${CMAKE_CURRENT_LIST_DIR}) -add_subdirectory(./cell/) -add_subdirectory(./patch/) -add_subdirectory(./reinfBar/) -add_subdirectory(./reinfLayer/) +add_subdirectory(cell) +add_subdirectory(patch) +add_subdirectory(reinfLayer) diff --git a/SRC/runtime/runtime/modeling/section/FiberSectionBuilder.h b/SRC/runtime/runtime/modeling/section/FiberSectionBuilder.h new file mode 100644 index 0000000000..dff4c0539f --- /dev/null +++ b/SRC/runtime/runtime/modeling/section/FiberSectionBuilder.h @@ -0,0 +1,150 @@ +//===----------------------------------------------------------------------===// +// +// xara +// +//===----------------------------------------------------------------------===// +// https://xara.so +//===----------------------------------------------------------------------===// +// Written: cmp +// +#ifndef FiberSectionBuilder_h +#define FiberSectionBuilder_h +#include +#include +#include +#include +#include +#include + +#include + +// Inherit tagged object so that the model builder can delete +class SectionBuilder: public TaggedObject { +public: + SectionBuilder(int tag) : TaggedObject(tag) {} + + virtual int addFiber(int tag, int mat, double area, + const Vector& cPos) =0; + + virtual int addHFiber(int tag, int mat, double area, const Vector& cPos)=0; + virtual int setWarping(int tag, int field, double w[3]) =0; + + int addPatch(const Patch& patch) { + Cell** cells = patch.getCells(); + const int nc = patch.getNumCells(); + const int mat = patch.getMaterialID(); + Vector cPos(2); + for(int j=0; jgetArea(); + const VectorND<2>& x = cells[j]->getPosition(); + cPos(0) = x(0); + cPos(1) = x(1); + if (this->addFiber(j, mat, area, cPos) < 0) + return -1; + } + return 0; + } + + int addLayer(const ReinfLayer& layer) { + + int numReinfBars = layer.getNumReinfBars(); + std::vector bars = layer.getReinfBars(); + int mat = layer.getMaterialID(); + Vector cPos(2); + for(int j=0; j& x = bars[j].getPosition(); + cPos(0) = x(0); + cPos(1) = x(1); + if (this->addFiber(j, mat, area, cPos) < 0) + return -1; + } + return 0; + } + +}; + +template +class FiberSectionBuilder : public SectionBuilder { +public: + FiberSectionBuilder(BasicModelBuilder& builder_, SecT& section_) + : SectionBuilder(section_.getTag()), builder(builder_), section(section_) {} + + virtual int addHFiber(int tag, int mat, double area, const Vector& cPos); + + int setWarping(int tag, int field, double w[3]) { + // Warping is set using the setParameter interface + + std::string ts = std::to_string(tag); + + for (int i=0; i<3; i++) { + // Dont pass argv/argc in Parameters constructor because it cant + // signal errors that way. + Parameter p(-1, nullptr, nullptr, 0); + + std::string s = std::to_string(w[i]); + std::string v = std::to_string(field*3+i); + const char* argv[] {"warp", ts.c_str(), v.c_str()}; + + if (0 > section.setParameter(argv, 3, p)) + return -1; + + p.update(w[i]); + } + + return 0; + } + + int + addFiber(int tag, int mat, double area, const Vector& cPos) + { + if (area <= 0.0) { + opserr << OpenSees::PromptValueError + << "fiber area <= 0.0 for fiber " << tag << "\n"; + return -1; + } + + MatT * theMaterial = builder.getTypedObject(mat); + if (theMaterial == nullptr) { + opserr << OpenSees::PromptValueError + << "no material with tag " << mat << " for fiber " << tag << "\n"; + return -1; + } + + int id = -1; + if constexpr (ndm==2) { + id = section.addFiber(*theMaterial, area, cPos(0)); + } + else { + id = section.addFiber(*theMaterial, area, cPos(0), cPos(1)); + } + return id; + } + +private: + BasicModelBuilder& builder; + SecT& section; +}; + +template <> int +FiberSectionBuilder<2, UniaxialMaterial, FiberSection2dInt>::addHFiber(int tag, int mat, double area, const Vector& cPos) { + + UniaxialMaterial * theMaterial = builder.getTypedObject(mat); + if (theMaterial == nullptr) { + opserr << OpenSees::PromptValueError + << "no material with tag " << mat << " for fiber " << tag << "\n"; + return -1; + } + + section.addHFiber(*theMaterial, area, cPos(0)); + return 0; +} + +template int +FiberSectionBuilder::addHFiber(int tag, int mat, double area, const Vector& cPos) { + opserr << OpenSees::PromptValueError << "section does not support H fibers\n"; + return -1; +} + +#endif + diff --git a/SRC/runtime/runtime/SectionBuilder/cell/CMakeLists.txt b/SRC/runtime/runtime/modeling/section/cell/CMakeLists.txt similarity index 97% rename from SRC/runtime/runtime/SectionBuilder/cell/CMakeLists.txt rename to SRC/runtime/runtime/modeling/section/cell/CMakeLists.txt index dd766ddbf3..7b45854d29 100644 --- a/SRC/runtime/runtime/SectionBuilder/cell/CMakeLists.txt +++ b/SRC/runtime/runtime/modeling/section/cell/CMakeLists.txt @@ -7,7 +7,6 @@ target_sources(OPS_Section_Repres PRIVATE - Cell.cpp CircSectionCell.cpp QuadCell.cpp PUBLIC diff --git a/SRC/runtime/runtime/SectionBuilder/cell/Cell.h b/SRC/runtime/runtime/modeling/section/cell/Cell.h similarity index 71% rename from SRC/runtime/runtime/SectionBuilder/cell/Cell.h rename to SRC/runtime/runtime/modeling/section/cell/Cell.h index 76302ed124..6211cdb640 100644 --- a/SRC/runtime/runtime/SectionBuilder/cell/Cell.h +++ b/SRC/runtime/runtime/modeling/section/cell/Cell.h @@ -23,37 +23,29 @@ // Written by Remo M. de Souza // December 1998 - -#ifndef Cell_h -#define Cell_h - -#include - -class Vector; - -class Cell -{ - public: - - Cell(); - virtual ~Cell(); - - // edition functions - - // reinforcing bar inquiring functions - - virtual double getArea (void) const = 0; - virtual double getdValue (void) const = 0; - virtual const Vector &getCentroidPosition (void) = 0; - - virtual void Print(OPS_Stream &s, int flag =0) const = 0; - friend OPS_Stream &operator<<(OPS_Stream &s, const Cell &Cell); - - protected: - - private: +#ifndef Cell_h +#define Cell_h +#include + +using OpenSees::VectorND; +class Cell { +public: + Cell() : area(0.0) {} + Cell(int mat, double area, const VectorND<2>& loc) : area(area), location(loc) + { + } + // reinforcing bar inquiring functions + + double getArea() const {return area;}; + double getdValue() const {return 0.0;}; + const VectorND<2>& getPosition() const {return location;}; + int getMaterial() const {return matID;}; + +protected: + double area; + int matID; + VectorND<2> location; +private: }; - #endif - diff --git a/SRC/runtime/runtime/modeling/section/cell/CircSectionCell.cpp b/SRC/runtime/runtime/modeling/section/cell/CircSectionCell.cpp new file mode 100644 index 0000000000..eeb2c0e198 --- /dev/null +++ b/SRC/runtime/runtime/modeling/section/cell/CircSectionCell.cpp @@ -0,0 +1,46 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +// Written: fmk +// March 2014 + +#include +#include +#include +#include + +#include + +CircSectionCell::CircSectionCell(double r1, double r2, double alpha, double theta, double offsetX, + double offsetY) +{ + + double a = alpha / 2.0; + double At = a * r2 * r2; + double ct = 2.0 * r2 * sin(a) / (3.0 * a); + double A1 = a * r1 * r1; + double c1 = 2.0 * r1 * sin(a) / (3.0 * a); + + area = At - A1; + double c = (At * ct - A1 * c1) / area; + + location[0] = std::cos(theta) * c + offsetX; + location[1] = std::sin(theta) * c + offsetY; +} \ No newline at end of file diff --git a/SRC/runtime/runtime/SectionBuilder/cell/Cell.cpp b/SRC/runtime/runtime/modeling/section/cell/CircSectionCell.h similarity index 74% rename from SRC/runtime/runtime/SectionBuilder/cell/Cell.cpp rename to SRC/runtime/runtime/modeling/section/cell/CircSectionCell.h index 8e0e460b54..84e9616963 100644 --- a/SRC/runtime/runtime/SectionBuilder/cell/Cell.cpp +++ b/SRC/runtime/runtime/modeling/section/cell/CircSectionCell.h @@ -17,25 +17,22 @@ ** Filip C. Filippou (filippou@ce.berkeley.edu) ** ** ** ** ****************************************************************** */ - -// $Revision: 1.1.1.1 $ -// $Date: 2000-09-15 08:23:22 $ -// $Source: /usr/local/cvs/OpenSees/SRC/material/section/repres/cell/Cell.cpp,v $ - - -// File: Cell.C -// Written by Remo M. de Souza -// December 1998 -#include +#ifndef CircSectionCell_h +#define CircSectionCell_h -Cell::Cell(void) -{ +#include +#include -} +class Matrix; +class Vector; -Cell::~Cell(void) -{ +class CircSectionCell : public Cell { +public: + CircSectionCell(double r2, double r1, double alpha, double theta, double centerX, double centerY); -} +protected: +private: +}; +#endif diff --git a/SRC/runtime/runtime/modeling/section/cell/QuadCell.cpp b/SRC/runtime/runtime/modeling/section/cell/QuadCell.cpp new file mode 100644 index 0000000000..bc24a9047b --- /dev/null +++ b/SRC/runtime/runtime/modeling/section/cell/QuadCell.cpp @@ -0,0 +1,92 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ +// +// File: QuadCell.C +// Written by Remo M. de Souza +// December 1998 +// +#include +#include +#include +using OpenSees::MatrixND; +using OpenSees::VectorND; +// QuadCell::QuadCell() : vertCoord{}, location{} {} + +QuadCell::QuadCell(const MatrixND<4,2>& vertCoord) + //: vertCoord(vertexCoords) +{ + + // double x0 = vertCoord(0, 0); + // double y0 = vertCoord(0, 1); + // double x1 = vertCoord(1, 0); + // double y1 = vertCoord(1, 1); + // double x2 = vertCoord(2, 0); + // double y2 = vertCoord(2, 1); + // double x3 = vertCoord(3, 0); + // double y3 = vertCoord(3, 1); + + // double area = ((x2 - x1) * (y0 - y1) - (x0 - x1) * (y2 - y1) + (x0 - x3) * (y2 - y3) - + // (x2 - x3) * (y0 - y3)) / + // 2.0; + + + area = 0; + + for (int i = 0; i < 4; i++) { + int i1 = (i + 1) % 4; + double yi = vertCoord(i, 0); + double zi = vertCoord(i, 1); + double yi1 = vertCoord(i1, 0); + double zi1 = vertCoord(i1, 1); + + area += (zi1 - zi) * (yi1 + yi); + } + area /= 2.0; + + // + // centroid + // + + double CGy = 0.0, CGz = 0.0; + + for (int i = 0; i < 4; i++) { + int i1 = (i + 1) % 4; + + double yi = vertCoord(i, 0); + double zi = vertCoord(i, 1); + double yi1 = vertCoord(i1, 0); + double zi1 = vertCoord(i1, 1); + + double dyi = yi1 - yi; + double dzi = zi1 - zi; + + double integ = yi * zi + (yi * dzi + zi * dyi) / 2.0 + dyi * dzi / 3.0; + + CGy -= dyi * integ; + CGz += dzi * integ; + } + + CGy /= area; + CGz /= area; + + location[0] = CGy; + location[1] = CGz; + +} diff --git a/SRC/runtime/runtime/SectionBuilder/reinfLayer/ReinfLayer.cpp b/SRC/runtime/runtime/modeling/section/cell/QuadCell.h similarity index 83% rename from SRC/runtime/runtime/SectionBuilder/reinfLayer/ReinfLayer.cpp rename to SRC/runtime/runtime/modeling/section/cell/QuadCell.h index 94a2da2a2b..59cbbdb8b3 100644 --- a/SRC/runtime/runtime/SectionBuilder/reinfLayer/ReinfLayer.cpp +++ b/SRC/runtime/runtime/modeling/section/cell/QuadCell.h @@ -17,22 +17,29 @@ ** Filip C. Filippou (filippou@ce.berkeley.edu) ** ** ** ** ****************************************************************** */ - -// File: ReinfLayer.C +// +// File: QuadCell.h +// // Written by Remo M. de Souza // December 1998 -#include - +#ifndef QuadCell_h +#define QuadCell_h -ReinfLayer::ReinfLayer(void) -{ +#include +#include +#include -} +using OpenSees::MatrixND; +using OpenSees::VectorND; -ReinfLayer::~ReinfLayer(void) -{ +class QuadCell : public Cell { +public: + QuadCell(const MatrixND<4,2>& vertexCoords); -} +protected: +private: +}; +#endif diff --git a/SRC/runtime/runtime/SectionBuilder/patch/CMakeLists.txt b/SRC/runtime/runtime/modeling/section/patch/CMakeLists.txt similarity index 96% rename from SRC/runtime/runtime/SectionBuilder/patch/CMakeLists.txt rename to SRC/runtime/runtime/modeling/section/patch/CMakeLists.txt index 253d0d8b5e..280891a8c7 100644 --- a/SRC/runtime/runtime/SectionBuilder/patch/CMakeLists.txt +++ b/SRC/runtime/runtime/modeling/section/patch/CMakeLists.txt @@ -8,7 +8,6 @@ target_sources(OPS_Section_Repres PRIVATE CircPatch.cpp - Patch.cpp QuadPatch.cpp PUBLIC CircPatch.h diff --git a/SRC/runtime/runtime/modeling/section/patch/CircPatch.cpp b/SRC/runtime/runtime/modeling/section/patch/CircPatch.cpp new file mode 100644 index 0000000000..5a97ae4921 --- /dev/null +++ b/SRC/runtime/runtime/modeling/section/patch/CircPatch.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// OpenSees - Open System for Earthquake Engineering Simulation +// +//===----------------------------------------------------------------------===// +// +// Adapted from CircPatch.C +// Written by Remo M. de Souza +// December 1998 +// +#include +#include +#include +#include +#include +#include +#include + +CircPatch::CircPatch(int materialID, int numSubdivCircunf, int numSubdivRadial, + const VectorND<2>& centerPosition, double internRadius, double externRadius, + double initialAngle, double finalAngle) + : matID(materialID), + nDivCirc(numSubdivCircunf), + nDivRad(numSubdivRadial), + centerPosit(centerPosition), + intRad(internRadius), + extRad(externRadius), + initAng(initialAngle), + finalAng(finalAngle) +{ +} + +CircPatch::~CircPatch() {} + +int +CircPatch::getMaterialID() const +{ + return matID; +} + +int +CircPatch::getNumCells() const +{ + return nDivCirc * nDivRad; +} + +Cell** +CircPatch::getCells() const +{ + double pi = acos(-1.0); + double deltaRad, deltaTheta; + double initAngRadians, finalAngRadians; + double theta_i, theta_i1; + Matrix cellVertCoord(4, 2); + + int numCells; + Cell** cells; + + if (nDivRad > 0 && nDivCirc > 0) { + numCells = this->getNumCells(); + + cells = new Cell*[numCells]; + + initAngRadians = pi * initAng / 180.0; + finalAngRadians = pi * finalAng / 180.0; + + deltaRad = (extRad - intRad) / nDivRad; + deltaTheta = (finalAngRadians - initAngRadians) / nDivCirc; + + int k = 0; + for (int j = 0; j < nDivRad; j++) { + double rad_j = intRad + deltaRad * j; + double rad_j1 = rad_j + deltaRad; + + for (int i = 0; i < nDivCirc; i++) { + + theta_i = initAngRadians + deltaTheta * i; + + theta_i1 = theta_i + deltaTheta / 2.0; + cells[k] = new CircSectionCell(rad_j, rad_j1, deltaTheta, theta_i1, centerPosit(0), centerPosit(1)); + + k++; + } + } + } else + return 0; + + return cells; +} diff --git a/SRC/runtime/runtime/modeling/section/patch/CircPatch.h b/SRC/runtime/runtime/modeling/section/patch/CircPatch.h new file mode 100644 index 0000000000..28936e077d --- /dev/null +++ b/SRC/runtime/runtime/modeling/section/patch/CircPatch.h @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// OpenSees - Open System for Earthquake Engineering Simulation +// +//===----------------------------------------------------------------------===// +// +// Adapted from CircPatch.h +// Written by Remo M. de Souza +// December 1998 +// +#ifndef CircPatch_h +#define CircPatch_h + +#include +#include +#include +using OpenSees::VectorND; + +class Cell; +class Matrix; + +class CircPatch : public Patch { +public: + CircPatch(int material, + int numSubdivCircunf, int numSubdivRadial, + const VectorND<2>& centerPosition, + double internRadius, double externRadius, + double initialAngle, double finalAngle); + + ~CircPatch(); + + int getMaterialID() const; + int getNumCells() const; + Cell** getCells() const; + +protected: +private: + int matID; + int nDivCirc, nDivRad; + const VectorND<2> centerPosit; + double intRad, extRad; + double initAng, finalAng; +}; + +#endif diff --git a/SRC/runtime/runtime/modeling/section/patch/Patch.h b/SRC/runtime/runtime/modeling/section/patch/Patch.h new file mode 100644 index 0000000000..f20b751702 --- /dev/null +++ b/SRC/runtime/runtime/modeling/section/patch/Patch.h @@ -0,0 +1,29 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ****************************************************************** */ +// +// File: Patch.h +// Written by Remo M. de Souza +// December 1998 +// +#ifndef Patch_h +#define Patch_h +class Cell; +class OPS_Stream; + +class Patch { +public: + + // inquiring functions + + virtual int getMaterialID() const = 0; + virtual int getNumCells() const = 0; + virtual Cell** getCells() const = 0; + +protected: +private: +}; + +#endif diff --git a/SRC/runtime/runtime/modeling/section/patch/QuadPatch.cpp b/SRC/runtime/runtime/modeling/section/patch/QuadPatch.cpp new file mode 100644 index 0000000000..605aa3fc22 --- /dev/null +++ b/SRC/runtime/runtime/modeling/section/patch/QuadPatch.cpp @@ -0,0 +1,120 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ +// +// File: QuadPatch.C +// Written by Remo M. de Souza +// December 1998 +// +#include +#include +#include +#include +#include +#include +#include +#include + +using OpenSees::VectorND; + +QuadPatch::QuadPatch(int materialID, int numSubdivIJ, int numSubdivJK, + const MatrixND<4,2>& vertexCoords) + : matID(materialID), nDivIJ(numSubdivIJ), nDivJK(numSubdivJK), vertCoord(vertexCoords) + +{ +} + +QuadPatch::~QuadPatch() {} + +int +QuadPatch::getMaterialID() const +{ + return matID; +} + +int +QuadPatch::getNumCells() const +{ + return nDivIJ * nDivJK; +} + +Cell** +QuadPatch::getCells() const +{ + VectorND<4> N; + double xi, eta; + int numCells; + Cell** cells; + + if (nDivIJ > 0 && nDivJK > 0) { + numCells = this->getNumCells(); + + cells = new Cell*[numCells]; + + if (!cells) + return 0; + + double deltaXi = 2.0 / nDivIJ; + double deltaEta = 2.0 / nDivJK; + + int k = 0; + for (int j = 0; j < nDivJK; j++) + for (int i = 0; i < nDivIJ; i++) { + // compute natural coordinates + + MatrixND<4,2> cellVertCoord; + cellVertCoord(0, 0) = -1.0 + deltaXi * i; + cellVertCoord(0, 1) = -1.0 + deltaEta * j; + cellVertCoord(1, 0) = -1.0 + deltaXi * (i + 1); + cellVertCoord(1, 1) = cellVertCoord(0, 1); + cellVertCoord(2, 0) = cellVertCoord(1, 0); + cellVertCoord(2, 1) = -1.0 + deltaEta * (j + 1); + cellVertCoord(3, 0) = cellVertCoord(0, 0); + cellVertCoord(3, 1) = cellVertCoord(2, 1); + + // map to cartesian coordinates using bilinear + // shape functions + + for (int r = 0; r < 4; r++) { + xi = cellVertCoord(r, 0); + eta = cellVertCoord(r, 1); + + N(0) = (1.0 - xi) * (1.0 - eta) / 4.0; + N(1) = (1.0 + xi) * (1.0 - eta) / 4.0; + N(2) = (1.0 + xi) * (1.0 + eta) / 4.0; + N(3) = (1.0 - xi) * (1.0 + eta) / 4.0; + + cellVertCoord(r, 0) = 0.0; + cellVertCoord(r, 1) = 0.0; + + for (int s = 0; s < 4; s++) { + cellVertCoord(r, 0) += N(s) * vertCoord(s, 0); + cellVertCoord(r, 1) += N(s) * vertCoord(s, 1); + } + } + + cells[k] = new QuadCell(cellVertCoord); + k++; + } + } else + return nullptr; + + return cells; +} + diff --git a/SRC/runtime/runtime/modeling/section/patch/QuadPatch.h b/SRC/runtime/runtime/modeling/section/patch/QuadPatch.h new file mode 100644 index 0000000000..96b35a2240 --- /dev/null +++ b/SRC/runtime/runtime/modeling/section/patch/QuadPatch.h @@ -0,0 +1,54 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ +// +// File: QuadPatch.h +// Written by Remo M. de Souza +// December 1998 +// +#ifndef QuadPatch_h +#define QuadPatch_h + +#include +#include +#include + +class Cell; +class Matrix; +using OpenSees::MatrixND; + +class QuadPatch : public Patch { +public: + QuadPatch(); + QuadPatch(int materialID, int numSubdivIJ, int numSubdivJK, const MatrixND<4,2>& vertexCoords); + + ~QuadPatch(); + + int getMaterialID() const; + int getNumCells() const; + Cell** getCells() const; + +protected: +private: + int matID; + int nDivIJ, nDivJK; + MatrixND<4,2> vertCoord; +}; + +#endif diff --git a/SRC/runtime/runtime/SectionBuilder/reinfLayer/CMakeLists.txt b/SRC/runtime/runtime/modeling/section/reinfLayer/CMakeLists.txt similarity index 96% rename from SRC/runtime/runtime/SectionBuilder/reinfLayer/CMakeLists.txt rename to SRC/runtime/runtime/modeling/section/reinfLayer/CMakeLists.txt index 6651d6dcdd..4b7b1faca7 100644 --- a/SRC/runtime/runtime/SectionBuilder/reinfLayer/CMakeLists.txt +++ b/SRC/runtime/runtime/modeling/section/reinfLayer/CMakeLists.txt @@ -8,7 +8,6 @@ target_sources(OPS_Section_Repres PRIVATE CircReinfLayer.cpp - ReinfLayer.cpp StraightReinfLayer.cpp PUBLIC CircReinfLayer.h diff --git a/SRC/runtime/runtime/modeling/section/reinfLayer/CircReinfLayer.cpp b/SRC/runtime/runtime/modeling/section/reinfLayer/CircReinfLayer.cpp new file mode 100644 index 0000000000..097acef42d --- /dev/null +++ b/SRC/runtime/runtime/modeling/section/reinfLayer/CircReinfLayer.cpp @@ -0,0 +1,98 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ +// +// File: CircReinfLayer.C +// Written by Remo M. de Souza +// December 1998 + +#include +#include +#include +#include +#include + +#include +#include + + + +CircReinfLayer::CircReinfLayer(int material, int numReinfBars, double area, + const VectorND<2>& centerPosition, double arcRadius, double initialAngle, + double finalAngle) + : ReinfLayer(material, area), + nReinfBars(numReinfBars), + centerPosit(centerPosition), + arcRad(arcRadius), + initAng(initialAngle), + finalAng(finalAngle) +{ +} + +CircReinfLayer::CircReinfLayer(int material, int numReinfBars, double area, + const VectorND<2>& centerPosition, double radius) + : ReinfLayer(material, area), + nReinfBars(numReinfBars), + centerPosit(centerPosition), + arcRad(radius), + initAng(0.0), + finalAng(0.0) +{ + // Figure out final angle so that complete circle does not put + // two bars at the same location + if (nReinfBars > 0) + finalAng = 360.0 - 360.0 / nReinfBars; +} + +int +CircReinfLayer::getNumReinfBars() const +{ + return nReinfBars; +} + +std::vector +CircReinfLayer::getReinfBars() const +{ + std::vector bars(nReinfBars); + + double pi = acos(-1.0); + + if (nReinfBars > 0) { + double initAngRad = pi * initAng / 180.0; + double finalAngRad = pi * finalAng / 180.0; + + double dtheta; + if (nReinfBars > 1) + dtheta = (finalAngRad - initAngRad) / (nReinfBars - 1); + else + dtheta = 0.0; // Doesn't really matter what this is + + + for (int i = 0; i < nReinfBars; i++) { + double theta = initAngRad + dtheta * i; + VectorND<2> position { + centerPosit(0) + arcRad * cos(theta), + centerPosit(1) + arcRad * sin(theta) + }; + bars[i] = Cell(this->getMaterialID(), this->getCellArea(), position); + } + } + + return bars; +} diff --git a/SRC/runtime/runtime/SectionBuilder/patch/Patch.h b/SRC/runtime/runtime/modeling/section/reinfLayer/CircReinfLayer.h similarity index 64% rename from SRC/runtime/runtime/SectionBuilder/patch/Patch.h rename to SRC/runtime/runtime/modeling/section/reinfLayer/CircReinfLayer.h index 2b247cbba5..0a0d227e6e 100644 --- a/SRC/runtime/runtime/SectionBuilder/patch/Patch.h +++ b/SRC/runtime/runtime/modeling/section/reinfLayer/CircReinfLayer.h @@ -18,41 +18,43 @@ ** ** ** ****************************************************************** */ // -// File: Patch.h +// File: CircReinfLayer.h // Written by Remo M. de Souza // December 1998 -// -#ifndef Patch_h -#define Patch_h -class Cell; -class OPS_Stream; +#ifndef CircReinfLayer_h +#define CircReinfLayer_h -class Patch -{ - public: +#include +#include +#include - Patch(); - virtual ~Patch(); - - // edition functions +using OpenSees::VectorND; - virtual void setMaterialID (int materialID) = 0; - - // inquiring functions +class CircReinfLayer : public ReinfLayer { +public: + // Constructor for an arc + CircReinfLayer(int material, int n, double area, + const VectorND<2>& center, double radius, + double initialAngle, + double finalAngle); + // Constructor for full circle + CircReinfLayer(int material, int n, double area, + const VectorND<2>& center, double radius); - virtual int getMaterialID (void) const = 0; - virtual int getNumCells (void) const = 0; - virtual Cell **getCells (void) const = 0; - virtual Patch *getCopy (void) const = 0; + virtual ~CircReinfLayer() {}; - virtual void Print(OPS_Stream &s, int flag =0) const =0; - friend OPS_Stream &operator<<(OPS_Stream &s, const Patch &patch); + int getNumReinfBars() const; + std::vector getReinfBars() const; - protected: - - private: -}; +protected: +private: + int nReinfBars; + VectorND<2> centerPosit; + double arcRad; + double initAng; + double finalAng; +}; #endif diff --git a/SRC/runtime/runtime/SectionBuilder/patch/Patch.cpp b/SRC/runtime/runtime/modeling/section/reinfLayer/ReinfLayer.h similarity index 74% rename from SRC/runtime/runtime/SectionBuilder/patch/Patch.cpp rename to SRC/runtime/runtime/modeling/section/reinfLayer/ReinfLayer.h index 4e340ddca7..15774c083f 100644 --- a/SRC/runtime/runtime/SectionBuilder/patch/Patch.cpp +++ b/SRC/runtime/runtime/modeling/section/reinfLayer/ReinfLayer.h @@ -17,26 +17,36 @@ ** Filip C. Filippou (filippou@ce.berkeley.edu) ** ** ** ** ****************************************************************** */ - -// $Revision: 1.1.1.1 $ -// $Date: 2000-09-15 08:23:22 $ -// $Source: /usr/local/cvs/OpenSees/SRC/material/section/repres/patch/Patch.cpp,v $ - - -// File: Patch.C +// +// File: ReinfLayer.h // Written by Remo M. de Souza // December 1998 +// +#ifndef ReinfLayer_h +#define ReinfLayer_h +#include +#include -#include +class ReinfLayer { +public: + ReinfLayer(int material, double area) : material(material), area(area) {} + virtual ~ReinfLayer() {}; -Patch::Patch(void) -{ + int getMaterialID() const { + return material; + }; -} + virtual int getNumReinfBars() const = 0; + virtual std::vector getReinfBars() const = 0; -Patch::~Patch(void) -{ - -} +protected: + double getCellArea() const { + return area; + }; +private: + int material; + double area; +}; +#endif diff --git a/SRC/runtime/runtime/SectionBuilder/reinfBar/ReinfBar.cpp b/SRC/runtime/runtime/modeling/section/reinfLayer/StraightReinfLayer.cpp similarity index 52% rename from SRC/runtime/runtime/SectionBuilder/reinfBar/ReinfBar.cpp rename to SRC/runtime/runtime/modeling/section/reinfLayer/StraightReinfLayer.cpp index 296f0aea98..2ed0ac63da 100644 --- a/SRC/runtime/runtime/SectionBuilder/reinfBar/ReinfBar.cpp +++ b/SRC/runtime/runtime/modeling/section/reinfLayer/StraightReinfLayer.cpp @@ -18,80 +18,70 @@ ** ** ** ****************************************************************** */ // -// File: ReinfBar.C +// File: StraightReinfLayer.C // Written by Remo M. de Souza // December 1998 - -#include +// #include -#include #include -#include - - -ReinfBar::ReinfBar (void): - diameter(0.0), area(0.0), matID(0), posit(2) -{ - -} - - -ReinfBar::ReinfBar(double barArea, int materialID, const Vector &position): - diameter(0.0), area(barArea), - matID(materialID), posit(position) -{ -} - -ReinfBar::~ReinfBar() +#include +#include +#include + +#include +#include + +StraightReinfLayer::StraightReinfLayer(int material, int n, double area, + const VectorND<2>& xi, + const VectorND<2>& xj) + : ReinfLayer(material, area), + nReinfBars(n), + initPosit(xi), + finalPosit(xj) { - } -void ReinfBar::setDiameter (double barDiameter) +int +StraightReinfLayer::getNumReinfBars() const { - double pi = acos(-1.0); - diameter = barDiameter; - area = pi * diameter*diameter/4.0; + return nReinfBars; } -void ReinfBar::setArea (double barArea) +std::vector +StraightReinfLayer::getReinfBars() const { - area = barArea; -} + VectorND<2> barPosit; + // ReinfBar* reinfBars; + std::vector bars(nReinfBars); -void ReinfBar::setMaterial (int materialID) -{ - matID = materialID; -} + if (nReinfBars == 1) { + VectorND<2> location { + barPosit(0) = (initPosit(0) + finalPosit(0)) / 2, + barPosit(1) = (initPosit(1) + finalPosit(1)) / 2 + }; -void ReinfBar::setPosition (const Vector &position) -{ - posit = position; -} + // reinfBars = new ReinfBar[1]; + bars[0] = Cell(this->getMaterialID(), this->getCellArea(), location); -double ReinfBar::getDiameter(void) const -{ - return diameter; -} + // bars[0].setPosition(barPosit); + // bars[0].setArea(this->area); + } -double ReinfBar::getArea (void) const -{ - return area; -} + else if (nReinfBars > 1) { + double dy = (finalPosit(0) - initPosit(0)) / (nReinfBars - 1); + double dz = (finalPosit(1) - initPosit(1)) / (nReinfBars - 1); + // reinfBars = new ReinfBar[nReinfBars]; -const Vector & ReinfBar::getPosition(void) const -{ - return posit; -} + for (int i = 0; i < nReinfBars; i++) { + VectorND<2> location { + initPosit(0) + dy * i, + initPosit(1) + dz * i + }; + bars[i] = Cell(this->getMaterialID(), this->getCellArea(), location); + } + } -void ReinfBar::Print(OPS_Stream &s, int flag) const -{ - s << "\nReinforcing Bar area: " << area; - s << "\nMaterial ID: " << matID; - s << "\nDiameter: " << diameter; - s << "\nArea: " << area; - s << "\nPosition: " << posit; + return bars; } - diff --git a/SRC/runtime/runtime/modeling/section/reinfLayer/StraightReinfLayer.h b/SRC/runtime/runtime/modeling/section/reinfLayer/StraightReinfLayer.h new file mode 100644 index 0000000000..f7e847114f --- /dev/null +++ b/SRC/runtime/runtime/modeling/section/reinfLayer/StraightReinfLayer.h @@ -0,0 +1,51 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ +// +// File: StraightReinfLayer.h +// Written by Remo M. de Souza +// December 1998 +// +#ifndef StraightReinfLayer_h +#define StraightReinfLayer_h + +#include +#include +#include + +using OpenSees::VectorND; + +class StraightReinfLayer : public ReinfLayer { +public: + StraightReinfLayer(int materialID, int numReinfBars, double reinfBarArea, + const VectorND<2>& initialPosition, const VectorND<2>& finalPosition); + + virtual ~StraightReinfLayer() {}; + + int getNumReinfBars() const; + std::vector getReinfBars() const; + +protected: +private: + int nReinfBars; + VectorND<2> initPosit; + VectorND<2> finalPosit; +}; + +#endif diff --git a/SRC/system_of_eqn/eigenSOE/CMakeLists.txt b/SRC/system_of_eqn/eigenSOE/CMakeLists.txt index 5f6de61057..cb61250c74 100644 --- a/SRC/system_of_eqn/eigenSOE/CMakeLists.txt +++ b/SRC/system_of_eqn/eigenSOE/CMakeLists.txt @@ -14,6 +14,8 @@ target_sources(OPS_SysOfEqn FullGenEigenSolver.cpp SymBandEigenSOE.cpp SymBandEigenSolver.cpp + SymmGeneralizedEigenSOE.cpp + SymmGeneralizedEigenSolver.cpp PUBLIC ArpackSOE.h ArpackSolver.h @@ -23,6 +25,8 @@ target_sources(OPS_SysOfEqn FullGenEigenSolver.h SymBandEigenSOE.h SymBandEigenSolver.h + SymmGeneralizedEigenSOE.h + SymmGeneralizedEigenSolver.h ) target_sources(OPS_SysOfEqn diff --git a/SRC/system_of_eqn/eigenSOE/Makefile b/SRC/system_of_eqn/eigenSOE/Makefile index bf8821b61d..2104083f27 100644 --- a/SRC/system_of_eqn/eigenSOE/Makefile +++ b/SRC/system_of_eqn/eigenSOE/Makefile @@ -7,7 +7,9 @@ OBJS = EigenSOE.o \ SymBandEigenSOE.o \ SymBandEigenSolver.o \ FullGenEigenSOE.o \ - FullGenEigenSolver.o + FullGenEigenSolver.o \ + SymmGeneralizedEigenSOE.o \ + SymmGeneralizedEigenSolver.o all: $(OBJS) diff --git a/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSOE.cpp b/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSOE.cpp new file mode 100644 index 0000000000..40290b673c --- /dev/null +++ b/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSOE.cpp @@ -0,0 +1,251 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using std::nothrow; + +SymmGeneralizedEigenSOE::SymmGeneralizedEigenSOE(SymmGeneralizedEigenSolver &theSolver, + AnalysisModel &aModel) + : EigenSOE(theSolver, EigenSOE_TAGS_SymmGeneralizedEigenSOE), + size(0), A(0), Asize(0), M(0), Msize(0), + factored(false), theModel(&aModel) +{ + theSolver.setEigenSOE(*this); +} + + +SymmGeneralizedEigenSOE::~SymmGeneralizedEigenSOE() +{ + if (A != 0) + delete [] A; + if (M != 0) + delete [] M; +} + + +int SymmGeneralizedEigenSOE::getNumEqn(void) const +{ + return size; +} + + +int SymmGeneralizedEigenSOE::setSize(Graph &theGraph) +{ + int result = 0; + size = theGraph.getNumVertex(); + + int newSize = size*size; + + // we have to get another space for A + if (newSize > Asize) { + if (A != 0) + delete [] A; + + A = new (nothrow) double[newSize]; + if (A == 0) { + opserr << "WARNING SymmGeneralizedEigenSOE::setSize() - " + << "ran out of memory for A (size,size) (" + << size << ", " << size << ")\n"; + Asize = 0; size = 0; + result= -1; + } + else + Asize = newSize; + } + + // zero the matrix + for (int i=0; i Msize) { + if (M != 0) + delete [] M; + + M = new (nothrow) double[newSize]; + if (M == 0) { + opserr << "WARNING SymmGeneralizedEigenSOE::setSize() - " + << "ran out of memory for M (size,size) (" + << size << ", " << size << ")\n"; + Msize = 0; size = 0; + result= -1; + } + else + Msize = newSize; + } + + // zero the matrix + for (int i=0; igetSolver(); + int solverOK = theSolver->setSize(); + if (solverOK < 0) { + opserr << "WARNING SymmGeneralizedEigenSOE::setSize() - "; + opserr << "solver failed in setSize()\n"; + return solverOK; + } + + return result; +} + + +int SymmGeneralizedEigenSOE::addA(const Matrix &m, const ID &id, double fact) +{ + // check for quick return + if (fact == 0.0) + return 0; + + // check that m and id are of similar size + int idSize = id.Size(); + if (idSize != m.noRows() && idSize != m.noCols()) { + opserr << "SymmGeneralizedEigenSOE::addA() - Matrix and ID not of similar sizes\n"; + return -1; + } + + if (fact == 1.0) { // do not need to multiply + for (int i=0; i= 0) { + double *startColiPtr = A + col*size; + for (int j=0; j= 0 && + row <= col) { // Only add upper + double *APtr = startColiPtr + row; + *APtr += m(j,i); + } + } // for j + } + } // for i + } else { + for (int i=0; i= 0) { + double *startColiPtr = A + col*size; + for (int j=0; j= 0 && + row <= col) { // Only add upper + double *APtr = startColiPtr + row; + *APtr += m(j,i)*fact; + } + } // for j + } + } // for i + } + + return 0; +} + + +int SymmGeneralizedEigenSOE::addM(const Matrix &m, const ID &id, double fact) +{ + // check for quick return + if (fact == 0.0) + return 0; + + // check that m and id are of similar size + int idSize = id.Size(); + if (idSize != m.noRows() && idSize != m.noCols()) { + opserr << "SymmGeneralizedEigenSOE::addM() - Matrix and ID not of similar sizes\n"; + return -1; + } + + if (fact == 1.0) { // do not need to multiply + for (int i=0; i= 0) { + double *startColiPtr = M + col*size; + for (int j=0; j= 0 && + row <= col) { // Only add upper + double *MPtr = startColiPtr + row; + *MPtr += m(j,i); + } + } // for j + } + } // for i + } else { + for (int i=0; i= 0) { + double *startColiPtr = M + col*size; + for (int j=0; j= 0 && + row <= col) { // Only add upper + double *MPtr = startColiPtr + row; + *MPtr += m(j,i)*fact; + } + } // for j + } + } // for i + } + + return 0; +} + + +void SymmGeneralizedEigenSOE::zeroA(void) +{ + double *Aptr = A; + for (int i = 0; i < Asize; i++) + *Aptr++ = 0; + + factored = false; +} + + +void SymmGeneralizedEigenSOE::zeroM(void) +{ + double *Mptr = M; + for (int i = 0; i < Msize; i++) + *Mptr++ = 0; + + factored = false; +} + + +int SymmGeneralizedEigenSOE::sendSelf(int commitTag, Channel &theChannel) +{ + return 0; +} + + +int SymmGeneralizedEigenSOE::recvSelf(int commitTag, Channel &theChannel, + FEM_ObjectBroker &theBroker) +{ + return 0; +} diff --git a/SRC/runtime/runtime/SectionBuilder/reinfBar/ReinfBar.h b/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSOE.h similarity index 59% rename from SRC/runtime/runtime/SectionBuilder/reinfBar/ReinfBar.h rename to SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSOE.h index 845f70a88c..944a710626 100644 --- a/SRC/runtime/runtime/SectionBuilder/reinfBar/ReinfBar.h +++ b/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSOE.h @@ -17,54 +17,49 @@ ** Filip C. Filippou (filippou@ce.berkeley.edu) ** ** ** ** ****************************************************************** */ -// -// File: ReinfBar.h -// -// Written by Remo M. de Souza -// November 1998 +#ifndef SymmGeneralizedEigenSOE_h +#define SymmGeneralizedEigenSOE_h -#ifndef ReinfBar_h -#define ReinfBar_h - +#include #include -class ReinfBar +class AnalysisModel; +class SymmGeneralizedEigenSolver; + +class SymmGeneralizedEigenSOE : public EigenSOE { - public: +public: + SymmGeneralizedEigenSOE(SymmGeneralizedEigenSolver &theSolver, + AnalysisModel &theModel); - ReinfBar(); - ReinfBar(double barArea, int materialID, const Vector &position); - - virtual ~ReinfBar(); - - // edition functions + virtual ~SymmGeneralizedEigenSOE(); - void setDiameter (double barDiameter); - void setArea (double barArea); - void setMaterial (int materialID); - void setPosition (const Vector &position); + virtual int getNumEqn(void) const; + virtual int setSize(Graph &theGraph); - // reinforcing bar inquiring functions - - double getDiameter (void) const; - double getArea (void) const; - int getMaterial (void) const; + virtual int addA(const Matrix &, const ID &, double fact = 1.0); + virtual int addM(const Matrix &, const ID &, double fact = 1.0); - const Vector & getPosition (void) const; + virtual void zeroA(void); + virtual void zeroM(void); - virtual void Print(OPS_Stream &s, int flag =0) const; - friend OPS_Stream &operator<<(OPS_Stream &s, const ReinfBar &reinfBar); - - protected: - - private: - int matID; - double diameter; - double area; - Vector posit; -}; + int sendSelf(int commitTag, Channel &theChannel); + int recvSelf(int commitTag, Channel &theChannel, + FEM_ObjectBroker &theBroker); + friend class SymmGeneralizedEigenSolver; -#endif +protected: +private: + int size; + double *A; + int Asize; + double *M; + int Msize; + bool factored; + AnalysisModel *theModel; +}; + +#endif diff --git a/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSolver.cpp b/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSolver.cpp new file mode 100644 index 0000000000..ae08ab2f75 --- /dev/null +++ b/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSolver.cpp @@ -0,0 +1,437 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef _WIN32 + +extern "C" int DSYGVX(int *ITPYE, char *JOBZ, char *RANGE, char *UPLO, + int *N, double *A, int *LDA, double *B, int *LDB, + double *VL, double *VU, int *IL, int *IU, + double *ABSTOL, int *M, double *W, double *Z, int *LDZ, + double *WORK, int *LWORK, int *IWORK, int *IFAIL, + int *INFO); + +#else + +extern "C" int dsygvx_(int *ITPYE, char *JOBZ, char *RANGE, char *UPLO, + int *N, double *A, int *LDA, double *B, int *LDB, + double *VL, double *VU, int *IL, int *IU, + double *ABSTOL, int *M, double *W, double *Z, int *LDZ, + double *WORK, int *LWORK, int *IWORK, int *IFAIL, + int *INFO); + +#endif + + +SymmGeneralizedEigenSolver::SymmGeneralizedEigenSolver(double m) + : EigenSolver(EigenSOLVER_TAGS_SymmGeneralizedEigenSolver), + theSOE(0), numEigen(0), eigenvalue(0), + eigenvector(0), sortingID(0), eigenV(0), msmall(m) +{ + +} + + +SymmGeneralizedEigenSolver::~SymmGeneralizedEigenSolver() +{ + if (eigenvalue != 0) + delete [] eigenvalue; + if (eigenvector != 0) + delete [] eigenvector; + if (sortingID != 0) + delete [] sortingID; + if (eigenV != 0) + delete eigenV; +} + + +int SymmGeneralizedEigenSolver::solve(int nEigen, bool generalized, bool findSmallest) +{ + if (generalized == false) { + opserr << "SymmGeneralizedEigenSolver::solve() - only solves generalized problem\n"; + return -1; + } + + if (theSOE == 0) { + opserr << "SymmGeneralizedEigenSolver::solve()- " + << " No EigenSOE object has been set yet\n"; + return -1; + } + + // check for quick return + if (nEigen < 1) { + numEigen = 0; + return 0; + } + + // get the number of equations + int n = theSOE->size; + + // set the number of eigenvalues + numEigen = nEigen; + if (numEigen > n) + numEigen = n; + + // Lower and upper range of eigenpairs + int il = 1; + int iu = numEigen; + + // solve K*x = lam*M*x + int itype = 1; + + // compute eigenvalues and eigenvectors + char *jobz = "V"; + + // compute range of eigenvalues + char *range = "I"; + + // upper or lower triangle of A and B + char *uplo = "U"; + + // stiffness matrix data + double *Kptr = theSOE->A; + + double *kCopy = new double[n*n]; + for (int i = 0; i < n*n; i++) + kCopy[i] = Kptr[i]; + + // leading dimension of K + int ldK = n; + + // mass matrix data + double *Mptr = theSOE->M; + + // Check for zero mass on diagonal, add some small mass + int index = 0; + for (int i = 0; i < n; i++) { + if (Mptr[index] == 0.0) + Mptr[index] = Kptr[index]*msmall; + index += n+1; + } + + double *mCopy = new double[n*n]; + for (int i=0; i0 ifail has indices of eigenvectors that failed to converge) + // info=out (0 if success, <0 arg error, >0 failed to converge) + DSYGVX(&itype, jobz, range, uplo, &n, Kptr, &ldK, Mptr, &ldM, + &vl, &vu, &il, &iu, &abstol, + &m, w, z, &ldz, work, &lwork, iwork, ifail, &info); +#else + dsygvx_(&itype, jobz, range, uplo, &n, Kptr, &ldK, Mptr, &ldM, + &vl, &vu, &il, &iu, &abstol, + &m, w, z, &ldz, work, &lwork, iwork, ifail, &info); +#endif + + if (info < 0) { + opserr << "SymmGeneralizedEigenSolver::solve() - invalid argument number " + << -info << " passed to LAPACK dsygvx routine\n"; + return info; + } + + if (info > 0) { + opserr << "SymmGeneralizedEigenSolver::solve() - the LAPACK dsygvx routine " + << "returned error code " << info << endln; + return -info; + } + + theSOE->factored = true; + + for (int i=0; i= 0) { + factor=1.0/sqrt(factor); + + for (int i=0; isort(numEigen, eigenvalue, sortingID); + + for (int i=0; isize; + + if (eigenV == 0 || eigenV->Size() != size) { + if (eigenV != 0) + delete eigenV; + + eigenV = new Vector(size); + if (eigenV == 0 || eigenV->Size() != size) { + opserr << "SymmGeneralizedEigenSolver::setSize() "; + opserr << " - ran out of memory for eigenVector of size "; + opserr << theSOE->size << endln; + return -2; + } + } + + return 0; +} + + +int SymmGeneralizedEigenSolver::setEigenSOE(SymmGeneralizedEigenSOE &thesoe) +{ + theSOE = &thesoe; + + return 0; +} + + +const Vector& SymmGeneralizedEigenSolver::getEigenvector(int mode) +{ + if (mode <= 0 || mode > numEigen) { + opserr << "SymmGeneralizedEigenSolver::getEigenVector() - mode " + << mode << " is out of range (1 - " << numEigen << ")\n"; + eigenV->Zero(); + return *eigenV; + } + + int size = theSOE->size; + int index = size*sortingID[mode-1]; + + if (eigenvector != 0) { + for (int i=0; iZero(); + } + + //opserr << "EIGEN VECTOR: " << *eigenV; + + return *eigenV; + +} + + +double SymmGeneralizedEigenSolver::getEigenvalue(int mode) +{ + if (mode <= 0 || mode > numEigen) { + opserr << "SymmGeneralizedEigenSolver::getEigenvalue() - mode " + << mode << " is out of range (1 - " << numEigen << ")\n"; + return 0.0; + } + + if (eigenvalue != 0) { + return eigenvalue[mode-1]; + } + else { + opserr << "SymmGeneralizedEigenSolver::getEigenvalue() - " + << "eigenvalues not yet computed\n"; + return 0.0; + } +} + + +int SymmGeneralizedEigenSolver::sendSelf(int commitTag, Channel &theChannel) +{ + return 0; +} + + +int SymmGeneralizedEigenSolver::recvSelf(int commitTag, Channel &theChannel, + FEM_ObjectBroker &theBroker) +{ + return 0; +} + + +void SymmGeneralizedEigenSolver::sort(int length, double *x, int *id) +{ + // this is an implementation of shell sort that + // additionally keeps track of the sorting order + + int flag = 1; + int d = length; + int i, idTmp; + double xTmp; + + while (flag || d>1) { + flag = 0; + d = (d+1)/2; + for (i=0; i<(length-d); i++) { + if (x[i+d] < x[i]) { + // swap items at positions i+d and d + xTmp = x[i+d]; idTmp = id[i+d]; + x[i+d] = x[i]; id[i+d] = id[i]; + x[i] = xTmp; id[i] = idTmp; + // indicate that a swap has occurred + flag = 1; + } + } + } + + return; +} diff --git a/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSolver.h b/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSolver.h new file mode 100644 index 0000000000..be2352be54 --- /dev/null +++ b/SRC/system_of_eqn/eigenSOE/SymmGeneralizedEigenSolver.h @@ -0,0 +1,59 @@ +/* ****************************************************************** ** +** OpenSees - Open System for Earthquake Engineering Simulation ** +** Pacific Earthquake Engineering Research Center ** +** ** +** ** +** (C) Copyright 1999, The Regents of the University of California ** +** All Rights Reserved. ** +** ** +** Commercial use of this program without express permission of the ** +** University of California, Berkeley, is strictly prohibited. See ** +** file 'COPYRIGHT' in main directory for information on usage and ** +** redistribution, and for a DISCLAIMER OF ALL WARRANTIES. ** +** ** +** Developed by: ** +** Frank McKenna (fmckenna@ce.berkeley.edu) ** +** Gregory L. Fenves (fenves@ce.berkeley.edu) ** +** Filip C. Filippou (filippou@ce.berkeley.edu) ** +** ** +** ****************************************************************** */ + +#ifndef SymmGenEigenSolver_h +#define SymmGenEigenSolver_h + +#include +#include + +class SymmGeneralizedEigenSolver : public EigenSolver +{ +public: + SymmGeneralizedEigenSolver(double msmall = 1e-10); + virtual ~SymmGeneralizedEigenSolver(); + + virtual int solve(int numEigen, bool generalized, bool findSmallest = true); + virtual int setSize(void); + virtual int setEigenSOE(SymmGeneralizedEigenSOE &theSOE); + + virtual const Vector &getEigenvector(int mode); + virtual double getEigenvalue(int mode); + + int sendSelf(int commitTag, Channel &theChannel); + int recvSelf(int commitTag, Channel &theChannel, + FEM_ObjectBroker &theBroker); + +protected: + +private: + void sort(int length, double *x, int *id); + SymmGeneralizedEigenSOE *theSOE; + int numEigen; + + double *eigenvalue; + double *eigenvector; + int *sortingID; + Vector *eigenV; + + double msmall; // m_ii = k_ii*msmall if m_ii == 0.0 +}; + +#endif diff --git a/SRC/system_of_eqn/linearSOE/CMakeLists.txt b/SRC/system_of_eqn/linearSOE/CMakeLists.txt index 92d4b27beb..d777be4cfa 100644 --- a/SRC/system_of_eqn/linearSOE/CMakeLists.txt +++ b/SRC/system_of_eqn/linearSOE/CMakeLists.txt @@ -30,5 +30,5 @@ add_subdirectory(profileSPD) #add_subdirectory(cg) #add_subdirectory(petsc) #add_subdirectory(mumps) -#add_subdirectory(itpack) +add_subdirectory(itpack) diff --git a/SRC/system_of_eqn/linearSOE/itpack/CMakeLists.txt b/SRC/system_of_eqn/linearSOE/itpack/CMakeLists.txt index 15232f9f8c..7315c18935 100644 --- a/SRC/system_of_eqn/linearSOE/itpack/CMakeLists.txt +++ b/SRC/system_of_eqn/linearSOE/itpack/CMakeLists.txt @@ -7,9 +7,12 @@ target_sources(OPS_SysOfEqn PRIVATE - + ItpackLinSOE.cpp + ItpackLinSolver.cpp + PUBLIC - + ItpackLinSOE.h + ItpackLinSolver.h ) target_include_directories(OPS_SysOfEqn PUBLIC ${CMAKE_CURRENT_LIST_DIR}) diff --git a/SRC/system_of_eqn/linearSOE/itpack/ItpackLinSOE.cpp b/SRC/system_of_eqn/linearSOE/itpack/ItpackLinSOE.cpp index 06430af8b6..9416895d79 100644 --- a/SRC/system_of_eqn/linearSOE/itpack/ItpackLinSOE.cpp +++ b/SRC/system_of_eqn/linearSOE/itpack/ItpackLinSOE.cpp @@ -48,10 +48,10 @@ #include -ItpackLinSOE::ItpackLinSOE(ItpackLinSolver &the_Solver) +ItpackLinSOE::ItpackLinSOE(ItpackLinSolver &the_Solver, bool symm) :LinearSOE(the_Solver, LinSOE_TAGS_ItpackLinSOE), size(0), nnz(0), A(0), B(0), X(0), colA(0), rowStartA(0), - vectX(0), vectB(0), Asize(0), Bsize(0), Aformed(false) + vectX(0), vectB(0), Asize(0), Bsize(0), Aformed(false), symmetric(symm) { the_Solver.setLinearSOE(*this); } @@ -90,7 +90,7 @@ ItpackLinSOE::setSize(Graph &theGraph) } nnz = newNNZ; - opserr << "ItpackLinSOE::setSize - n " << size << " nnz " << nnz << endln; + //opserr << "ItpackLinSOE::setSize - n " << size << " nnz " << nnz << endln; if (nnz > Asize) { // we have to get more space for A and colA @@ -256,6 +256,7 @@ ItpackLinSOE::addA(const Matrix &m, const ID &id, double fact) int endRowLoc = rowStartA[row+1]; for (int j=0; j= 0) { // find place in A using colA for (int k=startRowLoc; k= 0) { // find place in A using colA for (int k=startRowLoc; k #include #include +#include -ItpackLinSolver::ItpackLinSolver(int meth, int iter, double om) +void* OPS_ItpackLinSolver() +{ + int method = 1; + int numData = 1; + + int nArgs = OPS_GetNumRemainingInputArgs(); + if (nArgs == 0) { + opserr << "WARNING Itpack -- no method specified, using JCG" << endln; + } + if (nArgs > 0 && OPS_GetIntInput(&numData,&method) < 0) { + opserr << "WARNING Itpack -- error reading method\n"; + return 0; + } + + int iter = 100; + double omega = 1.0; + bool symmetric = true; + double zeta = 5e-6; + while (OPS_GetNumRemainingInputArgs() > 1) { + const char *arg = OPS_GetString(); + if (strcmp(arg,"-iter") == 0) { + if (OPS_GetIntInput(&numData,&iter) < 0) + return 0; + } + if (strcmp(arg,"-omega") == 0) { + if (OPS_GetDoubleInput(&numData,&omega) < 0) + return 0; + } + if (strcmp(arg,"-symmetric") == 0) { + int symm; + if (OPS_GetIntInput(&numData,&symm) < 0) + return 0; + symmetric = (symm != 0) ? true : false; + } + if (strcmp(arg,"-zeta") == 0) { + if (OPS_GetDoubleInput(&numData,&zeta) < 0) + return 0; + } + } + + ItpackLinSolver *theSolver = new ItpackLinSolver(method, iter, omega, zeta); + return new ItpackLinSOE(*theSolver, symmetric); +} + +ItpackLinSolver::ItpackLinSolver(int meth, int iter, double om, double z) :LinearSOESolver(SOLVER_TAGS_Itpack), theSOE(0), IA(0), JA(0), n(0), iwksp(0), wksp(0), nwksp(0), maxIter(iter), - method(meth), omega(om) + method(meth), omega(om), zeta(z) { } @@ -48,7 +93,7 @@ ItpackLinSolver::ItpackLinSolver() :LinearSOESolver(SOLVER_TAGS_Itpack), theSOE(0), IA(0), JA(0), n(0), iwksp(0), wksp(0), nwksp(0), maxIter(0), - method(0), omega(0.0) + method(0), omega(0.0), zeta(0.0) { } @@ -153,8 +198,8 @@ ItpackLinSolver::setSize(void) for (i = 0; i <= n; i++) IA[i] = iaPtr[i] + 1; - opserr << "ItpackLinSolver::setSize() -- method = " << method - << ", ITMAX = " << maxIter << endln; + //opserr << "ItpackLinSolver::setSize() -- method = " << method + // << ", ITMAX = " << maxIter << endln; return 0; } @@ -288,8 +333,22 @@ ItpackLinSolver::solve(void) // Overwrite default max number of iterations iparm[0] = maxIter; + /* Set convergence tolerance for inexact Newton methods. + * ITPACK stopping criterion: ||Ax-b|| / ||x|| * C < rparm[0] + * For (1+p)-order convergence: rparm[0] < ||b||^(1+p) + * Reference: Dembo et al. (1982) Inexact Newton Methods. + * SIAM Journal on Numerical Analysis, 19(2), 400–408. + * https://doi.org/10.1137/0719025 + */ + double norm_b = theSOE->normRHS(); + double norm_b_squared = norm_b * norm_b; + rparm[0] = (zeta < norm_b_squared) ? zeta : norm_b_squared; + + // Print flag + iparm[1] = 0; + // Sparse matrix storage scheme (0 = symmetric, 1 = nonsymmetric) - iparm[4] = 1; + iparm[4] = theSOE->symmetric ? 0 : 1; double *aPtr = theSOE->A; double *xPtr = theSOE->X; @@ -316,8 +375,8 @@ ItpackLinSolver::solve(void) int nb = theSOE->size-1; // I think this is what it should be // Fill the x vector with zeros as initial guess to solution of Ax=b - //double val = 0.0; - //vfill_(&n, xPtr, &val); + double val = 0.0; + vfill_(&n, xPtr, &val); switch (method) { case ItpackJCG: @@ -360,8 +419,11 @@ ItpackLinSolver::solve(void) if (ier > 0) { opserr << "ItpackLinSolver::solve() -- returned ier = " << ier << endln; + opserr << "Maximum iterations: " << iparm[0] << ", rparm = " << rparm[0] << endln; return -ier; } - else + else { + //opserr << "Converged in " << iparm[0] << " iterations" << endln; return 0; + } } diff --git a/SRC/system_of_eqn/linearSOE/itpack/ItpackLinSolver.h b/SRC/system_of_eqn/linearSOE/itpack/ItpackLinSolver.h index e2e0a7a87b..4ec76b5e64 100644 --- a/SRC/system_of_eqn/linearSOE/itpack/ItpackLinSolver.h +++ b/SRC/system_of_eqn/linearSOE/itpack/ItpackLinSolver.h @@ -55,7 +55,7 @@ class ItpackLinSOE; class ItpackLinSolver : public LinearSOESolver { public: - ItpackLinSolver(int method, int maxIter = 100, double omega = 1.0); + ItpackLinSolver(int method, int maxIter = 100, double omega = 1.0, double zeta = 5e-6); ItpackLinSolver(); virtual ~ItpackLinSolver(); @@ -96,6 +96,9 @@ class ItpackLinSolver : public LinearSOESolver // Parameter for SOR and SSOR fixed omega methods double omega; + + // Parameter for convergence criteria + double zeta; }; #endif diff --git a/SRC/tcl/commands.cpp b/SRC/tcl/commands.cpp index b727b8e577..dc9afebd0a 100644 --- a/SRC/tcl/commands.cpp +++ b/SRC/tcl/commands.cpp @@ -289,8 +289,8 @@ extern void OPS_SetReliabilityDomain(ReliabilityDomain *); #include #ifdef _ITPACK -//#include -//#include +#include +#include #endif #include @@ -3434,21 +3434,21 @@ specifySOE(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv) // theSOE = new UmfpackGenLinSOE(*theSolver, factLVALUE, factorOnce, printTime); theSOE = new UmfpackGenLinSOE(*theSolver); } - -#ifdef _ITPACK -// else if (strcmp(argv[1],"Itpack") == 0) { -// -// // now must determine the type of solver to create from rest of args -// int method = 1; -// if (argc == 3) { -// if (Tcl_GetInt(interp, argv[2], &method) != TCL_OK) -// return TCL_ERROR; -// } -// ItpackLinSolver *theSolver = new ItpackLinSolver(method); -// theSOE = new ItpackLinSOE(*theSolver); -// } -#endif // _ITPACK +#ifdef _ITPACK + else if (strcmp(argv[1],"Itpack") == 0) { + + // now must determine the type of solver to create from rest of args + int method = 1; + if (argc == 3) { + if (Tcl_GetInt(interp, argv[2], &method) != TCL_OK) + return TCL_ERROR; + } + ItpackLinSolver *theSolver = new ItpackLinSolver(method); + theSOE = new ItpackLinSOE(*theSolver); + } +#endif + else if (strcmp(argv[1],"FullGeneral") == 0) { // now must determine the type of solver to create from rest of args FullGenLinLapackSolver *theSolver = new FullGenLinLapackSolver(); @@ -7315,7 +7315,7 @@ nodeDOFs(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv) int tag; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { - opserr << "WARNING nodeMass nodeTag? nodeDOF? \n"; + opserr << "WARNING nodeDOFs nodeTag? nodeDOF? \n"; return TCL_ERROR; } @@ -7345,21 +7345,24 @@ nodeDOFs(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv) int nodeMass(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv) { - if (argc < 3) { - opserr << "WARNING want - nodeMass nodeTag? nodeDOF?\n"; + if (argc < 2) { + opserr << "WARNING want - nodeMass nodeTag? \n"; return TCL_ERROR; } - int tag, dof; + int tag; + int dof = -1; if (Tcl_GetInt(interp, argv[1], &tag) != TCL_OK) { opserr << "WARNING nodeMass nodeTag? nodeDOF? \n"; return TCL_ERROR; - } - if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { - opserr << "WARNING nodeMass nodeTag? nodeDOF? \n"; - return TCL_ERROR; - } + } + + if (argc == 3) + if (Tcl_GetInt(interp, argv[2], &dof) != TCL_OK) { + opserr << "WARNING nodeMass nodeTag? nodeDOF? \n"; + return TCL_ERROR; + } char buffer[40]; @@ -7369,14 +7372,24 @@ nodeMass(ClientData clientData, Tcl_Interp *interp, int argc, TCL_Char **argv) return TCL_ERROR; } int numDOF = theNode->getNumberDOF(); - if (dof < 1 || dof > numDOF) { - opserr << "WARNING nodeMass dof " << dof << " not in range" << endln; - return TCL_ERROR; - } - else { - const Matrix &mass = theNode->getMass(); - sprintf(buffer, "%35.20f", mass(dof-1,dof-1)); - Tcl_AppendResult(interp, buffer, NULL); + if (dof == -1) { + const Matrix &mass = theNode->getMass(); + for (int i =0; i numDOF) { + opserr << "WARNING nodeMass dof " << dof << " not in range" << endln; + return TCL_ERROR; + } + else { + const Matrix &mass = theNode->getMass(); + + sprintf(buffer, "%35.20f", mass(dof-1,dof-1)); + Tcl_AppendResult(interp, buffer, NULL); + } } return TCL_OK; diff --git a/SRC/utility/Unroll.h b/SRC/utility/Unroll.h new file mode 100644 index 0000000000..d7aecb2c8c --- /dev/null +++ b/SRC/utility/Unroll.h @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// xara +// https://xara.so +// +//===----------------------------------------------------------------------===// +// +// Copyright (c) 2025, Claudio M. Perez +// All rights reserved. No warranty, explicit or implicit, is provided. +// +// This source code is licensed under the BSD 2-Clause License. +// See LICENSE file or https://opensource.org/licenses/BSD-2-Clause +// +//===----------------------------------------------------------------------===// +#pragma once +#include +#include + +namespace OpenSees { +namespace +{ + template + struct num { static constexpr std::size_t value = N; }; + + // Helper that unpacks the index_sequence into calls to func + template + [[gnu::always_inline]] inline constexpr void + repeat_impl(F func, std::index_sequence) noexcept + { + (func(num{}), ...); + } + + // Helper that unpacks the index_sequence into calls to func, offset by Start + template + [[gnu::always_inline]] inline constexpr void + unroll_impl(F func, std::index_sequence) noexcept + { + (func(num{}), ...); + } +} + +#if 0 // __cplusplus >= 202002L +template +[[gnu::always_inline]] inline constexpr void +Repeat(F func) noexcept +{ + // Lambda with templated parameter pack (C++20 feature) + ([](F func, std::index_sequence){ + (func(num{}), ...); + })(func, std::make_index_sequence{}); +} +#else +template +[[gnu::always_inline]] inline constexpr void +Repeat(F func) noexcept +{ + repeat_impl(func, std::make_index_sequence{}); +} +#endif + +template +inline constexpr void +Unroll(F func) noexcept +{ + static_assert(Stop >= Start, "Stop must be greater than or equal to Start"); + constexpr std::size_t N = Stop - Start; + unroll_impl(func, std::make_index_sequence{}); +} + +} // namespace OpenSees \ No newline at end of file diff --git a/Win32/proj/element/element.vcxproj b/Win32/proj/element/element.vcxproj index 6564e73d3e..fe65c81d5d 100644 --- a/Win32/proj/element/element.vcxproj +++ b/Win32/proj/element/element.vcxproj @@ -149,7 +149,7 @@ - + @@ -183,6 +183,7 @@ + @@ -438,7 +439,7 @@ - + @@ -472,6 +473,7 @@ + diff --git a/Win32/proj/element/element.vcxproj.filters b/Win32/proj/element/element.vcxproj.filters index 9d5abcfdf8..2a9b740af7 100644 --- a/Win32/proj/element/element.vcxproj.filters +++ b/Win32/proj/element/element.vcxproj.filters @@ -716,7 +716,7 @@ mvlem - + mvlem @@ -966,7 +966,7 @@ PML - PML + PML PML @@ -977,6 +977,9 @@ PML + + PML + mvlem @@ -1501,7 +1504,7 @@ mvlem - + mvlem @@ -1755,13 +1758,16 @@ PML - + PML PML + + PML + mvlem diff --git a/Win32/proj/material/material.vcxproj b/Win32/proj/material/material.vcxproj index 5a1b858a31..83f712c921 100644 --- a/Win32/proj/material/material.vcxproj +++ b/Win32/proj/material/material.vcxproj @@ -134,6 +134,7 @@ + @@ -195,6 +196,7 @@ + @@ -563,6 +565,8 @@ + + @@ -625,6 +629,7 @@ + diff --git a/Win32/proj/material/material.vcxproj.filters b/Win32/proj/material/material.vcxproj.filters index 115843241c..e6a9760087 100644 --- a/Win32/proj/material/material.vcxproj.filters +++ b/Win32/proj/material/material.vcxproj.filters @@ -151,6 +151,9 @@ uniaxial + + uniaxial + uniaxial @@ -1349,6 +1352,9 @@ nD\UWmaterials + + nD\UWmaterials + nD @@ -1432,6 +1438,9 @@ uniaxial + + uniaxial + uniaxial @@ -2570,6 +2579,9 @@ nD\UWmaterials + + nD\UWmaterials + nD diff --git a/Win32/proj/recorder/recorder.vcxproj b/Win32/proj/recorder/recorder.vcxproj index 95dd6d244c..cfac6b5c85 100644 --- a/Win32/proj/recorder/recorder.vcxproj +++ b/Win32/proj/recorder/recorder.vcxproj @@ -131,6 +131,7 @@ + @@ -161,6 +162,7 @@ + diff --git a/Win32/proj/recorder/recorder.vcxproj.filters b/Win32/proj/recorder/recorder.vcxproj.filters index 2c1d755b37..db3aaba4f9 100644 --- a/Win32/proj/recorder/recorder.vcxproj.filters +++ b/Win32/proj/recorder/recorder.vcxproj.filters @@ -95,6 +95,9 @@ Source Files + + Source Files + Source Files @@ -181,6 +184,9 @@ Header Files + + Header Files + Header Files diff --git a/Win64/proj/domain/domain.vcxproj b/Win64/proj/domain/domain.vcxproj index c22b57615a..b6bae2e71e 100644 --- a/Win64/proj/domain/domain.vcxproj +++ b/Win64/proj/domain/domain.vcxproj @@ -245,6 +245,7 @@ + @@ -345,6 +346,7 @@ + @@ -392,4 +394,4 @@ - \ No newline at end of file + diff --git a/Win64/proj/domain/domain.vcxproj.filters b/Win64/proj/domain/domain.vcxproj.filters index d73fba6d18..a14984f79e 100644 --- a/Win64/proj/domain/domain.vcxproj.filters +++ b/Win64/proj/domain/domain.vcxproj.filters @@ -141,6 +141,9 @@ load\beam + + load\beam + load\beam @@ -440,6 +443,9 @@ load\beam + + load\beam + load\beam @@ -615,4 +621,4 @@ timeSeries - \ No newline at end of file + diff --git a/Win64/proj/element/element.vcxproj b/Win64/proj/element/element.vcxproj index f16d7ded2a..08938d509a 100644 --- a/Win64/proj/element/element.vcxproj +++ b/Win64/proj/element/element.vcxproj @@ -294,6 +294,7 @@ + @@ -599,6 +600,7 @@ + diff --git a/Win64/proj/element/element.vcxproj.filters b/Win64/proj/element/element.vcxproj.filters index a5e62fa69e..f88b58fd3e 100644 --- a/Win64/proj/element/element.vcxproj.filters +++ b/Win64/proj/element/element.vcxproj.filters @@ -105,6 +105,7 @@ + @@ -407,6 +408,7 @@ + diff --git a/Win64/proj/material/material.vcxproj b/Win64/proj/material/material.vcxproj index 31d36e1e86..c532b2d600 100644 --- a/Win64/proj/material/material.vcxproj +++ b/Win64/proj/material/material.vcxproj @@ -239,6 +239,7 @@ + @@ -294,6 +295,7 @@ + @@ -315,6 +317,7 @@ + @@ -717,6 +720,7 @@ + @@ -761,6 +765,7 @@ + @@ -1102,4 +1107,4 @@ - \ No newline at end of file + diff --git a/Win64/proj/material/material.vcxproj.filters b/Win64/proj/material/material.vcxproj.filters index 59300cae3c..dd87d7fbb4 100644 --- a/Win64/proj/material/material.vcxproj.filters +++ b/Win64/proj/material/material.vcxproj.filters @@ -160,6 +160,9 @@ uniaxial + + uniaxial + uniaxial @@ -1349,6 +1352,9 @@ nD\UWmaterials + + nD\UWmaterials + nD @@ -1526,6 +1532,9 @@ uniaxial + + uniaxial + nD\OrthotropicRotatingAngleConcreteT2DMaterial01 @@ -1600,6 +1609,9 @@ uniaxial + + uniaxial + uniaxial @@ -2726,6 +2738,9 @@ nD\UWmaterials + + nD\UWmaterials + nD @@ -2841,4 +2856,4 @@ nD - \ No newline at end of file + diff --git a/Win64/proj/recorder/recorder.vcxproj b/Win64/proj/recorder/recorder.vcxproj index 1bed981d4d..2846fd1f7f 100644 --- a/Win64/proj/recorder/recorder.vcxproj +++ b/Win64/proj/recorder/recorder.vcxproj @@ -217,6 +217,7 @@ + @@ -248,6 +249,7 @@ + diff --git a/Win64/proj/recorder/recorder.vcxproj.filters b/Win64/proj/recorder/recorder.vcxproj.filters index e524034c08..03e6cfba09 100644 --- a/Win64/proj/recorder/recorder.vcxproj.filters +++ b/Win64/proj/recorder/recorder.vcxproj.filters @@ -95,6 +95,9 @@ Source Files + + Source Files + Source Files @@ -184,6 +187,9 @@ Header Files + + Header Files + Header Files diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000000..9b5cfb2870 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,29 @@ +## Test Scripts + +A directory of verification tests using OpenSeesPy. + +### How to Run + +Run locally with `pytest` + +```console +pytest -v +``` + +### Import Statements + +So that the tests will work with the latest source code on GitHub +Actions, first try a local import, then use the standard pip install if +the local library is not found. + +```python +try: + import opensees as ops +except ModuleNotFoundError: + import openseespy.opensees as ops + +``` + +### Contributing + +Add test scripts to this folder via a PR. diff --git a/tests/test_force-beam-column.py b/tests/test_force-beam-column.py new file mode 100644 index 0000000000..3358507a91 --- /dev/null +++ b/tests/test_force-beam-column.py @@ -0,0 +1,49 @@ +try: + import opensees as ops +except ModuleNotFoundError: + import openseespy.opensees as ops +from math import isclose + +L = 48 +E = 29000 +A = 20 +I = 800 +P = 10 + +def end_loaded_cantilever(): + ops.wipe() + ops.model('basic','-ndm',2,'-ndf',3) + + ops.node(1,0,0); ops.fix(1,1,1,1) + ops.node(2,L,0) + + ops.section('Elastic',1,E,A,I) + ops.beamIntegration('Lobatto',1,1,3) + + ops.geomTransf('Linear',1) + + ops.element('forceBeamColumn',1,1,2,1,1) + + ops.timeSeries('Constant',1) + ops.pattern('Plain',1,1) + ops.load(2,0,P,0) + + ops.analysis('Static','-noWarnings') + ops.analyze(1) + ops.reactions() + +def test_deflection(): + end_loaded_cantilever() + assert isclose(ops.nodeDisp(2,2),P*L**3/(3*E*I)) + +def test_rotation(): + end_loaded_cantilever() + assert isclose(ops.nodeDisp(2,3),P*L**2/(2*E*I)) + +def test_force(): + end_loaded_cantilever() + assert isclose(ops.nodeReaction(1,2),-P) + +def test_moment(): + end_loaded_cantilever() + assert isclose(ops.nodeReaction(1,3),-P*L) diff --git a/tests/test_particle-dynamics.py b/tests/test_particle-dynamics.py new file mode 100644 index 0000000000..c742805068 --- /dev/null +++ b/tests/test_particle-dynamics.py @@ -0,0 +1,45 @@ +try: + import opensees as ops +except ModuleNotFoundError: + import openseespy.opensees as ops +from math import isclose + +m = 1.0 +F = 1.0 +t = 1.0 + +a = F/m + +def define_model(): + ops.wipe() + ops.model('basic','-ndm',1,'-ndf',1) + + ops.node(1,0); ops.mass(1,m) + + ops.timeSeries('Linear',1) + ops.pattern('Plain',1,1) + ops.load(1,F) + + ops.integrator('Newmark',0.5,1.0/6) + ops.analysis('Transient','-noWarnings') + Nsteps = 10 + dt = t/Nsteps + ops.analyze(Nsteps,dt) + +def test_acceleration(): + define_model() + + assert isclose(ops.nodeAccel(1,1),a) + +def test_velocity(): + define_model() + + assert isclose(ops.nodeVel(1,1),0.5*a*t) + +def test_displacement(): + define_model() + + assert isclose(ops.nodeDisp(1,1),a*t*t/6) + +if __name__ == '__main__': + test_displacement()