💻 Fortran Source Code Library
We currently offer 172 open-source, production-grade Fortran codes for offline testing. Run calculations locally on your own machine, view code structure, read technical explanations, and download compilation packages including sample input files.
Pinch Analysis & Process Integration
Core Numerical Engine in Fortran 90 • 34 total downloads
! =========================================================================
! Source File: hx_pinch.f90
! =========================================================================
program hx_pinch
implicit none
integer, parameter :: max_streams = 100
integer, parameter :: max_temps = 200
! Inputs
double precision :: dT_min
integer :: N
integer :: stream_type(max_streams) ! 1 = Hot, 2 = Cold
double precision :: Ts(max_streams), Tt(max_streams), CP(max_streams)
! Shifted temps
double precision :: ts_shift(max_streams), tt_shift(max_streams)
double precision :: shifted_temps(max_temps)
double precision :: unique_temps(max_temps)
integer :: m, i, j, k, iostat_val
! Intervals
double precision :: dH(max_temps)
double precision :: t_high, t_low, sum_cp_hot, sum_cp_cold
double precision :: s_min, s_max
! Cascades
double precision :: cascade_I(0:max_temps)
double precision :: cascade_I_corr(0:max_temps)
double precision :: cascade_I_min, Q_H_min, Q_C_min, Q_recup_max
double precision :: T_pinch_shifted, T_pinch_hot, T_pinch_cold
! Hot Composite
double precision :: hot_temps(max_temps)
double precision :: unique_hot_temps(max_temps)
integer :: num_hot_temps, num_unique_hot
double precision :: hot_dH(max_temps)
double precision :: hot_H(max_temps)
double precision :: Q_hot_total
! Cold Composite
double precision :: cold_temps(max_temps)
double precision :: unique_cold_temps(max_temps)
integer :: num_cold_temps, num_unique_cold
double precision :: cold_dH(max_temps)
double precision :: cold_H(max_temps)
double precision :: Q_cold_total
double precision :: val, temp_val
logical :: found
! Read inputs
read(*,*,iostat=iostat_val) dT_min
if (iostat_val /= 0) then
write(*,*) 'ERROR: Invalid dT_min'
stop
end if
read(*,*,iostat=iostat_val) N
if (iostat_val /= 0 .or. N <= 0 .or. N > max_streams) then
write(*,*) 'ERROR: Invalid number of streams'
stop
end if
do i = 1, N
read(*,*,iostat=iostat_val) stream_type(i), Ts(i), Tt(i), CP(i)
if (iostat_val /= 0) then
write(*,*) 'ERROR: Invalid stream data at index ', i
stop
end if
if (stream_type(i) /= 1 .and. stream_type(i) /= 2) then
write(*,*) 'ERROR: Stream type must be 1 (Hot) or 2 (Cold) at index ', i
stop
end if
if (CP(i) < 0.0d0) then
write(*,*) 'ERROR: CP must be positive or zero at index ', i
stop
end if
end do
! 1. Shift Temperatures
do i = 1, N
if (stream_type(i) == 1) then
ts_shift(i) = Ts(i) - dT_min / 2.0d0
tt_shift(i) = Tt(i) - dT_min / 2.0d0
else
ts_shift(i) = Ts(i) + dT_min / 2.0d0
tt_shift(i) = Tt(i) + dT_min / 2.0d0
end if
end do
! 2. Gather unique shifted temperatures
do i = 1, N
shifted_temps(2*i - 1) = ts_shift(i)
shifted_temps(2*i) = tt_shift(i)
end do
m = 0
do i = 1, 2*N
val = shifted_temps(i)
found = .false.
do j = 1, m
if (abs(unique_temps(j) - val) < 1.0d-5) then
found = .true.
exit
end if
end do
if (.not. found) then
m = m + 1
unique_temps(m) = val
end if
end do
! Sort unique shifted temperatures descending
do i = 1, m-1
do j = i+1, m
if (unique_temps(j) > unique_temps(i)) then
temp_val = unique_temps(i)
unique_temps(i) = unique_temps(j)
unique_temps(j) = temp_val
end if
end do
end do
! 3. Interval heat balances
do j = 1, m-1
t_high = unique_temps(j)
t_low = unique_temps(j+1)
sum_cp_hot = 0.0d0
sum_cp_cold = 0.0d0
do i = 1, N
s_min = min(ts_shift(i), tt_shift(i))
s_max = max(ts_shift(i), tt_shift(i))
if (s_min <= t_low + 1.0d-5 .and. s_max >= t_high - 1.0d-5) then
if (stream_type(i) == 1) then
sum_cp_hot = sum_cp_hot + CP(i)
else
sum_cp_cold = sum_cp_cold + CP(i)
end if
end if
end do
dH(j) = (t_high - t_low) * (sum_cp_hot - sum_cp_cold)
end do
! 4. Heat Cascade
cascade_I(0) = 0.0d0
do j = 1, m-1
cascade_I(j) = cascade_I(j-1) + dH(j)
end do
cascade_I_min = 0.0d0
do j = 0, m-1
if (cascade_I(j) < cascade_I_min) then
cascade_I_min = cascade_I(j)
end if
end do
Q_H_min = 0.0d0
if (cascade_I_min < 0.0d0) then
Q_H_min = -cascade_I_min
end if
cascade_I_corr(0) = Q_H_min
do j = 1, m-1
cascade_I_corr(j) = cascade_I_corr(j-1) + dH(j)
end do
Q_C_min = cascade_I_corr(m-1)
! 5. Pinch point
T_pinch_shifted = -999.0d0
do j = 0, m-1
if (abs(cascade_I_corr(j)) < 1.0d-5) then
T_pinch_shifted = unique_temps(j+1)
exit
end if
end do
if (T_pinch_shifted == -999.0d0) then
! Fallback if no exact zero, use the minimum of cascade
T_pinch_shifted = unique_temps(m)
end if
T_pinch_hot = T_pinch_shifted + dT_min / 2.0d0
T_pinch_cold = T_pinch_shifted - dT_min / 2.0d0
! Total heat duty changes
Q_hot_total = 0.0d0
Q_cold_total = 0.0d0
do i = 1, N
if (stream_type(i) == 1) then
Q_hot_total = Q_hot_total + CP(i) * abs(Ts(i) - Tt(i))
else
Q_cold_total = Q_cold_total + CP(i) * abs(Ts(i) - Tt(i))
end if
end do
Q_recup_max = Q_hot_total - Q_C_min
! 6. Hot Composite Curve construction
num_hot_temps = 0
do i = 1, N
if (stream_type(i) == 1) then
num_hot_temps = num_hot_temps + 1
hot_temps(num_hot_temps) = Ts(i)
num_hot_temps = num_hot_temps + 1
hot_temps(num_hot_temps) = Tt(i)
end if
end do
num_unique_hot = 0
do i = 1, num_hot_temps
val = hot_temps(i)
found = .false.
do j = 1, num_unique_hot
if (abs(unique_hot_temps(j) - val) < 1.0d-5) then
found = .true.
exit
end if
end do
if (.not. found) then
num_unique_hot = num_unique_hot + 1
unique_hot_temps(num_unique_hot) = val
end if
end do
! Sort unique hot temps descending
do i = 1, num_unique_hot-1
do j = i+1, num_unique_hot
if (unique_hot_temps(j) > unique_hot_temps(i)) then
temp_val = unique_hot_temps(i)
unique_hot_temps(i) = unique_hot_temps(j)
unique_hot_temps(j) = temp_val
end if
end do
end do
! Integrate Hot Composite Curve Enthalpy
! We start at lowest temperature (unique_hot_temps(num_unique_hot)) with H = 0.0
hot_H(num_unique_hot) = 0.0d0
do j = num_unique_hot-1, 1, -1
t_low = unique_hot_temps(j+1)
t_high = unique_hot_temps(j)
sum_cp_hot = 0.0d0
do i = 1, N
if (stream_type(i) == 1) then
s_min = min(Ts(i), Tt(i))
s_max = max(Ts(i), Tt(i))
if (s_min <= t_low + 1.0d-5 .and. s_max >= t_high - 1.0d-5) then
sum_cp_hot = sum_cp_hot + CP(i)
end if
end if
end do
hot_dH(j) = (t_high - t_low) * sum_cp_hot
hot_H(j) = hot_H(j+1) + hot_dH(j)
end do
! 7. Cold Composite Curve construction
num_cold_temps = 0
do i = 1, N
if (stream_type(i) == 2) then
num_cold_temps = num_cold_temps + 1
cold_temps(num_cold_temps) = Ts(i)
num_cold_temps = num_cold_temps + 1
cold_temps(num_cold_temps) = Tt(i)
end if
end do
num_unique_cold = 0
do i = 1, num_cold_temps
val = cold_temps(i)
found = .false.
do j = 1, num_unique_cold
if (abs(unique_cold_temps(j) - val) < 1.0d-5) then
found = .true.
exit
end if
end do
if (.not. found) then
num_unique_cold = num_unique_cold + 1
unique_cold_temps(num_unique_cold) = val
end if
end do
! Sort unique cold temps descending
do i = 1, num_unique_cold-1
do j = i+1, num_unique_cold
if (unique_cold_temps(j) > unique_cold_temps(i)) then
temp_val = unique_cold_temps(i)
unique_cold_temps(i) = unique_cold_temps(j)
unique_cold_temps(j) = temp_val
end if
end do
end do
! Integrate Cold Composite Curve Enthalpy
! We start at lowest temperature (unique_cold_temps(num_unique_cold)) with H = 0.0,
! then in output we shift by Q_C_min.
cold_H(num_unique_cold) = 0.0d0
do j = num_unique_cold-1, 1, -1
t_low = unique_cold_temps(j+1)
t_high = unique_cold_temps(j)
sum_cp_cold = 0.0d0
do i = 1, N
if (stream_type(i) == 2) then
s_min = min(Ts(i), Tt(i))
s_max = max(Ts(i), Tt(i))
if (s_min <= t_low + 1.0d-5 .and. s_max >= t_high - 1.0d-5) then
sum_cp_cold = sum_cp_cold + CP(i)
end if
end if
end do
cold_dH(j) = (t_high - t_low) * sum_cp_cold
cold_H(j) = cold_H(j+1) + cold_dH(j)
end do
! Output results to stdout in KEY=value format
write(*,'(A,F18.4)') 'QH_MIN=', Q_H_min
write(*,'(A,F18.4)') 'QC_MIN=', Q_C_min
write(*,'(A,F18.4)') 'Q_RECUP_MAX=', Q_recup_max
write(*,'(A,F18.4)') 'T_PINCH_HOT=', T_pinch_hot
write(*,'(A,F18.4)') 'T_PINCH_COLD=', T_pinch_cold
! Output Hot Composite coordinates (sorted descending)
! They are already stored with unique_hot_temps descending, hot_H matching them.
write(*,'(A,I4)') 'HOT_COMP_PTS_COUNT=', num_unique_hot
write(*,'(A)',advance='no') 'HOT_COMP_H='
do j = 1, num_unique_hot
if (j > 1) write(*,'(A)',advance='no') ','
write(*,'(F18.4)',advance='no') hot_H(j)
end do
write(*,*) ''
write(*,'(A)',advance='no') 'HOT_COMP_T='
do j = 1, num_unique_hot
if (j > 1) write(*,'(A)',advance='no') ','
write(*,'(F18.4)',advance='no') unique_hot_temps(j)
end do
write(*,*) ''
! Output Cold Composite coordinates (sorted descending)
! They are already stored with unique_cold_temps descending, cold_H matching them.
! We shift the H value by Q_C_min.
write(*,'(A,I4)') 'COLD_COMP_PTS_COUNT=', num_unique_cold
write(*,'(A)',advance='no') 'COLD_COMP_H='
do j = 1, num_unique_cold
if (j > 1) write(*,'(A)',advance='no') ','
write(*,'(F18.4)',advance='no') cold_H(j) + Q_C_min
end do
write(*,*) ''
write(*,'(A)',advance='no') 'COLD_COMP_T='
do j = 1, num_unique_cold
if (j > 1) write(*,'(A)',advance='no') ','
write(*,'(F18.4)',advance='no') unique_cold_temps(j)
end do
write(*,*) ''
end program hx_pinch
Solver Description
Solve process utility targets and composite curve alignment coordinates using the Linnhoff-March Interval Temperature Table method. Calculates minimum hot utility $Q_{H,min}$, minimum cold utility $Q_{C,min}$, maximum heat recovery $Q_{recup,max}$, and locate pinch temperatures.
Key Numerical Methods & Architecture
- Input Redirection: Reads parameters sequentially from standard input (`stdin`) using Fortran sequential read (`read(*,*)`), ensuring modular integration.
- Modular Design: Formulated using pure mathematical routines, separation of equations from output formatting, and precise numerical solvers (e.g. bisection, Newton-Raphson).
- Standard Compliant: Written in clean, standards-compliant Fortran 90 to ensure cross-compiler compatibility.
🛠️ Local Compilation
To test this code on your machine, compile the source code file(s) using a standard Fortran compiler (e.g., `gfortran`).
Compilation Command:
Execution Command:
Execute the program by feeding the sample input file into the program using stdin redirection:
📥 Downloads & Local Files
Preview of the required input file (input.txt):
10.0
! Number of process streams N
4
! Stream 1: Type (1=Hot, 2=Cold), Ts [°C], Tt [°C], CP [kW/K]
1 150.0 60.0 20.0
! Stream 2: Type (1=Hot, 2=Cold), Ts [°C], Tt [°C], CP [kW/K]
1 90.0 60.0 80.0
! Stream 3: Type (1=Hot, 2=Cold), Ts [°C], Tt [°C], CP [kW/K]
2 20.0 125.0 25.0
! Stream 4: Type (1=Hot, 2=Cold), Ts [°C], Tt [°C], CP [kW/K]
2 80.0 140.0 30.0