If it is of any help, this is part of the code:
! DLL Max. moments and shear forces in 2-span beam with! DLL Max. moments and shear forces in 2-span beam with equal lengths
! under up to 4 moving loads
! Version Author Date
! A R.M. 14/06/2024
! B R.M. 02/05/2025
! C R.M. 23/06/2025 (ISO C Binding modifications)
! D R.M. 24/06/2025 (Literal Kind Conversion Fix)
! E R.M. 24/06/2025 (INTENT(IN) & Declarations Fix)
! F R.M. 24/06/2025 (Robust String Parsing & Call Fix)
! G R.M. 24/06/2025 (Incorporated actual profielen.txt data)
module mom_m
use iso_c_binding, only: c_float, c_double, c_int, c_char, c_null_char
implicit none
! Conversion factors
real(c_float), parameter, public :: m_to_mm = 1000.0_c_float
real(c_float), parameter, public :: N_to_kN = 0.001_c_float
real(c_float), parameter, public :: kNm_to_Nm = 1000.0_c_float
real(c_float), parameter, public :: MPa_to_Pa = 1.0e6_c_float
real(c_float), parameter, public :: mm_to_m = 0.001_c_float
real(c_float), parameter, public :: kN_to_N = 1000.0_c_float
real(c_float), parameter, public :: Nm_to_kNm = 0.001_c_float
real(c_float), parameter, public :: Pa_to_MPa = 1.0e-6_c_float
! Error codes
integer(c_int), parameter, public :: ERR_SUCCESS = 0
integer(c_int), parameter, public :: ERR_INVALID_INPUT = -1
integer(c_int), parameter, public :: ERR_CALCULATION = -2
! Module constants
real(c_float), parameter :: PI = 3.141592653589793_c_float
real(c_float), parameter :: TINY_VALUE = 1.0E-10_c_float
real(c_float), parameter :: GammaM0 = 1.00_c_float
real(c_float), parameter :: GammaM1 = 1.10_c_float
real(c_float), parameter :: GammaM2 = 1.14_c_float
real(c_float), parameter :: GammaMser = 1.00_c_float
contains
! Helper function to convert C_CHAR array to Fortran string
! This function is internal to the module and not exposed to C.
function c_char_to_fortran_string(c_str_array, c_str_len, max_fortran_len) result(f_str)
character(kind=c_char), dimension(*), intent(in) :: c_str_array
integer(c_int), value, intent(in) :: c_str_len
integer(c_int), value, intent(in) :: max_fortran_len
character(len=max_fortran_len) :: f_str
integer :: i, actual_len
f_str = ' ' ! Initialize with spaces
actual_len = 0
do i = 1, c_str_len
if (c_str_array(i) == c_null_char) then
exit
else if (actual_len < max_fortran_len) then
f_str(i:i) = char(ichar(c_str_array(i)))
actual_len = actual_len + 1
else
! String is longer than max_fortran_len, truncate
exit
end if
end do
! Trim any trailing nulls if the C string was shorter than its reported length
f_str = f_str(1:actual_len)
end function c_char_to_fortran_string
real(c_float) function Mx(x_in, a_in, L_in, P_in)
!Calling parameters
real(c_float), intent(in) :: x_in ! Position where moment is calculated
real(c_float), intent(in) :: a_in ! Position point load
real(c_float), intent(in) :: L_in ! Span
real(c_float), intent(in) :: P_in ! Value load
! Local copies for modification
real(c_float) :: x, a, L, P, b
x = x_in
a = a_in
L = L_in
P = P_in
! Evaluate Mx
if (a < L) then
b = L - a
else
a = 2._c_float * L - a
b = L - a
x = 2._c_float * L - x
endif
if (a < 0._c_float .or. a > 2._c_float * L) then
Mx = 0.0_c_float
else if (x <= a) then
Mx = ((P * b) / (4._c_float * (L ** 3._c_float))) * ((4._c_float * (L ** 2._c_float)) - (a * (L + a))) * x
else if ((x > a) .and. (x <= L)) then
Mx = ((P * b) / (4._c_float * (L ** 3._c_float))) * ((4._c_float * (L ** 2._c_float)) - (a * (L + a))) * x - P * (x - a)
else if (x > L) then
Mx = -( (P * b * a) / (4._c_float * L ** 3._c_float) ) * (L + a) * (2._c_float * L - x)
end if
end function Mx
real(c_float) function Va(a_in,L_in,P_in)
! Function to calcute max. shear at end support under one moving point load
!Calling parameters
real(c_float), intent(in) :: a_in, L_in, P_in
! Local copies for modification
real(c_float) :: a, L, P, b
a = a_in
L = L_in
P = P_in
Va = 0.0_c_float
! Evaluate Va
if (a <= L) then
b = L-a
else
a = 2._c_float*L-a
b = a-L
endif
if (a < 0._c_float .or. a > 2._c_float*L) then
Va = 0.0_c_float
else if (a <= L) then
Va = -((P*b)/(4._c_float*L**3._c_float))*(4._c_float*L**2._c_float-a*(L+a))
else if (a > L) then
Va = -((P*a*b)/(4._c_float*L**3._c_float))*(L+a)
end if
end function Va
real(c_float) function Vb(a_in,L_in,P_in)
! Function to calcute max. shear at mid support under one moving point load
!Calling parameters
real(c_float), intent(in) :: a_in, L_in, P_in
! Local copies for modification
real(c_float) :: a, L, P, b
a = a_in
L = L_in
P = P_in
Vb = 0.0_c_float
! Evaluate Vb
if (a <= L) then
b = L-a
else
a = 2._c_float*L-a
b = a-L
endif
if (a < 0._c_float .or. a > 2._c_float*L) then
Vb = 0.0_c_float
else if (a <= L) then
Vb = -((P*a)/(4._c_float*L**3._c_float))*(4._c_float*L**2._c_float+b*(L+a))
else if (a > L) then
Vb = -((P*a*b)/(4._c_float*L**3._c_float))*(L+a)
end if
end function Vb
real(c_float) function Rb(a_in,L_in,P_in)
!Function to calcute max. reaction at mid support under one moving point load
real(c_float), intent(in) :: a_in, L_in, P_in
! Local copies for modification
real(c_float) :: a, L, P, b
a = a_in
L = L_in
P = P_in
Rb = 0.0_c_float
! Evaluate rb
if (a <= L) then
b = L-a
else
a = 2._c_float*L-a
b = a-L
endif
if (a < 0._c_float .or. a > 2._c_float*L) then
Rb = 0.0_c_float
else if (a <= L) then
Rb = ((P*a)/(2._c_float*L**3._c_float))*(2._c_float*L**2._c_float+b*(L+a))
else if (a > L) then
Rb = ((P*a)/(2._c_float*L**3._c_float))*(2._c_float*L**2._c_float+b*(L+a))
end if
end function Rb
! Pure function for moment calculation - needs to be at module level for MaxMin to use it
pure function calc_total_moment(x_in, a_in, L_in, P_in, L3inv, L2_4) result(Mx_val)
real(c_float), intent(in) :: x_in, a_in, L_in, P_in, L3inv, L2_4
real(c_float) :: Mx_val, b, a_local, x_local
a_local = a_in
x_local = x_in
! Early exit for zero load
if (abs(P_in) < tiny(P_in)) then
Mx_val = 0.0_c_float
return
endif
! Handle position calculations
if (a_local < L_in) then
b = L_in - a_local
else
a_local = 2.0_c_float*L_in - a_local
x_local = 2.0_c_float*L_in - x_local
b = L_in - a_local
endif
! Check bounds
if (a_local < 0.0_c_float .or. a_local > 2.0_c_float*L_in) then
Mx_val = 0.0_c_float
else if (x_local <= a_local) then
Mx_val = (P_in * b * L3inv) * (L2_4 - a_local * (L_in + a_local)) * x_local
else if (x_local <= L_in) then
Mx_val = (P_in * b * L3inv) * (L2_4 - a_local * (L_in + a_local)) * x_local - P_in * (x_local - a_local)
else
Mx_val = -(P_in * b * a_local * L3inv * (L_in + a_local)) * (2.0_c_float*L_in - x_local)
endif
end function calc_total_moment
! Subroutine to calculate moments maxmin
! Using BIND(C) for C interoperability
subroutine MaxMin(L, P1, P2, P3, P4, a1, a2, a3, t, ar) bind(C, name='MaxMin')
use omp_lib ! Add OpenMP library (assuming it's compatible with C binding)
real(c_float), intent(in) :: L, P1, P2, P3, P4, a1, a2, a3, t
real(c_float), intent(out) :: ar(6) ! Fixed size array for C interoperability
integer :: n, ia, ix
real(c_float) :: chunk
real(c_float) :: maxmom, minmom
integer :: maxpos(2), minpos(2)
real(c_float) :: maxposx, maxposa, minposx, minposa
real(c_float) :: curr_moment, x, a
real(c_float) :: a12, a123, L3inv, L2_4 ! Pre-calculated constants
if (L <= 0.0_c_float .or. t <= 0.0_c_float) then
print *, "Error: Invalid length or step size"
ar = 0.0_c_float
return
endif
if (a1 < 0.0_c_float .or. a2 < 0.0_c_float .or. a3 < 0.0_c_float) then
print *, "Error: Invalid load spacing"
ar = 0.0_c_float
return
endif
! Pre-calculate frequently used values
n = int(2._c_float * L / t + 1._c_float)
a12 = a1 + a2
a123 = a12 + a3
L3inv = 1.0_c_float / (4.0_c_float * L**3._c_float) ! Inverse of L^3 used in Mx
L2_4 = 4.0_c_float * L**2._c_float ! 4L^2 used in Mx
chunk = max(1, n/4) ! Use fixed chunk size instead of omp_get_max_threads
! Initialize with proper min/max values
maxmom = -huge(maxmom)
minmom = huge(minmom)
maxpos = 0
minpos = 0
do ix = 1, n
do ia = 1, n
! Corrected conversion: use REAL(expression, KIND=c_float)
x = REAL(ix-1, KIND=c_float) * t
a = REAL(ia-1, KIND=c_float) * t
! Inline moment calculation for better performance
curr_moment = calc_total_moment(x, a, L, P1, L3inv, L2_4) + &
calc_total_moment(x, a - a1, L, P2, L3inv, L2_4) + &
calc_total_moment(x, a - a12, L, P3, L3inv, L2_4) + &
calc_total_moment(x, a - a123, L, P4, L3inv, L2_4)
! Update max/min in thread-safe way
if (curr_moment > maxmom) then
!$OMP CRITICAL
if (curr_moment > maxmom) then
maxmom = curr_moment
maxpos = (/ia, ix/)
endif
!$OMP END CRITICAL
endif
if (curr_moment < minmom) then
!$OMP CRITICAL
if (curr_moment < minmom) then
minmom = curr_moment
minpos = (/ia, ix/)
endif
!$OMP END CRITICAL
endif
end do
end do
!$OMP END PARALLEL DO
! Calculate final positions
! Corrected conversion: use REAL(expression, KIND=c_float)
maxposx = REAL(maxpos(2)-1, KIND=c_float) * t
maxposa = REAL(maxpos(1)-1, KIND=c_float) * t
minposx = REAL(minpos(2)-1, KIND=c_float) * t
minposa = REAL(minpos(1)-1, KIND=c_float) * t
! Set output arrays
ar = (/maxmom, minmom, maxposx, maxposa, minposx, minposa/)
end subroutine MaxMin
real(c_float) function DkEnd(L, P1, P2, P3, P4, a1, a2, a3, t) bind(C, name='DkEnd')
! Function to calculate max. shear force at end support
integer :: ia, n, alloc_stat
real(c_float), intent(in) :: L, P1, P2, P3, P4, a1, a2, a3, t
real(c_float) :: MaxVa
real(c_float), dimension(:), allocatable :: dka
n = int(2._c_float * L / t + 1._c_float)
! print *, "DEBUG: DkEnd - L=", L, " t=", t, " Calculated n=", n
allocate(dka(n), stat=alloc_stat)
if (alloc_stat /= 0) then
print *, "Error: DkEnd - Memory allocation failed for dka, n=", n, " stat=", alloc_stat
DkEnd = 0.0_c_float ! Return a safe value on error
return
endif
do ia = 1, n
! Corrected conversion: use REAL(expression, KIND=c_float)
dka(ia) = Va(REAL(ia-1, KIND=c_float) * t, L, P1) + &
Va(REAL(ia-1, KIND=c_float) * t - a1, L, P2) + &
Va(REAL(ia-1, KIND=c_float) * t - (a1+a2), L, P3) + &
Va(REAL(ia-1, KIND=c_float) * t - (a1+a2+a3), L, P4)
end do
MaxVa = minval(dka)
DkEnd = MaxVa
deallocate(dka, stat=alloc_stat)
end function DkEnd
real(c_float) function DkMid(L, P1, P2, P3, P4, a1, a2, a3, t) bind(C, name='DkMid')
! Function to calculate max. shear force at mid support
integer :: ia
integer :: n
integer :: alloc_stat
real(c_float), intent(in) :: L,P1,P2,P3,P4,a1,a2,a3,t
real(c_float) :: MaxVb
real(c_float), dimension(:), allocatable :: dkb
n = int(2._c_float * L / t + 1._c_float)
!print *, "DEBUG: DkMid - L=", L, " t=", t, " Calculated n=", n
allocate(dkb(n), stat=alloc_stat)
if (alloc_stat /= 0) then
print *, "Error: DkMid - Memory allocation failed for dkb, n=", n, " stat=", alloc_stat
DkMid = 0.0_c_float ! Return a safe value on error
return
endif
do ia = 1, n
! Corrected conversion: use REAL(expression, KIND=c_float)
dkb(ia) = Vb(REAL(ia-1, KIND=c_float) * t, L, P1) + &
Vb(REAL(ia-1, KIND=c_float) * t - a1, L, P2) + &
Vb(REAL(ia-1, KIND=c_float) * t - (a1+a2), L, P3) + &
Vb(REAL(ia-1, KIND=c_float) * t - (a1+a2+a3), L, P4)
end do
MaxVb = minval(dkb)
DkMid = MaxVb
deallocate(dkb, stat=alloc_stat)
end function DkMid
real(c_float) function ReacB(L, P1, P2, P3, P4, a1, a2, a3, t) bind(C, name='ReacB')
! Function to calculate max. reaction at mid support
integer :: ia
integer :: n
integer :: alloc_stat
real(c_float), intent(in) :: L,P1,P2,P3,P4,a1,a2,a3,t
real(c_float) :: MaxRb
real(c_float), dimension(:), allocatable :: recb
n = int(2._c_float * L / t + 1._c_float)
!print *, "DEBUG: ReacB - L=", L, " t=", t, " Calculated n=", n
allocate(recb(n), stat=alloc_stat)
if (alloc_stat /= 0) then
print *, "Error: ReacB - Memory allocation failed for recb, n=", n, " stat=", alloc_stat
ReacB = 0.0_c_float ! Return a safe value on error
return
endif
do ia = 1, n
! Corrected conversion: use REAL(expression, KIND=c_float)
recb(ia) = Rb(REAL(ia-1, KIND=c_float) * t, L, P1) + &
Rb(REAL(ia-1, KIND=c_float) * t - a1, L, P2) + &
Rb(REAL(ia-1, KIND=c_float) * t - (a1+a2), L, P3) + &
Rb(REAL(ia-1, KIND=c_float) * t - (a1+a2+a3), L, P4)
end do
MaxRb = maxval(recb)
ReacB = MaxRb
deallocate(recb, stat=alloc_stat)
end function ReacB
! Internal function, parameters are standard Fortran strings after conversion
function validate_input(HC, S, name) result(valid)
implicit none
character(len=*), intent(in) :: HC, S, name
logical :: valid
integer :: ios, num
valid = .false.
! Check HC format (HC1-HC4)
if (len_trim(HC) /= 3) return
if (HC(1:2) /= 'HC') return
read(HC(len_trim(HC):len_trim(HC)), '(I1)', iostat=ios) num
if (ios /= 0 .or. num < 1 .or. num > 4) return
! Check S format (S1-S10)
if (len_trim(S) /= 2) return
if (S(1:1) /= 'S') return
read(S(len_trim(S):len_trim(S)), '(I1)', iostat=ios) num
if (ios /= 0 .or. num < 1 .or. num > 10) return
! Check name (must be in profielen.fi)
if (len_trim(name) == 0 .or. len_trim(name) > 10) return
! All validations passed
valid = .true.
end function validate_input
! Main subroutine for external calls
subroutine mom_EV12(L_in, Qh_in, Qc_in, H1acc_in, H2acc_in, H1rail_in, H2rail_in, &
a1_in, a2_in, a3_in, t_in, HC_in, HC_len, name_in, name_len, S_in, S_len, v_in, &
all_results, Mzmax1, Mzmin1, Mzmax5, Mzmin5, Mymax1, Mymin1, Mymax5, Mymin5,&
Mzmx1, Mzmx5, Mymx1, Mymx5, &
MyEd, MzEd, MyEd5, MzEd5, VzEdMid1, VyEdEnd1, VzEdMid5, VyEdEnd5, P) &
bind(C, name='mom_EV12')
implicit none
! Input parameters (C-compatible types)
real(c_float), intent(in) :: L_in, a1_in, a2_in, a3_in, t_in, v_in
real(c_float), intent(in) :: Qh_in, Qc_in, H1acc_in, H2acc_in, H1rail_in, H2rail_in
character(kind=c_char), dimension(3), intent(in) :: HC_in ! Max len for HC is 3 (e.g., 'HC2')
integer(c_int), value, intent(in) :: HC_len
character(kind=c_char), dimension(10), intent(in) :: name_in ! Max len for name is 10 (e.g., 'HEB300 ')
integer(c_int), value, intent(in) :: name_len
character(kind=c_char), dimension(3), intent(in) :: S_in ! Max len for S is 2 (e.g., 'S2')
integer(c_int), value, intent(in) :: S_len
! Output parameters (C-compatible types)
real(c_float), intent(out) :: all_results(4,6) ! Results for all 4 force sets
real(c_float), intent(out) :: Mzmax1, Mzmin1, Mzmax5, Mzmin5, Mymax1, Mymin1, Mymax5, Mymin5
real(c_float), intent(out) :: Mzmx1, Mzmx5, Mymx1, Mymx5 ! Max/min moments
real(c_float), intent(out) :: MyEd, MzEd, MyEd5, MzEd5, VzEdMid1, VyEdEnd1, VzEdMid5, VyEdEnd5 ! Design moments shear forces
real(c_float), intent(out) :: P(7) ! Force values output
! Local Fortran variables
integer :: ios, i, HCCl, SCl ! Declared HCCl and SCl here
real(c_float) :: G, Gb
real(c_float) :: arp_in(26)
real(c_float) :: ar(6)
real(c_float) :: P11, P21, P31, P41, P15, P25, P35, P45
real(c_float) :: H11, H21, H31, H41, H15, H25, H35, H45
real(c_float) :: Mybmax, Mybmin, Vbend, Vbmid
real(c_float) :: phi1, phi2, phi4, phi5, phi2min
real(c_float) :: beta2,v_local, norm, sch
character(len=3) :: HC_local ! Fortran string copy
character(len=2) :: S_local ! Fortran string copy
character(len=10) :: name_local ! Fortran string copy
! Convert C strings (character(kind=c_char) arrays) to Fortran strings
HC_local = c_char_to_fortran_string(HC_in, HC_len, 3)
S_local = c_char_to_fortran_string(S_in, S_len, 2)
name_local = c_char_to_fortran_string(name_in, name_len, 10)
! Validate input parameters
if (.not. validate_input(HC_local, S_local, name_local)) then
print *, "Error: Invalid input parameters in mom_EV12"
print *, "HC=", trim(HC_local), " S=", trim(S_local), " name=", trim(name_local)
all_results = 0.0_c_float
! Initialize all output variables to 0.0_c_float on error
Mzmax1 = 0.0_c_float; Mzmin1 = 0.0_c_float; Mzmax5 = 0.0_c_float; Mzmin5 = 0.0_c_float
Mymax1 = 0.0_c_float; Mymin1 = 0.0_c_float; Mymax5 = 0.0_c_float; Mymin5 = 0.0_c_float
Mzmx1 = 0.0_c_float; Mzmx5 = 0.0_c_float; Mymx1 = 0.0_c_float; Mymx5 = 0.0_c_float
MyEd = 0.0_c_float; MzEd = 0.0_c_float; MyEd5 = 0.0_c_float; MzEd5 = 0.0_c_float
VzEdMid1 = 0.0_c_float; VyEdEnd1 = 0.0_c_float; VzEdMid5 = 0.0_c_float; VyEdEnd5 = 0.0_c_float
P = 0.0_c_float
return
endif
! Get dynamic factors
! CRITICAL FIX: Pass the original C-compatible string arguments to dyfa
call dyfa(HC_in, HC_len, S_in, S_len, v_in, beta2, phi2min, phi2, norm, sch)
! Use v_in directly, not v_local
phi2 = phi2min + beta2 * v_in / 60.0_c_float ! Calculate phi2 based on beta2 and v_in
phi1 = 1.1_c_float
phi4 = 1.0_c_float
phi5 = 1.5_c_float
! Get beam own weight
! Pass the length of the name_local Fortran string
call poutrel(name_local, len_trim(name_local), arp_in)
G = arp_in(8)
Gb = G
! Calculate moment, shear beam
Mybmax = (0.0772_c_float * Gb * L_in**2_c_float) / 100.0_c_float
Mybmin = (0.1250_c_float * Gb * L_in**2_c_float) / 100.0_c_float
Vbend = ((3.0_c_float/8.0_c_float) * Gb * L_in) / 100.0_c_float
Vbmid = ((5.0_c_float/8.0_c_float) * Gb * L_in) / 100.0_c_float
! Calculate forces
P11 = phi1 * Qc_in + phi2 * Qh_in
P21 = phi1 * Qc_in + phi2 * Qh_in
P31 = 0.0_c_float
P41 = 0.0_c_float
P15 = phi4 * Qc_in + phi4 * Qh_in
P25 = phi4 * Qc_in + phi4 * Qh_in
P35 = 0.0_c_float
P45 = 0.0_c_float
H11 = phi5 * H1acc_in
H21 = -phi5 * H1acc_in
H31 = 0.0_c_float
H41 = 0.0_c_float
H15 = H1rail_in
H25 = 0.0_c_float
H35 = 0.0_c_float
H45 = 0.0_c_float
P = (/P11, P21, P15, P25, H11, H21, H15/)
! Calculate force sets
call MaxMin(L_in, P11, P21, P31, P41, a1_in, a2_in, a3_in, t_in, ar)
all_results(1,:) = ar
call MaxMin(L_in, P15, P25, P35, P45, a1_in, a2_in, a3_in, t_in, ar)
all_results(2,:) = ar
call MaxMin(L_in, H11, H21, H31, H41, a1_in, a2_in, a3_in, t_in, ar)
all_results(3,:) = ar
call MaxMin(L_in, H15, H25, H35, H45, a1_in, a2_in, a3_in, t_in, ar)
all_results(4,:) = ar
Mymax1 = all_results(1, 1) ! Maximum moment for first set
Mymin1 = all_results(1, 2) ! Minimum moment for first set
Mymx1 = max(abs(Mymax1), abs(Mymin1))
Mymax5 = all_results(2, 1) ! Maximum moment for second set
Mymin5 = all_results(2, 2) ! Minimum moment for second set
Mymx5 = max(abs(Mymax5), abs(Mymin5))
Mzmax1 = all_results(3, 1) ! Maximum moment for third set
Mzmin1 = all_results(3, 2) ! Minimum moment for third set
Mzmx1 = max(abs(Mzmax1), abs(Mzmin1))
Mzmax5 = all_results(4, 1) ! Maximum moment for fourth set
Mzmin5 = all_results(4, 2) ! Minimum moment for fourth set
Mzmx5 = max(abs(Mzmax5), abs(Mzmin5))
MyEd = 1.35_c_float * (Mymx1 + Mybmax)
MzEd = 1.35_c_float * Mzmx1
MyEd5 = 1.35_c_float * (Mymx5 + Mybmax)
MzEd5 = 1.35_c_float * Mzmx5
! Calculate vertical shear forces
VzEdMid1 = 1.35_c_float * (DkMid(L_in, P11, P21, P31, P41, a1_in, a2_in, a3_in, t_in) - VbMid)
VyEdEnd1 = 1.35_c_float * (DkEnd(L_in, H11, H21, H31, H41, a1_in, a2_in, a3_in, t_in))
VzEdMid5 = 1.35_c_float * (DkMid(L_in, P15, P25, P35, P45, a1_in, a2_in, a3_in, t_in) - VbMid)
VyEdEnd5 = 1.35_c_float * (DkEnd(L_in, H15, H25, H35, H45, a1_in, a2_in, a3_in, t_in))
! Add validation check
if (abs(VzEdMid1) < TINY_VALUE) VzEdMid1 = 0.0_c_float
if (abs(VyEdEnd1) < TINY_VALUE) VyEdEnd1 = 0.0_c_float
if (abs(VzEdMid5) < TINY_VALUE) VzEdMid5 = 0.0_c_float
if (abs(VyEdEnd5) < TINY_VALUE) VyEdEnd5 = 0.0_c_float
end subroutine mom_EV12
! Poutrel subroutine - special handling for character string 'name'
subroutine poutrel(name_in, name_len, arp) bind(C, name='poutrel')
use iso_fortran_env, only: error_unit
implicit none
! Calling parameter (C-compatible character array)
character(kind=c_char), dimension(10), intent(in) :: name_in ! Fixed max length 10
integer(c_int), value, intent(in) :: name_len ! Length of the C string
real(c_float), intent(out) :: arp(26) ! Array of profile data
! Internal Fortran string for processing
character(len=10) :: name_local
! Define the internal derived type for profiles
type :: profiel
character(len=10) :: name ! Fortran string
real(c_float) :: A, h, b, tw, tf, r
end type profiel
! NPROF is now dynamically set to 69 based on profielen.txt content
integer, parameter :: NPROF = 90
type(profiel) :: profielen(NPROF)
! The following DATA statements are generated from your profielen.txt file
DATA profielen / &
profiel("HEA100 ",2124.000,96.00000,100.0000,5.000000,8.000000,12.00000), &
profiel("HEA120 ",2534.000,114.0000,120.0000,5.000000,8.000000,12.00000), &
...........
real(c_float) :: A = 0.0_c_float, h = 0.0_c_float, b = 0.0_c_float, tw = 0.0_c_float, tf = 0.0_c_float, r = 0.0_c_float
real(c_float) :: Iy = 0.0_c_float, Avz = 0.0_c_float, Wy = 0.0_c_float, Wply = 0.0_c_float, iry = 0.0_c_float
real(c_float) :: Iz = 0.0_c_float, Wz = 0.0_c_float, Wplz = 0.0_c_float, irz = 0.0_c_float
real(c_float) :: Ss = 0.0_c_float, IT = 0.0_c_float, Iw = 0.0_c_float, G = 0.0_c_float
real(c_float) :: Auf = 0.0_c_float, Izuf = 0.0_c_float, irzuf = 0.0_c_float, Wzuf = 0.0_c_float, Wzpluf = 0.0_c_float, Sy = 0.0_c_float, Syr = 0.0_c_float
real(c_float) :: Mplyd = 0.0_c_float, Mplzd = 0.0_c_float, Mplwd = 0.0_c_float, Vplzd = 0.0_c_float, Vplyd = 0.0_c_float
real(c_float), parameter :: pi = 3.1415926535_c_float
integer :: idx, i
! Initialize output array to zeros
arp = 0.0_c_float
! Convert C string to Fortran string for search
name_local = c_char_to_fortran_string(name_in, name_len, 10)
! Pad with spaces if the string is shorter than 10 characters
name_local = adjustl(name_local)
name_local = name_local // REPEAT(' ', 10 - LEN_TRIM(name_local))
! Search for the profile
! Using an explicit loop for findloc on derived type array
idx = 0
do i = 1, NPROF
if (profielen(i)%name == name_local) then
idx = i
exit
end if
end do
if (idx == 0) then
print *, "Invalid input in poutrel: Profile '", trim(name_local), "' not found."
! Initialize with zeros in case profile not found (already done)
return
end if
! Profile was found
A = profielen(idx)%A
h = profielen(idx)%h
b = profielen(idx)%b
tw = profielen(idx)%tw
tf = profielen(idx)%tf
r = profielen(idx)%r
! Shear area
Avz = A - 2._c_float*b*tf + (tw+2._c_float*r)*tf
! Weight per meter
G = A * 8000._c_float * 1.0e-6_c_float
! Second moment of inertia
Iy =(1.0_c_float/12.0_c_float)*(b*h**3.0_c_float-(b-tw)*(h-2.0_c_float*tf)**3.0_c_float)+0.03_c_float*r**4.0_c_float+0.2146_c_float*r**2.0_c_float*(h-2.0_c_float*tf-0.4468_c_float*r)**2.0_c_float
! Second moment of inertia about z-axis
Iz = (1.0_c_float/12.0_c_float)*(2._c_float*tf*b**3.0_c_float+(h-2._c_float*tf)*tw**3.0_c_float) + &
0.03_c_float*r**4.0_c_float + 0.2146_c_float*r**2.0_c_float*(tw-0.4468_c_float*r)**2.0_c_float
! Radius of gyration
iry = sqrt(Iy/A)
irz = sqrt(Iz/A)
! Tortional constant
IT = (2.0_c_float/3.0_c_float)*(b-0.63_c_float*tf)*tf**3.0_c_float+1.0_c_float/3.0_c_float*(h-2._c_float*tf)*tw**3.0_c_float+2._c_float*tw/tf*(0.145_c_float+0.1_c_float*r/tf) &
*((((r+tw/2.0_c_float)**2.0_c_float+(r+tf)**2.0_c_float-r**2.0_c_float)/(2._c_float*r+tf))**4.0_c_float)
! Warping constant
Iw = ((tf*b**3.0_c_float)/24.0_c_float)*(h-tf)**2.0_c_float
! Length of stiff bearing
Ss = tw+2._c_float*tf+(4.0_c_float-2.0_c_float*sqrt(2.0_c_float))*r
! Elastic section modulus
Wy = 2._c_float*Iy/h
Wz = 2._c_float*Iz/b
! Plastic section modulus
Wply = (tw*h**2.0_c_float)/4.0_c_float+(b-tw)*(h-tf)*tf+((4.0_c_float-pi)/2.0_c_float)*r**2.0_c_float*(h-2.0_c_float*tf)+((3.0_c_float*pi-10.0_c_float)/3.0_c_float)*r**3.0_c_float
Wplz = (b**2.0_c_float*tf)/2.0_c_float + ((h-2.0_c_float*tf)/4.0_c_float)*tw**2.0_c_float+r**3.0_c_float*(10.0_c_float/3.0_c_float-pi)+(2.0_c_float-pi/2.0_c_float)*tw*r**2.0_c_float
! Static radius
Sy = b*tf*((h-tf)/2.0_c_float)+(h/2.0_c_float-tf)*tw*((h-2.0_c_float*tf)/4.0_c_float)+((r**2_c_float*(4.0_c_float-pi))/4.0_c_float)*((h-2.0_c_float*tf-r)/2.0_c_float)
Syr = Sy - tw*((h/2.0_c_float-tf-r)**2_c_float)/2.0_c_float
! Cross sectional values top flange top flange + 1/5 web)
Auf = b*tf + ((h - 2._c_float*tf)/5._c_float)*tw
Izuf = Iz/2.0_c_float
irzuf = sqrt(Izuf/Auf)
Wzuf = Wz /2.0_c_float
Wzpluf = Wplz/2.0_c_float
! Output (indexed for easier reference)
arp( 1) = A
arp( 2) = h
arp( 3) = b
arp( 4) = tw
arp( 5) = tf
arp( 6) = r
arp( 7) = Avz
arp( 8) = G
arp( 9) = Iy
arp(10) = Iz
arp(11) = iry
arp(12) = irz
arp(13) = IT
arp(14) = Iw
arp(15) = Ss
arp(16) = Wy
arp(17) = Wz
arp(18) = Wply
arp(19) = Wplz
arp(20) = Auf
arp(21) = Izuf
arp(22) = irzuf
arp(23) = Wzuf
arp(24) = Wzpluf
arp(25) = Sy
arp(26) = Syr
end subroutine poutrel
I’m a structural engineer, but programming is a hobby of mine and since I’m retired I have lots of time.
Roger