diff --git a/.gitignore b/.gitignore index 1634702f8b..0b6dd4368e 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ vs-build/ .vscode .atom .fortls +.devcontainer # backup files *.asv ~$*.xlsx diff --git a/docs/source/user/subdyn/examples/OC4_Jacket_SD_Input.dat b/docs/source/user/subdyn/examples/OC4_Jacket_SD_Input.dat index 67f6f15ceb..43111b830f 100644 --- a/docs/source/user/subdyn/examples/OC4_Jacket_SD_Input.dat +++ b/docs/source/user/subdyn/examples/OC4_Jacket_SD_Input.dat @@ -1,19 +1,19 @@ ------------ SubDyn MultiMember Support Structure Input File ------------ +----------- SubDyn MultiMember Support Structure Input File --------------------------- OC4 'Jacket' SubStructure Input File. The grouted connection is simulated with an equivalent tubular beam of enhanced properties. RRD 10/15/2013 --------------------------- SIMULATION CONTROL --------------------------------- +-------------------------- SIMULATION CONTROL ----------------------------------------- False Echo - Echo input data to ".SD.ech" (flag) "DEFAULT" SDdeltaT - Local Integration Step. If "default", the glue-code integration step will be used. 3 IntMethod - Integration Method [1/2/3/4 = RK4/AB4/ABM4/AM2]. True SttcSolve - Solve dynamics about static equilibrium point True GuyanLoadCorrection - Include extra moment from lever arm at interface and rotate FEM for floating. --------------------- FEA and CRAIG-BAMPTON PARAMETERS--------------------------- +-------------------- FEA and CRAIG-BAMPTON PARAMETERS --------------------------------- 3 FEMMod - FEM switch: element model in the FEM. [1= Euler-Bernoulli(E-B); 2=Tapered E-B (unavailable); 3= 2-node Timoshenko; 4= 2-node tapered Timoshenko (unavailable)] 2 NDiv - Number of sub-elements per member True CBMod - [T/F] If True perform C-B reduction, else full FEM dofs will be retained. If True, select Nmodes to retain in C-B reduced system. 8 Nmodes - Number of internal modes to retain (ignored if CBMod=False). If Nmodes=0 --> Guyan Reduction. 1 JDampings - Damping Ratios for each retained mode (% of critical) If Nmodes>0, list Nmodes structural damping ratios for each retained mode (% of critical), or a single damping ratio to be applied to all retained modes. (last entered value will be used for all remaining modes). 0 GuyanDampMod - Guyan damping {0=none, 1=Rayleigh Damping, 2=user specified 6x6 matrix} - 0.000, 0.000 RayleighDamp - Mass and stiffness proportional damping coefficients (Rayleigh Damping) [only if GuyanDampMod=1] + 0.000, 0.000 RayleighDamp - Mass and stiffness proportional damping coefficients (Rayleigh Damping) [only if GuyanDampMod=1] 6 GuyanDampSize - Guyan damping matrix (6x6) [only if GuyanDampMod=2] 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 @@ -21,9 +21,9 @@ True CBMod - [T/F] If True perform C-B reduction, else full FE 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 0.0000e+00 ----- STRUCTURE JOINTS: joints connect structure members (~Hydrodyn Input File)--- +---- STRUCTURE JOINTS: joints connect structure members (~Hydrodyn Input File) -------- 64 NJoints - Number of joints (-) -JointID JointXss JointYss JointZss JointType JointDirX JointDirY JointDirZ JointStiff +JointID JointXss JointYss JointZss JointType JointDirX JointDirY JointDirZ JointStiff ![Coordinates of Member joints in SS-Coordinate System][JointType={1:cantilever, 2:universal joint, 3:revolute joint, 4:spherical joint}] (-) (m) (m) (m) (-) (-) (-) (-) (Nm/rad) 1 6.00000 6.00000 -45.50000 1 0.0 0.0 0.0 0.0 2 6.00000 6.00000 -45.00000 1 0.0 0.0 0.0 0.0 @@ -91,15 +91,15 @@ JointID JointXss JointYss JointZss Join 64 -6.00000 6.00000 -50.00100 1 0.0 0.0 0.0 0.0 ------------------- BASE REACTION JOINTS: 1/0 for Locked/Free DOF @ each Reaction Node --------------------- 4 NReact - Number of Joints with reaction forces; be sure to remove all rigid motion DOFs of the structure (else det([K])=[0]) -RJointID RctTDXss RctTDYss RctTDZss RctRDXss RctRDYss RctRDZss SSIfile [Global Coordinate System] - (-) (flag) (flag) (flag) (flag) (flag) (flag) (string) +RJointID RctTDXss RctTDYss RctTDZss RctRDXss RctRDYss RctRDZss SSIfile ![Global Coordinate System] + (-) (flag) (flag) (flag) (flag) (flag) (flag) (string) 61 1 1 1 1 1 1 "OC4_Jacket_SD_SSI.txt" 62 1 1 1 1 1 1 "OC4_Jacket_SD_SSI.txt" 63 1 1 1 1 1 1 "OC4_Jacket_SD_SSI.txt" 64 1 1 1 1 1 1 "OC4_Jacket_SD_SSI.txt" ------- INTERFACE JOINTS: 1/0 for Locked (to the TP)/Free DOF @each Interface Joint (only Locked-to-TP implemented thus far (=rigid TP)) --------- 8 NInterf - Number of interface joints locked to the Transition Piece (TP): be sure to remove all rigid motion dofs -IJointID ItfTDXss ItfTDYss ItfTDZss ItfRDXss ItfRDYss ItfRDZss [Global Coordinate System] +IJointID ItfTDXss ItfTDYss ItfTDZss ItfRDXss ItfRDYss ItfRDZss ![Global Coordinate System] (-) (flag) (flag) (flag) (flag) (flag) (flag) 24 1 1 1 1 1 1 28 1 1 1 1 1 1 @@ -109,124 +109,124 @@ IJointID ItfTDXss ItfTDYss ItfTDZss ItfRDXss ItfRDYss ItfRDZss 54 1 1 1 1 1 1 55 1 1 1 1 1 1 56 1 1 1 1 1 1 ------------------------------------ MEMBERS -------------------------------------- - 112 NMembers - Number of frame members -MemberID MJointID1 MJointID2 MPropSetID1 MPropSetID2 MType COSMID +----------------------------------- MEMBERS ------------------------------------------- + 112 NMembers - Number of members (-) +MemberID MJointID1 MJointID2 MPropSetID1 MPropSetID2 MType COSMID ![MType={1:beam circ., 2:cable, 3:rigid, 4:beam arb.}. COMSID={-1:none}] (-) (-) (-) (-) (-) (-) (-) - 1 1 2 2 2 1 - 2 2 3 2 2 1 - 3 3 4 2 2 1 - 4 4 5 2 2 1 - 5 6 7 2 2 1 - 6 7 8 2 2 1 - 7 8 9 2 2 1 - 8 9 10 2 2 1 - 9 11 12 2 2 1 - 10 12 13 2 2 1 - 11 13 14 2 2 1 - 12 14 15 2 2 1 - 13 16 17 2 2 1 - 14 17 18 2 2 1 - 15 18 19 2 2 1 - 16 19 20 2 2 1 - 17 5 21 3 3 1 - 18 21 22 3 3 1 - 19 22 23 3 3 1 - 20 23 24 3 3 1 - 21 10 25 3 3 1 - 22 25 26 3 3 1 - 23 26 27 3 3 1 - 24 27 28 3 3 1 - 25 15 29 3 3 1 - 26 29 30 3 3 1 - 27 30 31 3 3 1 - 28 31 32 3 3 1 - 29 20 33 3 3 1 - 30 33 34 3 3 1 - 31 34 35 3 3 1 - 32 35 36 3 3 1 - 33 8 3 1 1 1 - 34 13 8 1 1 1 - 35 13 18 1 1 1 - 36 18 3 1 1 1 - 37 4 37 1 1 1 - 38 37 20 1 1 1 - 39 19 37 1 1 1 - 40 37 5 1 1 1 - 41 9 38 1 1 1 - 42 38 15 1 1 1 - 43 14 38 1 1 1 - 44 38 10 1 1 1 - 45 4 39 1 1 1 - 46 39 10 1 1 1 - 47 9 39 1 1 1 - 48 39 5 1 1 1 - 49 19 40 1 1 1 - 50 40 15 1 1 1 - 51 14 40 1 1 1 - 52 40 20 1 1 1 - 53 5 41 1 1 1 - 54 41 33 1 1 1 - 55 20 41 1 1 1 - 56 41 21 1 1 1 - 57 10 42 1 1 1 - 58 42 29 1 1 1 - 59 15 42 1 1 1 - 60 42 25 1 1 1 - 61 5 43 1 1 1 - 62 43 25 1 1 1 - 63 10 43 1 1 1 - 64 43 21 1 1 1 - 65 20 44 1 1 1 - 66 44 29 1 1 1 - 67 15 44 1 1 1 - 68 44 33 1 1 1 - 69 21 45 1 1 1 - 70 45 34 1 1 1 - 71 33 45 1 1 1 - 72 45 22 1 1 1 - 73 25 46 1 1 1 - 74 46 30 1 1 1 - 75 29 46 1 1 1 - 76 46 26 1 1 1 - 77 21 47 1 1 1 - 78 47 26 1 1 1 - 79 25 47 1 1 1 - 80 47 22 1 1 1 - 81 33 48 1 1 1 - 82 48 30 1 1 1 - 83 29 48 1 1 1 - 84 48 34 1 1 1 - 85 22 49 1 1 1 - 86 49 35 1 1 1 - 87 34 49 1 1 1 - 88 49 23 1 1 1 - 89 26 50 1 1 1 - 90 50 31 1 1 1 - 91 30 50 1 1 1 - 92 50 27 1 1 1 - 93 22 51 1 1 1 - 94 51 27 1 1 1 - 95 26 51 1 1 1 - 96 51 23 1 1 1 - 97 34 52 1 1 1 - 98 52 31 1 1 1 - 99 30 52 1 1 1 - 100 52 35 1 1 1 - 101 24 53 4 4 1 - 102 28 54 4 4 1 - 103 32 56 4 4 1 - 104 36 55 4 4 1 - 105 58 1 5 5 1 - 106 57 16 5 5 1 - 107 60 6 5 5 1 - 108 59 11 5 5 1 - 109 62 58 6 6 1 - 110 61 57 6 6 1 - 111 64 60 6 6 1 - 112 63 59 6 6 1 ------------------- MEMBER X-SECTION PROPERTY data 1/2 [isotropic material for now: use this table for circular-tubular elements] ------------------------ - 6 NPropSets - Number of structurally unique x-sections (i.e. how many groups of X-sectional properties are utilized throughout all of the members) + 1 1 2 2 2 1 -1 + 2 2 3 2 2 1 -1 + 3 3 4 2 2 1 -1 + 4 4 5 2 2 1 -1 + 5 6 7 2 2 1 -1 + 6 7 8 2 2 1 -1 + 7 8 9 2 2 1 -1 + 8 9 10 2 2 1 -1 + 9 11 12 2 2 1 -1 + 10 12 13 2 2 1 -1 + 11 13 14 2 2 1 -1 + 12 14 15 2 2 1 -1 + 13 16 17 2 2 1 -1 + 14 17 18 2 2 1 -1 + 15 18 19 2 2 1 -1 + 16 19 20 2 2 1 -1 + 17 5 21 3 3 1 -1 + 18 21 22 3 3 1 -1 + 19 22 23 3 3 1 -1 + 20 23 24 3 3 1 -1 + 21 10 25 3 3 1 -1 + 22 25 26 3 3 1 -1 + 23 26 27 3 3 1 -1 + 24 27 28 3 3 1 -1 + 25 15 29 3 3 1 -1 + 26 29 30 3 3 1 -1 + 27 30 31 3 3 1 -1 + 28 31 32 3 3 1 -1 + 29 20 33 3 3 1 -1 + 30 33 34 3 3 1 -1 + 31 34 35 3 3 1 -1 + 32 35 36 3 3 1 -1 + 33 8 3 1 1 1 -1 + 34 13 8 1 1 1 -1 + 35 13 18 1 1 1 -1 + 36 18 3 1 1 1 -1 + 37 4 37 1 1 1 -1 + 38 37 20 1 1 1 -1 + 39 19 37 1 1 1 -1 + 40 37 5 1 1 1 -1 + 41 9 38 1 1 1 -1 + 42 38 15 1 1 1 -1 + 43 14 38 1 1 1 -1 + 44 38 10 1 1 1 -1 + 45 4 39 1 1 1 -1 + 46 39 10 1 1 1 -1 + 47 9 39 1 1 1 -1 + 48 39 5 1 1 1 -1 + 49 19 40 1 1 1 -1 + 50 40 15 1 1 1 -1 + 51 14 40 1 1 1 -1 + 52 40 20 1 1 1 -1 + 53 5 41 1 1 1 -1 + 54 41 33 1 1 1 -1 + 55 20 41 1 1 1 -1 + 56 41 21 1 1 1 -1 + 57 10 42 1 1 1 -1 + 58 42 29 1 1 1 -1 + 59 15 42 1 1 1 -1 + 60 42 25 1 1 1 -1 + 61 5 43 1 1 1 -1 + 62 43 25 1 1 1 -1 + 63 10 43 1 1 1 -1 + 64 43 21 1 1 1 -1 + 65 20 44 1 1 1 -1 + 66 44 29 1 1 1 -1 + 67 15 44 1 1 1 -1 + 68 44 33 1 1 1 -1 + 69 21 45 1 1 1 -1 + 70 45 34 1 1 1 -1 + 71 33 45 1 1 1 -1 + 72 45 22 1 1 1 -1 + 73 25 46 1 1 1 -1 + 74 46 30 1 1 1 -1 + 75 29 46 1 1 1 -1 + 76 46 26 1 1 1 -1 + 77 21 47 1 1 1 -1 + 78 47 26 1 1 1 -1 + 79 25 47 1 1 1 -1 + 80 47 22 1 1 1 -1 + 81 33 48 1 1 1 -1 + 82 48 30 1 1 1 -1 + 83 29 48 1 1 1 -1 + 84 48 34 1 1 1 -1 + 85 22 49 1 1 1 -1 + 86 49 35 1 1 1 -1 + 87 34 49 1 1 1 -1 + 88 49 23 1 1 1 -1 + 89 26 50 1 1 1 -1 + 90 50 31 1 1 1 -1 + 91 30 50 1 1 1 -1 + 92 50 27 1 1 1 -1 + 93 22 51 1 1 1 -1 + 94 51 27 1 1 1 -1 + 95 26 51 1 1 1 -1 + 96 51 23 1 1 1 -1 + 97 34 52 1 1 1 -1 + 98 52 31 1 1 1 -1 + 99 30 52 1 1 1 -1 + 100 52 35 1 1 1 -1 + 101 24 53 4 4 1 -1 + 102 28 54 4 4 1 -1 + 103 32 56 4 4 1 -1 + 104 36 55 4 4 1 -1 + 105 58 1 5 5 1 -1 + 106 57 16 5 5 1 -1 + 107 60 6 5 5 1 -1 + 108 59 11 5 5 1 -1 + 109 62 58 6 6 1 -1 + 110 61 57 6 6 1 -1 + 111 64 60 6 6 1 -1 + 112 63 59 6 6 1 -1 +------------------ CIRCULAR BEAM CROSS-SECTION PROPERTIES ----------------------------- + 6 NPropSets - Number of structurally unique circular cross-sections PropSetID YoungE ShearG MatDens XsecD XsecT (-) (N/m2) (N/m2) (kg/m3) (m) (m) 1 2.10000e+11 8.07690e+10 7850.00 0.800000 0.020000 @@ -235,32 +235,32 @@ PropSetID YoungE ShearG MatDens XsecD X 4 2.10000e+11 8.07690e+10 7850.00 1.200000 0.040000 5 2.10000e+11 8.07690e+10 3339.12 2.082000 0.491000 6 2.10000e+11 8.07690e+10 7850.00 2.082000 0.060000 ------------------- MEMBER X-SECTION PROPERTY data 2/2 [isotropic material for now: use this table if any section other than circular, however provide COSM(i,j) below] ------------------------ - 0 NXPropSets - Number of structurally unique non-circular x-sections (if 0 the following table is ignored) +----------------- ARBITRARY BEAM CROSS-SECTION PROPERTIES ----------------------------- + 0 NXPropSets - Number of structurally unique non-circular cross-sections (if 0 the following table is ignored) PropSetID YoungE ShearG MatDens XsecA XsecAsx XsecAsy XsecJxx XsecJyy XsecJ0 (-) (N/m2) (N/m2) (kg/m3) (m2) (m2) (m2) (m4) (m4) (m4) --------------------------- CABLE PROPERTIES ------------------------------------- +-------------------------- CABLE PROPERTIES ------------------------------------------- 0 NCablePropSets - Number of cable cable properties -PropSetID EA MatDens T0 - (-) (N) (kg/m) (N) ------------------------ RIGID LINK PROPERTIES ------------------------------------ +PropSetID EA MatDens T0 CtrlChannel + (-) (N) (kg/m) (N) (-) +----------------------- RIGID LINK PROPERTIES ----------------------------------------- 0 NRigidPropSets - Number of rigid link properties PropSetID MatDens - (-) (kg/m) ----------------------- MEMBER COSINE MATRICES COSM(i,j) ------------------------ + (-) (kg/m) +---------------------- MEMBER COSINE MATRICES COSM(i,j) ------------------------------- 0 NCOSMs - Number of unique cosine matrices (i.e., of unique member alignments including principal axis rotations); ignored if NXPropSets=0 or 9999 in any element below COSMID COSM11 COSM12 COSM13 COSM21 COSM22 COSM23 COSM31 COSM32 COSM33 (-) (-) (-) (-) (-) (-) (-) (-) (-) (-) ------------------------ JOINT ADDITIONAL CONCENTRATED MASSES-------------------------- 0 NCmass - Number of joints with concentrated masses; Global Coordinate System -CMJointID JMass JMXX JMYY JMZZ JMXY JMXZ JMYZ MCGX MCGY MCGZ +CMJointID JMass JMXX JMYY JMZZ JMXY JMXZ JMYZ MCGX MCGY MCGZ (-) (kg) (kg*m^2) (kg*m^2) (kg*m^2) (kg*m^2) (kg*m^2) (kg*m^2) (m) (m) (m) ----------------------------- OUTPUT: SUMMARY & OUTFILE ------------------------------ -True SumPrint - Output a Summary File (flag).It contains: matrices K,M and C-B reduced M_BB, M-BM, K_BB, K_MM(OMG^2), PHI_R, PHI_L. It can also contain COSMs if requested. +---------------------------- OUTPUT: SUMMARY & OUTFILE -------------------------------- +True SumPrint - Output a Summary File (flag) 0 OutCBModes - Output Guyan and Craig-Bampton modes {0: No output, 1: JSON output}, (flag) 0 OutFEMModes - Output first 30 FEM modes {0: No output, 1: JSON output} (flag) False OutCOSM - Output cosine matrices with the selected output member forces (flag) -False OutAll - [T/F] Output all members' end forces +False OutAll - [T/F] Output all members' end forces 1 OutSwtch - [1/2/3] Output requested channels to: 1=.SD.out; 2=.out (generated by FAST); 3=both files. True TabDelim - Generate a tab-delimited output in the .SD.out file 1 OutDec - Decimation of output in the .SD.out file @@ -268,7 +268,7 @@ True TabDelim - Generate a tab-delimited output in the "A11" OutSFmt - Output format for header strings in the .SD.out file ------------------------- MEMBER OUTPUT LIST ------------------------------------------ 8 NMOutputs - Number of members whose forces/displacements/velocities/accelerations will be output (-) [Must be <= 9]. -MemberID NOutCnt NodeCnt [NOutCnt=how many nodes to get output for [< 10]; NodeCnt are local ordinal numbers from the start of the member, and must be >=1 and <= NDiv+1] If NMOutputs=0 leave blank as well. +MemberID NOutCnt NodeCnt ![NOutCnt=how many nodes to get output for [< 10]; NodeCnt are local ordinal numbers from the start of the member, and must be >=1 and <= NDiv+1] If NMOutputs=0 leave blank as well. (-) (-) (-) 22 1 3 30 1 3 diff --git a/docs/source/user/subdyn/input_files.rst b/docs/source/user/subdyn/input_files.rst index f5a7f06523..808ce67f8d 100644 --- a/docs/source/user/subdyn/input_files.rst +++ b/docs/source/user/subdyn/input_files.rst @@ -427,8 +427,9 @@ A member is one of the three following types (see :numref:`SD_FEM`): - Rigid link (*MType=3*) -**COSMID** refers to the IDs of the members’ cosine matrices for -noncircular members; the current release ignores this column. +**COSMID** refers to the IDs of the members' cosine matrices for +noncircular members; the current release uses SubDyn's default direction + cosine convention if it's not present or when COSMID values are -1. An example of member table is given below @@ -543,17 +544,13 @@ An example of rigid link properties table is given below Member Cosine Matrices COSM (i,j) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -This table is not currently used by SubDyn, but in future releases it -will need to be populated if members with cross-sections other than -circular will be employed. - **NCOSMs** rows, one for each unique member orientation set, will need to be provided. Each row of the table will list the nine entries of the -direction cosine matrices (COSM11, COSM12,…COSM33) for matrix elements -(1,1), (1,2),…(3,3) that establish the orientation of the local member -axes (*x*,\ *y* principal axes in the cross-sectional plane, *z* along -the member longitudinal axis) with respect to the SS coordinate system -(local-to-global transformation matrices). +direction cosine matrices (COSM11, COSM12,…COSM33) for matrix elements. +Each row is a vector in the global coordinate system for principal axes +in the x, y and z directions respectively. These vectors need to be +specified with an extremely high level of precision for results to be +equivalent to an internal calculation. Joint Additional Concentrated Masses ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/modules/subdyn/src/FEM.f90 b/modules/subdyn/src/FEM.f90 index b8a9eed453..0fe0376f29 100644 --- a/modules/subdyn/src/FEM.f90 +++ b/modules/subdyn/src/FEM.f90 @@ -26,8 +26,9 @@ MODULE FEM INTEGER, PARAMETER :: LaKi = R8Ki ! Define the kind to be used for LaPack INTERFACE FINDLOCI ! In the future, use FINDLOC from intrinsic - MODULE PROCEDURE FINDLOCI_ReKi + MODULE PROCEDURE FINDLOCI_R8Ki MODULE PROCEDURE FINDLOCI_IntKi + MODULE PROCEDURE FINDLOCI_SiKi END INTERFACE @@ -836,8 +837,8 @@ END SUBROUTINE InsertDOFrows !------------------------------------------------------------------------------------------------------ !> Returns index of val in Array (val is an integer!) ! NOTE: in the future use intrinsinc function findloc -FUNCTION FINDLOCI_ReKi(Array, Val) result(i) - real(ReKi) , dimension(:), intent(in) :: Array !< Array to search in +FUNCTION FINDLOCI_R8Ki(Array, Val) result(i) + real(R8Ki) , dimension(:), intent(in) :: Array !< Array to search in integer(IntKi), intent(in) :: val !< Val integer(IntKi) :: i !< Index of joint in joint table i = 1 @@ -866,6 +867,21 @@ FUNCTION FINDLOCI_IntKi(Array, Val) result(i) enddo i=-1 END FUNCTION + +FUNCTION FINDLOCI_SiKi(Array, Val) result(i) + real(SiKi), dimension(:), intent(in) :: Array !< Array to search in + integer(IntKi), intent(in) :: val !< Val + integer(IntKi) :: i !< Index of joint in joint table + i = 1 + do while ( i <= size(Array) ) + if ( Val == Array(i) ) THEN + return ! Exit when found + else + i = i + 1 + endif + enddo + i=-1 +END FUNCTION !------------------------------------------------------------------------------------------------------ SUBROUTINE RigidTransformationLine(dx,dy,dz,iLine,Line) real(ReKi), INTENT(IN) :: dx,dy,dz @@ -1022,8 +1038,8 @@ END SUBROUTINE GetOrthVectors !> Element stiffness matrix for classical beam elements !! shear is true -- non-tapered Timoshenko beam !! shear is false -- non-tapered Euler-Bernoulli beam -SUBROUTINE ElemK_Beam(A, L, Ixx, Iyy, Jzz, Shear, kappa, E, G, DirCos, K) - REAL(ReKi), INTENT( IN) :: A, L, Ixx, Iyy, Jzz, E, G, kappa +SUBROUTINE ElemK_Beam(A, L, Ixx, Iyy, Jzz, Shear, kappa_x, kappa_y, E, G, DirCos, K) + REAL(ReKi), INTENT( IN) :: A, L, Ixx, Iyy, Jzz, E, G, kappa_x, kappa_y REAL(FEKi), INTENT( IN) :: DirCos(3,3) !< From element to global: xg = DC.xe, Kg = DC.Ke.DC^t LOGICAL , INTENT( IN) :: Shear REAL(FEKi), INTENT(OUT) :: K(12, 12) @@ -1031,8 +1047,8 @@ SUBROUTINE ElemK_Beam(A, L, Ixx, Iyy, Jzz, Shear, kappa, E, G, DirCos, K) REAL(FEKi) :: Ax, Ay, Kx, Ky REAL(FEKi) :: DC(12, 12) - Ax = kappa*A - Ay = kappa*A + Ax = kappa_x*A + Ay = kappa_y*A K(1:12,1:12) = 0.0_FEKi diff --git a/modules/subdyn/src/SD_FEM.f90 b/modules/subdyn/src/SD_FEM.f90 index bee8e4a9e7..4eae76de57 100644 --- a/modules/subdyn/src/SD_FEM.f90 +++ b/modules/subdyn/src/SD_FEM.f90 @@ -32,7 +32,7 @@ MODULE SD_FEM INTEGER(IntKi), PARAMETER :: InterfCol = 7 ! Number of columns in interf matrix (JointID,ItfTDxss,ItfTDYss,ItfTDZss,ItfRDXss,ItfRDYss,ItfRDZss) INTEGER(IntKi), PARAMETER :: ReactCol = 7 ! Number of columns in reaction matrix (JointID,ItfTDxss,ItfTDYss,ItfTDZss,ItfRDXss,ItfRDYss,ItfRDZss) INTEGER(IntKi), PARAMETER :: MaxNodesPerElem = 2 ! Maximum number of nodes per element (currently 2) - INTEGER(IntKi), PARAMETER :: MembersCol = MaxNodesPerElem + 3+1 ! Number of columns in Members (MemberID,MJointID1,MJointID2,MPropSetID1,MPropSetID2,COSMID) + INTEGER(IntKi), PARAMETER :: MembersCol = MaxNodesPerElem + 3+1+1 ! Number of columns in Members (MemberID,MJointID1,MJointID2,MPropSetID1,MPropSetID2,COSMID) INTEGER(IntKi), PARAMETER :: PropSetsBCol = 6 ! Number of columns in PropSets (PropSetID,YoungE,ShearG,MatDens,XsecD,XsecT) !bjj: this really doesn't need to store k, does it? or is this supposed to be an ID, in which case we shouldn't be storing k (except new property sets), we should be storing IDs INTEGER(IntKi), PARAMETER :: PropSetsXCol = 10 ! Number of columns in XPropSets (PropSetID,YoungE,ShearG,MatDens,XsecA,XsecAsx,XsecAsy,XsecJxx,XsecJyy,XsecJ0) INTEGER(IntKi), PARAMETER :: PropSetsCCol = 5 ! Number of columns in CablePropSet (PropSetID, EA, MatDens, T0) @@ -41,6 +41,7 @@ MODULE SD_FEM INTEGER(IntKi), PARAMETER :: CMassCol = 11 ! Number of columns in Concentrated Mass (CMJointID,JMass,JMXX,JMYY,JMZZ, Optional:JMXY,JMXZ,JMYZ,CGX,CGY,CGZ) ! Indices in Members table INTEGER(IntKi), PARAMETER :: iMType= 6 ! Index in Members table where the type is stored + INTEGER(IntKi), PARAMETER :: iMDirCosID = 7 ! Index in Members table where the type is stored INTEGER(IntKi), PARAMETER :: iMProp= 4 ! Index in Members table where the PropSet1 and 2 are stored ! Indices in Joints table @@ -55,9 +56,10 @@ MODULE SD_FEM INTEGER(IntKi), PARAMETER :: idJointBall = 4 ! ID for member types - INTEGER(IntKi), PARAMETER :: idMemberBeam = 1 + INTEGER(IntKi), PARAMETER :: idMemberBeamCirc = 1 INTEGER(IntKi), PARAMETER :: idMemberCable = 2 INTEGER(IntKi), PARAMETER :: idMemberRigid = 3 + INTEGER(IntKi), PARAMETER :: idMemberBeamArb = 4 ! Types of Boundary Conditions INTEGER(IntKi), PARAMETER :: idBC_Fixed = 11 ! Fixed BC @@ -380,8 +382,8 @@ SUBROUTINE SD_ReIndex_CreateNodesAndElems(Init,p, ErrStat, ErrMsg) ! NOTE: this index has different meaning depending on the member type ! DO n=iMProp,iMProp+1 - if (mType==idMemberBeam) then - sType='Member x-section property' + if (mType==idMemberBeamCirc) then + sType='Member circular cross-section property' p%Elems(iMem,n) = FINDLOCI(Init%PropSetsB(:,1), Init%Members(iMem, n) ) else if (mType==idMemberCable) then sType='Cable property' @@ -389,15 +391,19 @@ SUBROUTINE SD_ReIndex_CreateNodesAndElems(Init,p, ErrStat, ErrMsg) else if (mType==idMemberRigid) then sType='Rigid property' p%Elems(iMem,n) = FINDLOCI(Init%PropSetsR(:,1), Init%Members(iMem, n) ) + else if (mType==idMemberBeamArb) then + sType='Member arbitrary cross-section property' + p%Elems(iMem,n) = FINDLOCI(Init%PropSetsX(:,1), Init%Members(iMem, n) ) else ! Should not happen print*,'Element type unknown',mType STOP end if ! Test that the two properties match for non-beam - if (mType/=idMemberBeam) then + if (mType/=idMemberBeamCirc) then if (Init%Members(iMem, iMProp)/=Init%Members(iMem, iMProp+1)) then - call Fatal('Properties should be the same at each node for non-beam members. Check member with ID: '//TRIM(Num2LStr(Init%Members(iMem,1)))) + ! NOTE: for non circular beams, we could just check that E, rho, G are the same for both properties + call Fatal('Property IDs should be the same at both joints for arbitrary beams, rigid links, and cables. Check member with ID: '//TRIM(Num2LStr(Init%Members(iMem,1)))) return endif endif @@ -408,6 +414,12 @@ SUBROUTINE SD_ReIndex_CreateNodesAndElems(Init,p, ErrStat, ErrMsg) END DO !n, loop through property ids ! Column 6: member type p%Elems(iMem, iMType) = Init%Members(iMem, iMType) ! + ! Column 7: member type + + if (p%Elems(iMem, iMDirCosID)/=-1) then + p%Elems(iMem, iMDirCosID) = FINDLOCI(Init%COSMs(:,1), Init%Members(iMem, iMDirCosID) ) + endif + END DO !iMem, loop through members ! TODO in theory, we shouldn't need these anymore @@ -436,11 +448,13 @@ SUBROUTINE SD_Discrt(Init,p, ErrStat, ErrMsg) INTEGER :: NNE ! number of nodes per element INTEGER :: MaxNProp REAL(ReKi), ALLOCATABLE :: TempProps(:, :) + REAL(ReKi), ALLOCATABLE :: TempPropsX(:, :) INTEGER, ALLOCATABLE :: TempMembers(:, :) INTEGER :: knode, kelem, kprop, nprop + INTEGER :: iDirCos REAL(ReKi) :: x1, y1, z1, x2, y2, z2, dx, dy, dz, dd, dt, d1, d2, t1, t2 LOGICAL :: CreateNewProp - INTEGER(IntKi) :: nMemberCable, nMemberRigid, nMemberBeam !< Number of memebers per type + INTEGER(IntKi) :: nMemberCable, nMemberRigid, nMemberBeamCirc, nMemberBeamArb !< Number of memebers per type INTEGER(IntKi) :: eType !< Element Type INTEGER(IntKi) :: ErrStat2 CHARACTER(ErrMsgLen) :: ErrMsg2 @@ -455,16 +469,17 @@ SUBROUTINE SD_Discrt(Init,p, ErrStat, ErrMsg) ENDIF ! --- Total number of element - nMemberBeam = count(Init%Members(:,iMType) == idMemberBeam) - nMemberCable = count(Init%Members(:,iMType) == idMemberCable) - nMemberRigid = count(Init%Members(:,iMType) == idMemberRigid) - Init%NElem = nMemberBeam*Init%NDiv + nMemberCable + nMemberRigid ! NOTE: only Beams are divided - IF ( (nMemberBeam+nMemberRigid+nMemberCable) /= size(Init%Members,1)) then + nMemberBeamCirc = count(Init%Members(:,iMType) == idMemberBeamCirc) + nMemberCable = count(Init%Members(:,iMType) == idMemberCable) + nMemberRigid = count(Init%Members(:,iMType) == idMemberRigid) + nMemberBeamArb = count(Init%Members(:,iMType) == idMemberBeamArb) + Init%NElem = (nMemberBeamCirc + nMemberBeamArb)*Init%NDiv + nMemberCable + nMemberRigid ! NOTE: only Beams are divided + IF ( (nMemberBeamCirc+nMemberRigid+nMemberCable+nMemberBeamArb) /= size(Init%Members,1)) then CALL Fatal(' Member list contains an element which is not a beam, a cable or a rigid link'); return ENDIF ! Total number of nodes - Depends on division and number of nodes per element - p%nNodes = Init%NJoints + ( Init%NDiv - 1 )*nMemberBeam + p%nNodes = Init%NJoints + ( Init%NDiv - 1 )*(nMemberBeamCirc) ! TODO add nMemberBeamArb when support for division provided ! check the number of interior modes IF ( p%nDOFM > 6*(p%nNodes - p%nNodes_I - p%nNodes_C) ) THEN @@ -492,13 +507,24 @@ SUBROUTINE SD_Discrt(Init,p, ErrStat, ErrMsg) return endif - if (eType==idMemberBeam) then + if (eType==idMemberBeamCirc) then if ( ( .not. EqualRealNos(Init%PropSetsB(Prop1, 2),Init%PropSetsB(Prop2, 2) ) ) & .or. ( .not. EqualRealNos(Init%PropSetsB(Prop1, 3),Init%PropSetsB(Prop2, 3) ) ) & .or. ( .not. EqualRealNos(Init%PropSetsB(Prop1, 4),Init%PropSetsB(Prop2, 4) ) ) ) then call Fatal(' Material E, G and rho in a member must be the same (See member at position '//trim(num2lstr(I))//' in member list)') return endif + else if (eType==idMemberBeamArb) then + if (Prop1 /= Prop2 ) then + call Fatal(' Members using arbitrary cross section properties must have the same properties on both ends. See member at position '//trim(num2lstr(I))//' in member list)') + return + endif + !if ( ( .not. EqualRealNos(Init%PropSetsX(Prop1, 2),Init%PropSetsX(Prop2, 2) ) ) & + ! .or. ( .not. EqualRealNos(Init%PropSetsX(Prop1, 3),Init%PropSetsX(Prop2, 3) ) ) & + ! .or. ( .not. EqualRealNos(Init%PropSetsX(Prop1, 4),Init%PropSetsX(Prop2, 4) ) ) ) then + ! call Fatal(' Material E, G and rho in a member must be the same (See member at position '//trim(num2lstr(I))//' in member list)') + ! return + !endif endif ! is beam enddo @@ -519,17 +545,21 @@ SUBROUTINE SD_Discrt(Init,p, ErrStat, ErrMsg) ! Initialize Temp arrays that will contain user inputs + input from the subdivided members ! We don't know how many properties will be needed, so allocated to size MaxNProp - MaxNProp = Init%NPropSetsB + Init%NElem*NNE ! Maximum possible number of property sets (temp): This is property set per element node, for all elements (bjj, added Init%NPropSets to account for possibility of entering many unused prop sets) + ! TODO add Init%NPropSetsX and use PropSetXCol in the future or allocate a new TempProps + MaxNProp = Init%NPropSetsB + Init%NElem*NNE ! Maximum possible number of property sets (temp): This is property set per element node, for all elements (bjj, added Init%NPropSets to account for possibility of entering many unused prop sets) CALL AllocAry(TempMembers, p%NMembers, MembersCol , 'TempMembers', ErrStat2, ErrMsg2); if(Failed()) return CALL AllocAry(TempProps, MaxNProp, PropSetsBCol,'TempProps', ErrStat2, ErrMsg2); if(Failed()) return TempProps = -9999. + TempProps(1:Init%NPropSetsB, :) = Init%PropSetsB TempMembers = p%Elems(1:p%NMembers,:) - TempProps(1:Init%NPropSetsB, :) = Init%PropSetsB + p%Elems(:,:) = -9999. ! Reinitialized. Elements will be ordered by member subdivisions (see setNewElem) kelem = 0 knode = Init%NJoints + kprop = Init%NPropSetsB + DO I = 1, p%NMembers !the first p%NMembers rows of p%Elems contain the element information ! Member data Node1 = TempMembers(I, 2) @@ -537,14 +567,15 @@ SUBROUTINE SD_Discrt(Init,p, ErrStat, ErrMsg) Prop1 = TempMembers(I, iMProp ) Prop2 = TempMembers(I, iMProp+1) eType = TempMembers(I, iMType ) + iDirCos = TempMembers(I, iMDirCosID) - if (eType/=idMemberBeam) then + if (eType==idMemberRigid .OR. eType==idMemberCable) then ! --- Cables and rigid links are not subdivided and have same prop at nodes ! No need to create new properties or new nodes Init%MemberNodes(I, 1) = Node1 Init%MemberNodes(I, 2) = Node2 kelem = kelem + 1 - CALL SetNewElem(kelem, Node1, Node2, eType, Prop1, Prop1, p) + CALL SetNewElem(kelem, Node1, Node2, eType, Prop1, Prop1, p, iDirCos) cycle endif @@ -563,19 +594,29 @@ SUBROUTINE SD_Discrt(Init,p, ErrStat, ErrMsg) dx = ( x2 - x1 )/Init%NDiv dy = ( y2 - y1 )/Init%NDiv dz = ( z2 - z1 )/Init%NDiv - - d1 = TempProps(Prop1, 5) - t1 = TempProps(Prop1, 6) - d2 = TempProps(Prop2, 5) - t2 = TempProps(Prop2, 6) - - dd = ( d2 - d1 )/Init%NDiv - dt = ( t2 - t1 )/Init%NDiv - + if (eType == idMemberBeamCirc) then + + d1 = TempProps(Prop1, 5) + t1 = TempProps(Prop1, 6) + + d2 = TempProps(Prop2, 5) + t2 = TempProps(Prop2, 6) + + dd = ( d2 - d1 )/Init%NDiv + dt = ( t2 - t1 )/Init%NDiv + ! If both dd and dt are 0, no interpolation is needed, and we can use the same property set for new nodes/elements. otherwise we'll have to create new properties for each new node - CreateNewProp = .NOT. ( EqualRealNos( dd , 0.0_ReKi ) .AND. EqualRealNos( dt , 0.0_ReKi ) ) - + + CreateNewProp = .NOT. ( EqualRealNos( dd , 0.0_ReKi ) .AND. EqualRealNos( dt , 0.0_ReKi ) ) + + elseif (eType == idMemberBeamArb) then + + CreateNewProp = .FALSE. + CALL WrScr('[WARNING] Members with non-circular cross-sections are currently not divided (member at position '//TRIM(Num2LStr(I))//' ).') + + endif + ! node connect to Node1 knode = knode + 1 Init%MemberNodes(I, 2) = knode @@ -587,11 +628,11 @@ SUBROUTINE SD_Discrt(Init,p, ErrStat, ErrMsg) ! k, E1, G1, rho1, d, t, CALL SetNewProp(kprop, TempProps(Prop1, 2), TempProps(Prop1, 3), TempProps(Prop1, 4), d1+dd, t1+dt, TempProps) kelem = kelem + 1 - CALL SetNewElem(kelem, Node1, knode, eType, Prop1, kprop, p); if (ErrStat>ErrID_None) return; + CALL SetNewElem(kelem, Node1, knode, eType, Prop1, kprop, p, iDirCos); if (ErrStat>ErrID_None) return; nprop = kprop ELSE kelem = kelem + 1 - CALL SetNewElem(kelem, Node1, knode, eType, Prop1, Prop1, p); if (ErrStat>ErrID_None) return; + CALL SetNewElem(kelem, Node1, knode, eType, Prop1, Prop1, p, iDirCos); if (ErrStat>ErrID_None) return; nprop = Prop1 ENDIF @@ -608,17 +649,17 @@ SUBROUTINE SD_Discrt(Init,p, ErrStat, ErrMsg) ! k, E1, G1, rho1, d, t CALL SetNewProp(kprop, TempProps(Prop1, 2), TempProps(Prop1, 3), Init%PropSetsB(Prop1, 4), d1 + J*dd, t1 + J*dt, TempProps) kelem = kelem + 1 - CALL SetNewElem(kelem, knode-1, knode, eType, nprop, kprop, p); if (ErrStat>ErrID_None) return; + CALL SetNewElem(kelem, knode-1, knode, eType, nprop, kprop, p, iDirCos); if (ErrStat>ErrID_None) return; nprop = kprop ELSE kelem = kelem + 1 - CALL SetNewElem(kelem, knode-1, knode, eType, nprop, nprop, p); if (ErrStat>ErrID_None) return; + CALL SetNewElem(kelem, knode-1, knode, eType, nprop, nprop, p, iDirCos); if (ErrStat>ErrID_None) return; ENDIF ENDDO ! the element connect to Node2 kelem = kelem + 1 - CALL SetNewElem(kelem, knode, Node2, eType, nprop, Prop2, p); if (ErrStat>ErrID_None) return; + CALL SetNewElem(kelem, knode, Node2, eType, nprop, Prop2, p, iDirCos); if (ErrStat>ErrID_None) return; ENDDO ! loop over all members ! Init%NPropB = kprop @@ -689,13 +730,14 @@ SUBROUTINE SetNewNode(k, x, y, z, Init) END SUBROUTINE SetNewNode !> Set properties of element k - SUBROUTINE SetNewElem(k, n1, n2, etype, p1, p2, p) + SUBROUTINE SetNewElem(k, n1, n2, etype, p1, p2, p, iDirCos) INTEGER, INTENT(IN ) :: k INTEGER, INTENT(IN ) :: n1 INTEGER, INTENT(IN ) :: n2 INTEGER, INTENT(IN ) :: eType INTEGER, INTENT(IN ) :: p1 INTEGER, INTENT(IN ) :: p2 + INTEGER, INTENT(IN ) :: iDirCos TYPE(SD_ParameterType), INTENT(INOUT) :: p if (k>size(p%Elems,1)) then call Fatal('Implementation Error. Attempt to add more element than space allocated.'); @@ -707,6 +749,7 @@ SUBROUTINE SetNewElem(k, n1, n2, etype, p1, p2, p) p%Elems(k, iMProp ) = p1 p%Elems(k, iMProp+1) = p2 p%Elems(k, iMType) = eType + p%Elems(k, iMDirCosID) = iDirCos END SUBROUTINE SetNewElem !> Set material properties of element k, NOTE: this is only for a beam @@ -770,10 +813,11 @@ SUBROUTINE SetElementProperties(Init, p, ErrStat, ErrMsg) INTEGER :: I INTEGER :: N1, N2 ! starting node and ending node in the element INTEGER :: P1, P2 ! property set numbers for starting and ending nodes + INTEGER :: iDirCos REAL(ReKi) :: D1, D2, t1, t2, E, G, rho ! properties of a section REAL(FEKi) :: DirCos(3, 3) ! direction cosine matrices REAL(ReKi) :: L ! length of the element - REAL(ReKi) :: r1, r2, t, Iyy, Jzz, Ixx, A, kappa, nu, ratioSq, D_inner, D_outer + REAL(ReKi) :: r1, r2, t, Iyy, Jzz, Ixx, A, kappa, kappa_x, kappa_y, nu, ratioSq, D_inner, D_outer LOGICAL :: shear INTEGER(IntKi) :: eType !< Member type REAL(ReKi) :: Point1(3), Point2(3) ! (x,y,z) positions of two nodes making up an element @@ -793,11 +837,32 @@ SUBROUTINE SetElementProperties(Init, p, ErrStat, ErrMsg) P1 = p%Elems(I, iMProp ) P2 = p%Elems(I, iMProp+1) eType = p%Elems(I, iMType) + iDirCos = p%Elems(I, iMDirCosID) ! --- Properties common to all element types: L, DirCos (and Area and rho) Point1 = Init%Nodes(N1,2:4) Point2 = Init%Nodes(N2,2:4) - CALL GetDirCos(Point1, Point2, DirCos, L, ErrStat2, ErrMsg2); if(Failed()) return ! L and DirCos + + if (iDirCos/=-1) then + CALL GetDirCos(Point1, Point2, DirCos, L, ErrStat2, ErrMsg2); if(Failed()) return ! sets L + + ! overwrites direction cosines + DirCos(1, 1) = Init%COSMs(iDirCos, 2) + DirCos(2, 1) = Init%COSMs(iDirCos, 3) + DirCos(3, 1) = Init%COSMs(iDirCos, 4) + DirCos(1, 2) = Init%COSMs(iDirCos, 5) + DirCos(2, 2) = Init%COSMs(iDirCos, 6) + DirCos(3, 2) = Init%COSMs(iDirCos, 7) + DirCos(1, 3) = Init%COSMs(iDirCos, 8) + DirCos(2, 3) = Init%COSMs(iDirCos, 9) + DirCos(3, 3) = Init%COSMs(iDirCos, 10) + + else + CALL GetDirCos(Point1, Point2, DirCos, L, ErrStat2, ErrMsg2); if(Failed()) return ! L and DirCos + endif + + + p%ElemProps(i)%eType = eType p%ElemProps(i)%Length = L p%ElemProps(i)%DirCos = DirCos @@ -806,7 +871,8 @@ SUBROUTINE SetElementProperties(Init, p, ErrStat, ErrMsg) p%ElemProps(i)%Ixx = -9.99e+36 p%ElemProps(i)%Iyy = -9.99e+36 p%ElemProps(i)%Jzz = -9.99e+36 - p%ElemProps(i)%Kappa = -9.99e+36 + p%ElemProps(i)%Kappa_x = -9.99e+36 + p%ElemProps(i)%Kappa_y = -9.99e+36 p%ElemProps(i)%YoungE = -9.99e+36 p%ElemProps(i)%ShearG = -9.99e+36 p%ElemProps(i)%Area = -9.99e+36 @@ -814,7 +880,7 @@ SUBROUTINE SetElementProperties(Init, p, ErrStat, ErrMsg) p%ElemProps(i)%T0 = -9.99e+36 ! --- Properties that are specific to some elements - if (eType==idMemberBeam) then + if (eType==idMemberBeamCirc) then E = Init%PropsB(P1, 2) ! TODO E2 G = Init%PropsB(P1, 3) ! TODO G2 rho = Init%PropsB(P1, 4) ! TODO rho2 @@ -853,7 +919,43 @@ SUBROUTINE SetElementProperties(Init, p, ErrStat, ErrMsg) p%ElemProps(i)%Iyy = Iyy p%ElemProps(i)%Jzz = Jzz p%ElemProps(i)%Shear = Shear - p%ElemProps(i)%kappa = kappa + p%ElemProps(i)%Kappa_x = kappa + p%ElemProps(i)%Kappa_y = kappa + p%ElemProps(i)%YoungE = E + p%ElemProps(i)%ShearG = G + p%ElemProps(i)%Area = A + p%ElemProps(i)%Rho = rho + p%ElemProps(i)%D = (/D1, D2/) + + else if (eType==idMemberBeamArb) then + + p%ElemProps(i)%eType = 1 + if( Init%FEMMod == 1 ) then ! uniform Euler-Bernoulli + Shear = .false. + elseif( Init%FEMMod == 3 ) then ! uniform Timoshenko + Shear = .true. + endif + ! Storing Beam specific properties + ! Here we are averaging the values at both extremities which is different from what is done for regular beams. + ! The averaging should have no effect for the material properties because the beam is assumed to be isotropic (E, G, rho constant). + E = (Init%PropSetsX(P1, 2) + Init%PropSetsX(P2, 2)) / 2 + G = (Init%PropSetsX(P1, 3) + Init%PropSetsX(P2, 3)) / 2 + rho = (Init%PropSetsX(P1, 4) + Init%PropSetsX(P2, 4)) / 2 + ! Averaging will have an impact on geometry, shear and inertia + ! but we are currently forcing the property ID to be the same, so no effect. + A = (Init%PropSetsX(P1, 5) + Init%PropSetsX(P2, 5)) / 2 + Kappa_x = (Init%PropSetsX(P1, 6) + Init%PropSetsX(P2, 6)) / 2 / A + Kappa_y = (Init%PropSetsX(P1, 7) + Init%PropSetsX(P2, 7)) / 2 / A + Ixx = (Init%PropSetsX(P1, 8) + Init%PropSetsX(P2, 8)) / 2 + Iyy = (Init%PropSetsX(P1, 9) + Init%PropSetsX(P2, 9)) / 2 + Jzz = (Init%PropSetsX(P1, 10) + Init%PropSetsX(P2, 10)) / 2 + + p%ElemProps(i)%Ixx = Ixx + p%ElemProps(i)%Iyy = Iyy + p%ElemProps(i)%Jzz = Jzz + p%ElemProps(i)%Shear = Shear + p%ElemProps(i)%Kappa_x = kappa_x + p%ElemProps(i)%Kappa_y = kappa_y p%ElemProps(i)%YoungE = E p%ElemProps(i)%ShearG = G p%ElemProps(i)%Area = A @@ -2160,7 +2262,7 @@ SUBROUTINE ElemM(ep, Me) TYPE(ElemPropType), INTENT(IN) :: eP !< Element Property REAL(FEKi), INTENT(OUT) :: Me(12, 12) REAL(FEKi) :: L0, Eps0 - if (ep%eType==idMemberBeam) then + if (ep%eType==idMemberBeamCirc) then !Calculate Ke, Me to be used for output CALL ElemM_Beam(eP%Area, eP%Length, eP%Ixx, eP%Iyy, eP%Jzz, eP%rho, eP%DirCos, Me) @@ -2183,8 +2285,8 @@ SUBROUTINE ElemK(ep, Ke) TYPE(ElemPropType), INTENT(IN) :: eP !< Element Property REAL(FEKi), INTENT(OUT) :: Ke(12, 12) - if (ep%eType==idMemberBeam) then - CALL ElemK_Beam( eP%Area, eP%Length, eP%Ixx, eP%Iyy, eP%Jzz, eP%Shear, eP%kappa, eP%YoungE, eP%ShearG, eP%DirCos, Ke) + if (ep%eType==idMemberBeamCirc) then + CALL ElemK_Beam( eP%Area, eP%Length, eP%Ixx, eP%Iyy, eP%Jzz, eP%Shear, eP%Kappa_x, eP%Kappa_y, eP%YoungE, eP%ShearG, eP%DirCos, Ke) else if (ep%eType==idMemberCable) then CALL ElemK_Cable(ep%Area, ep%Length, ep%YoungE, ep%T0, eP%DirCos, Ke) @@ -2199,7 +2301,7 @@ SUBROUTINE ElemF(ep, gravity, Fg, Fo) REAL(ReKi), INTENT(IN) :: gravity !< acceleration of gravity REAL(FEKi), INTENT(OUT) :: Fg(12) REAL(FEKi), INTENT(OUT) :: Fo(12) - if (ep%eType==idMemberBeam) then + if (ep%eType==idMemberBeamCirc) then Fo(1:12)=0.0_FEKi else if (ep%eType==idMemberCable) then CALL ElemF_Cable(ep%T0, ep%DirCos, Fo) diff --git a/modules/subdyn/src/SubDyn.f90 b/modules/subdyn/src/SubDyn.f90 index e4f411a8c7..7bc5e6f161 100644 --- a/modules/subdyn/src/SubDyn.f90 +++ b/modules/subdyn/src/SubDyn.f90 @@ -851,7 +851,7 @@ SUBROUTINE SD_Input(SDInputFile, Init, p, ErrStat,ErrMsg) CHARACTER(64), ALLOCATABLE :: StrArray(:) ! Array of strings, for better control of table inputs LOGICAL :: Echo LOGICAL :: LegacyFormat -LOGICAL :: bNumeric +LOGICAL :: bNumeric, bInteger INTEGER(IntKi) :: UnIn INTEGER(IntKi) :: nColumns, nColValid, nColNumeric INTEGER(IntKi) :: IOS @@ -1149,20 +1149,50 @@ SUBROUTINE SD_Input(SDInputFile, Init, p, ErrStat,ErrMsg) CALL ReadCom ( UnIn, SDInputFile, 'Members Units ' ,ErrStat2, ErrMsg2, UnEc ); if(Failed()) return CALL AllocAry(Init%Members, p%NMembers, MembersCol, 'Members', ErrStat2, ErrMsg2) Init%Members(:,:) = 0.0_ReKi -if (LegacyFormat) then - nColumns = 5 - Init%Members(:,iMType) = idMemberBeam ! Important, in legacy all members are beams -else - nColumns = MembersCol + +nColumns=MembersCol + +if (p%NMembers == 0) then + CALL Fatal(' Error in file "'//TRIM(SDInputFile)//'": There should be at least one SubDyn member: "'//trim(Line)//'"') + return +endif + +CALL AllocAry(StrArray, nColumns, 'StrArray',ErrStat2,ErrMsg2); if (Failed()) return +READ(UnIn, FMT='(A)', IOSTAT=ErrStat2) Line ; ErrMsg2='First line of members array'; if (Failed()) return +CALL ReadCAryFromStr ( Line, StrArray, nColumns, 'Members', 'First line of members array', ErrStat2, ErrMsg2 ) +if (ErrStat2/=0) then + ! We try with one column less (legacy format) + nColumns = MembersCol-1 + deallocate(StrArray) + CALL AllocAry(StrArray, nColumns, 'StrArray',ErrStat2,ErrMsg2); if (Failed()) return + CALL ReadCAryFromStr ( Line, StrArray, nColumns, 'Members', 'First line of members array', ErrStat2, ErrMsg2 ); if(Failed()) return + call LegacyWarning('Member table contains 6 columns instead of 7, using default member directional cosines ID (-1) for all members.\ + The directional cosines will be computed based on the member nodes for all members.') + Init%Members(:,7) = -1 endif -DO I = 1, p%NMembers +! Extract fields from first line +DO I = 1, nColumns + bInteger = is_integer(StrArray(I), Init%Members(1,I)) ! Convert from string to float + if (.not.bInteger) then + CALL Fatal(' Error in file "'//TRIM(SDInputFile)//'": Non integer character found in Member line. Problematic line: "'//trim(Line)//'"') + return + endif +ENDDO + +if (allocated(StrArray)) then + deallocate(StrArray) +endif + +! ! Read remaining lines +DO I = 2, p%NMembers CALL ReadAry( UnIn, SDInputFile, Dummy_IntAry, nColumns, 'Members line '//Num2LStr(I), 'Member number and connectivity ', ErrStat2,ErrMsg2, UnEc); if(Failed()) return Init%Members(I,1:nColumns) = Dummy_IntAry(1:nColumns) -ENDDO +ENDDO + IF (Check( p%NMembers < 1 , 'NMembers must be > 0')) return -!------------------ MEMBER X-SECTION PROPERTY data 1/2 [isotropic material for now: use this table if circular-tubular elements ------------------------ -CALL ReadCom ( UnIn, SDInputFile, ' Member X-Section Property Data 1/2 ',ErrStat2, ErrMsg2, UnEc ); if(Failed()) return +!------------------ MEMBER CROSS-SECTION PROPERTY data 1/2 [isotropic material for now: use this table if circular-tubular elements ------------------------ +CALL ReadCom ( UnIn, SDInputFile, ' Member CROSS-Section Property Data 1/2 ',ErrStat2, ErrMsg2, UnEc ); if(Failed()) return CALL ReadIVar ( UnIn, SDInputFile, Init%NPropSetsB, 'NPropSets', 'Number of property sets',ErrStat2, ErrMsg2, UnEc ); if(Failed()) return CALL ReadCom ( UnIn, SDInputFile, 'Property Data 1/2 Header' ,ErrStat2, ErrMsg2, UnEc ); if(Failed()) return CALL ReadCom ( UnIn, SDInputFile, 'Property Data 1/2 Units ' ,ErrStat2, ErrMsg2, UnEc ); if(Failed()) return @@ -1173,8 +1203,8 @@ SUBROUTINE SD_Input(SDInputFile, Init, p, ErrStat,ErrMsg) ENDDO IF (Check( Init%NPropSetsB < 1 , 'NPropSets must be >0')) return -!------------------ MEMBER X-SECTION PROPERTY data 2/2 [isotropic material for now: use this table if any section other than circular, however provide COSM(i,j) below) ------------------------ -CALL ReadCom ( UnIn, SDInputFile, 'Member X-Section Property Data 2/2 ' ,ErrStat2, ErrMsg2, UnEc ); if(Failed()) return +!------------------ MEMBER CROSS-SECTION PROPERTY data 2/2 [isotropic material for now: use this table if any section other than circular, however provide COSM(i,j) below) ------------------------ +CALL ReadCom ( UnIn, SDInputFile, 'Member CROSS-Section Property Data 2/2 ' ,ErrStat2, ErrMsg2, UnEc ); if(Failed()) return CALL ReadIVar ( UnIn, SDInputFile, Init%NPropSetsX, 'NXPropSets', 'Number of non-circular property sets',ErrStat2, ErrMsg2, UnEc ); if(Failed()) return CALL ReadCom ( UnIn, SDInputFile, 'Property Data 2/2 Header' ,ErrStat2, ErrMsg2, UnEc ); if(Failed()) return CALL ReadCom ( UnIn, SDInputFile, 'Property Data 2/2 Unit ' ,ErrStat2, ErrMsg2, UnEc ); if(Failed()) return @@ -3662,7 +3692,7 @@ SUBROUTINE OutSummary(Init, p, m, InitInput, CBparams, Modes, Omega, Omega_Gy, E DummyArray(i,9) = p%ElemProps(i)%Rho ! density kg/m^3 DummyArray(i,10) = p%ElemProps(i)%YoungE ! Young modulus DummyArray(i,11) = p%ElemProps(i)%ShearG ! G - DummyArray(i,12) = p%ElemProps(i)%Kappa ! Shear coefficient + DummyArray(i,12) = p%ElemProps(i)%Kappa_x ! Shear coefficient DummyArray(i,13) = p%ElemProps(i)%Ixx ! Moment of inertia DummyArray(i,14) = p%ElemProps(i)%Iyy ! Moment of inertia DummyArray(i,15) = p%ElemProps(i)%Jzz ! Moment of inertia @@ -3728,7 +3758,7 @@ SUBROUTINE OutSummary(Init, p, m, InitInput, CBparams, Modes, Omega, Omega_Gy, E mLength=MemberLength(Init%Members(i,1),Init,ErrStat,ErrMsg) ! TODO double check mass and length IF (ErrStat .EQ. ErrID_None) THEN mType = Init%Members(I, iMType) ! - if (mType==idMemberBeam) then + if (mType==idMemberBeamCirc) then iProp(1) = FINDLOCI(Init%PropSetsB(:,1), propIDs(1)) iProp(2) = FINDLOCI(Init%PropSetsB(:,1), propIDs(2)) mMass= BeamMass(Init%PropSetsB(iProp(1),4),Init%PropSetsB(iProp(1),5),Init%PropSetsB(iProp(1),6), & @@ -3746,6 +3776,12 @@ SUBROUTINE OutSummary(Init, p, m, InitInput, CBparams, Modes, Omega, Omega_Gy, E mMass= Init%PropSetsR(iProp(1),2) * mLength ! rho [kg/m] * L WRITE(UnSum, '("#",I9,I10,I10,I10,I10,ES15.6E2,ES15.6E2, A3,2(I6),A)') Init%Members(i,1:3),propIDs(1),propIDs(2),& mMass,mLength,' ',(Init%MemberNodes(i, j), j = 1, 2), ' # Rigid link' + else if (mType==idMemberBeamArb) then + iProp(1) = FINDLOCI(Init%PropSetsX(:,1), propIDs(1)) + iProp(2) = FINDLOCI(Init%PropSetsX(:,1), propIDs(2)) + mMass= -1 ! TODO compute mass for arbitrary beams + WRITE(UnSum, '("#",I9,I10,I10,I10,I10,ES15.6E2,ES15.6E2, A3,'//Num2LStr(Init%NDiv + 1 )//'(I6))') Init%Members(i,1:3),propIDs(1),propIDs(2),& + mMass, mLength,' ',(Init%MemberNodes(i, j), j = 1, Init%NDiv+1) else WRITE(UnSum, '(A)') '#TODO, member unknown' endif @@ -3766,7 +3802,7 @@ SUBROUTINE OutSummary(Init, p, m, InitInput, CBparams, Modes, Omega, Omega_Gy, E XYZ2 = Init%Joints(iNode2,2:4) CALL GetDirCos(XYZ1(1:3), XYZ2(1:3), DirCos, mLength, ErrStat, ErrMsg) DirCos=TRANSPOSE(DirCos) !This is now global to local - WRITE(UnSum, '("#",I9,9(ES11.3E2))') Init%Members(i,1), ((DirCos(k,j),j=1,3),k=1,3) + WRITE(UnSum, '("#",I9,9(ES28.18E2))') Init%Members(i,1), ((DirCos(k,j),j=1,3),k=1,3) ENDDO @@ -4134,6 +4170,19 @@ FUNCTION is_numeric(string, x) READ(string,fmt,IOSTAT=e) x is_numeric = e == 0 END FUNCTION is_numeric + +FUNCTION is_integer(string, x) + IMPLICIT NONE + CHARACTER(len=*), INTENT(IN) :: string + INTEGER(IntKi), INTENT(OUT) :: x + LOGICAL :: is_integer + INTEGER :: e, n + x = 0 + n=LEN_TRIM(string) + READ(string,*,IOSTAT=e) x + is_integer = e == 0 +END FUNCTION is_integer + FUNCTION is_logical(string, b) IMPLICIT NONE CHARACTER(len=*), INTENT(IN) :: string diff --git a/modules/subdyn/src/SubDyn_Registry.txt b/modules/subdyn/src/SubDyn_Registry.txt index 9bcd06aff0..b3b78a1a2d 100644 --- a/modules/subdyn/src/SubDyn_Registry.txt +++ b/modules/subdyn/src/SubDyn_Registry.txt @@ -33,7 +33,8 @@ typedef ^ ElemPropType ReKi Ixx - - - "Moment of inertia of an el typedef ^ ElemPropType ReKi Iyy - - - "Moment of inertia of an element" typedef ^ ElemPropType ReKi Jzz - - - "Moment of inertia of an element" typedef ^ ElemPropType LOGICAL Shear - - - "Use timoshenko (true) E-B (false)" -typedef ^ ElemPropType ReKi Kappa - - - "Shear coefficient" +typedef ^ ElemPropType ReKi Kappa_x - - - "Shear coefficient" +typedef ^ ElemPropType ReKi Kappa_y - - - "Shear coefficient" typedef ^ ElemPropType ReKi YoungE - - - "Young's modulus" typedef ^ ElemPropType ReKi ShearG - - - "Shear modulus" N/m^2 # Properties common to all element types: @@ -90,7 +91,7 @@ typedef ^ SD_InitType ReKi PropSetsB {:}{:} - - "Property typedef ^ SD_InitType ReKi PropSetsC {:}{:} - - "Property ID and values for cables" typedef ^ SD_InitType ReKi PropSetsR {:}{:} - - "Property ID and values for rigid link" typedef ^ SD_InitType ReKi PropSetsX {:}{:} - - "Extended property sets" -typedef ^ SD_InitType ReKi COSMs {:}{:} - - "Independent direction cosine matrices" +typedef ^ SD_InitType R8Ki COSMs {:}{:} - - "Independent direction cosine matrices" typedef ^ SD_InitType ReKi CMass {:}{:} - - "Concentrated mass information" typedef ^ SD_InitType ReKi JDampings {:} - - "Damping coefficients for internal modes" typedef ^ SD_InitType IntKi GuyanDampMod - - - "Guyan damping [0=none, 1=Rayleigh Damping, 2= user specified 6x6 matrix]" diff --git a/modules/subdyn/src/SubDyn_Types.f90 b/modules/subdyn/src/SubDyn_Types.f90 index 4b53972dd0..df7648535f 100644 --- a/modules/subdyn/src/SubDyn_Types.f90 +++ b/modules/subdyn/src/SubDyn_Types.f90 @@ -69,7 +69,8 @@ MODULE SubDyn_Types REAL(ReKi) :: Iyy !< Moment of inertia of an element [-] REAL(ReKi) :: Jzz !< Moment of inertia of an element [-] LOGICAL :: Shear !< Use timoshenko (true) E-B (false) [-] - REAL(ReKi) :: Kappa !< Shear coefficient [-] + REAL(ReKi) :: Kappa_x !< Shear coefficient [-] + REAL(ReKi) :: Kappa_y !< Shear coefficient [-] REAL(ReKi) :: YoungE !< Young's modulus [-] REAL(ReKi) :: ShearG !< Shear modulus [N/m^2] REAL(ReKi) , DIMENSION(1:2) :: D !< Diameter at node 1 and 2, for visualization only [m] @@ -130,7 +131,7 @@ MODULE SubDyn_Types REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: PropSetsC !< Property ID and values for cables [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: PropSetsR !< Property ID and values for rigid link [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: PropSetsX !< Extended property sets [-] - REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: COSMs !< Independent direction cosine matrices [-] + REAL(R8Ki) , DIMENSION(:,:), ALLOCATABLE :: COSMs !< Independent direction cosine matrices [-] REAL(ReKi) , DIMENSION(:,:), ALLOCATABLE :: CMass !< Concentrated mass information [-] REAL(ReKi) , DIMENSION(:), ALLOCATABLE :: JDampings !< Damping coefficients for internal modes [-] INTEGER(IntKi) :: GuyanDampMod !< Guyan damping [0=none, 1=Rayleigh Damping, 2= user specified 6x6 matrix] [-] @@ -1706,7 +1707,8 @@ SUBROUTINE SD_CopyElemPropType( SrcElemPropTypeData, DstElemPropTypeData, CtrlCo DstElemPropTypeData%Iyy = SrcElemPropTypeData%Iyy DstElemPropTypeData%Jzz = SrcElemPropTypeData%Jzz DstElemPropTypeData%Shear = SrcElemPropTypeData%Shear - DstElemPropTypeData%Kappa = SrcElemPropTypeData%Kappa + DstElemPropTypeData%Kappa_x = SrcElemPropTypeData%Kappa_x + DstElemPropTypeData%Kappa_y = SrcElemPropTypeData%Kappa_y DstElemPropTypeData%YoungE = SrcElemPropTypeData%YoungE DstElemPropTypeData%ShearG = SrcElemPropTypeData%ShearG DstElemPropTypeData%D = SrcElemPropTypeData%D @@ -1780,7 +1782,8 @@ SUBROUTINE SD_PackElemPropType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Re_BufSz = Re_BufSz + 1 ! Iyy Re_BufSz = Re_BufSz + 1 ! Jzz Int_BufSz = Int_BufSz + 1 ! Shear - Re_BufSz = Re_BufSz + 1 ! Kappa + Re_BufSz = Re_BufSz + 1 ! Kappa_x + Re_BufSz = Re_BufSz + 1 ! Kappa_y Re_BufSz = Re_BufSz + 1 ! YoungE Re_BufSz = Re_BufSz + 1 ! ShearG Re_BufSz = Re_BufSz + SIZE(InData%D) ! D @@ -1827,7 +1830,9 @@ SUBROUTINE SD_PackElemPropType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, Err Re_Xferred = Re_Xferred + 1 IntKiBuf(Int_Xferred) = TRANSFER(InData%Shear, IntKiBuf(1)) Int_Xferred = Int_Xferred + 1 - ReKiBuf(Re_Xferred) = InData%Kappa + ReKiBuf(Re_Xferred) = InData%Kappa_x + Re_Xferred = Re_Xferred + 1 + ReKiBuf(Re_Xferred) = InData%Kappa_y Re_Xferred = Re_Xferred + 1 ReKiBuf(Re_Xferred) = InData%YoungE Re_Xferred = Re_Xferred + 1 @@ -1891,7 +1896,9 @@ SUBROUTINE SD_UnPackElemPropType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, Re_Xferred = Re_Xferred + 1 OutData%Shear = TRANSFER(IntKiBuf(Int_Xferred), OutData%Shear) Int_Xferred = Int_Xferred + 1 - OutData%Kappa = ReKiBuf(Re_Xferred) + OutData%Kappa_x = ReKiBuf(Re_Xferred) + Re_Xferred = Re_Xferred + 1 + OutData%Kappa_y = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 OutData%YoungE = ReKiBuf(Re_Xferred) Re_Xferred = Re_Xferred + 1 @@ -3690,7 +3697,7 @@ SUBROUTINE SD_PackInitType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, Int_BufSz = Int_BufSz + 1 ! COSMs allocated yes/no IF ( ALLOCATED(InData%COSMs) ) THEN Int_BufSz = Int_BufSz + 2*2 ! COSMs upper/lower bounds for each dimension - Re_BufSz = Re_BufSz + SIZE(InData%COSMs) ! COSMs + Db_BufSz = Db_BufSz + SIZE(InData%COSMs) ! COSMs END IF Int_BufSz = Int_BufSz + 1 ! CMass allocated yes/no IF ( ALLOCATED(InData%CMass) ) THEN @@ -3978,8 +3985,8 @@ SUBROUTINE SD_PackInitType( ReKiBuf, DbKiBuf, IntKiBuf, Indata, ErrStat, ErrMsg, DO i2 = LBOUND(InData%COSMs,2), UBOUND(InData%COSMs,2) DO i1 = LBOUND(InData%COSMs,1), UBOUND(InData%COSMs,1) - ReKiBuf(Re_Xferred) = InData%COSMs(i1,i2) - Re_Xferred = Re_Xferred + 1 + DbKiBuf(Db_Xferred) = InData%COSMs(i1,i2) + Db_Xferred = Db_Xferred + 1 END DO END DO END IF @@ -4598,8 +4605,8 @@ SUBROUTINE SD_UnPackInitType( ReKiBuf, DbKiBuf, IntKiBuf, Outdata, ErrStat, ErrM END IF DO i2 = LBOUND(OutData%COSMs,2), UBOUND(OutData%COSMs,2) DO i1 = LBOUND(OutData%COSMs,1), UBOUND(OutData%COSMs,1) - OutData%COSMs(i1,i2) = ReKiBuf(Re_Xferred) - Re_Xferred = Re_Xferred + 1 + OutData%COSMs(i1,i2) = REAL(DbKiBuf(Db_Xferred), R8Ki) + Db_Xferred = Db_Xferred + 1 END DO END DO END IF diff --git a/reg_tests/r-test b/reg_tests/r-test index 6bdff86677..2c2483b52c 160000 --- a/reg_tests/r-test +++ b/reg_tests/r-test @@ -1 +1 @@ -Subproject commit 6bdff86677970f5c4fa6084846d77e7a09a04b50 +Subproject commit 2c2483b52c028614a7666d624141a2b63a650bdf