Skip to content

Instantly share code, notes, and snippets.

@eskil
Created May 13, 2016 21:34
Show Gist options
  • Save eskil/a1b8365b31cb95253f78186125c89fda to your computer and use it in GitHub Desktop.
Save eskil/a1b8365b31cb95253f78186125c89fda to your computer and use it in GitHub Desktop.
VPM-B
PROGRAM VPMDECO
C===============================================================================
C Varying Permeability Model (VPM) Decompression Program in FORTRAN
C
C Author: Erik C. Baker
C
C "DISTRIBUTE FREELY - CREDIT THE AUTHORS"
C
C This program extends the 1986 VPM algorithm (Yount & Hoffman) to include
C mixed gas, repetitive, and altitude diving. Developments to the algorithm
C were made by David E. Yount, Eric B. Maiken, and Erik C. Baker over a
C period from 1999 to 2001. This work is dedicated in remembrance of
C Professor David E. Yount who passed away on April 27, 2000.
C
C Notes:
C 1. This program uses the sixteen (16) half-time compartments of the
C Buhlmann ZH-L16 model. The optional Compartment 1b is used here with
C half-times of 1.88 minutes for helium and 5.0 minutes for nitrogen.
C
C 2. This program uses various DEC, IBM, and Microsoft extensions which
C may not be supported by all FORTRAN compilers. Comments are made with
C a capital "C" in the first column or an exclamation point "!" placed
C in a line after code. An asterisk "*" in column 6 is a continuation
C of the previous line. All code, except for line numbers, starts in
C column 7.
C
C 3. Comments and suggestions for improvements are welcome. Please
C respond by e-mail to: EBaker@se.aeieng.com
C
C Acknowledgment: Thanks to Kurt Spaugh for recommendations on how to clean
C up the code.
C===============================================================================
IMPLICIT NONE
C===============================================================================
C LOCAL VARIABLES - MAIN PROGRAM
C===============================================================================
CHARACTER M*1, OS_Command*3, Word*7, Units*3
CHARACTER Line1*70, Critical_Volume_Algorithm*3
CHARACTER Units_Word1*4, Units_Word2*7, Altitude_Dive_Algorithm*3
INTEGER I, J !loop counters
INTEGER*2 Month, Day, Year, Clock_Hour, Minute
INTEGER Number_of_Mixes, Number_of_Changes, Profile_Code
INTEGER Segment_Number_Start_of_Ascent, Repetitive_Dive_Flag
LOGICAL Schedule_Converged, Critical_Volume_Algorithm_Off
LOGICAL Altitude_Dive_Algorithm_Off
REAL Deco_Ceiling_Depth, Deco_Stop_Depth, Step_Size
REAL Sum_of_Fractions, Sum_Check
REAL Depth, Ending_Depth, Starting_Depth
REAL Rate, Rounding_Operation1, Run_Time_End_of_Segment
REAL Last_Run_Time, Stop_Time, Depth_Start_of_Deco_Zone
REAL Rounding_Operation2, Deepest_Possible_Stop_Depth
REAL First_Stop_Depth, Critical_Volume_Comparison
REAL Next_Stop, Run_Time_Start_of_Deco_Zone
REAL Critical_Radius_N2_Microns, Critical_Radius_He_Microns
REAL Run_Time_Start_of_Ascent, Altitude_of_Dive
REAL Deco_Phase_Volume_Time, Surface_Interval_Time
REAL Pressure_Other_Gases_mmHg
C===============================================================================
C LOCAL ARRAYS - MAIN PROGRAM
C===============================================================================
INTEGER Mix_Change(10)
REAL Fraction_Oxygen(10)
REAL Depth_Change (10)
REAL Rate_Change(10), Step_Size_Change(10)
REAL Helium_Half_Time(16), Nitrogen_Half_Time(16)
REAL He_Pressure_Start_of_Ascent(16)
REAL N2_Pressure_Start_of_Ascent(16)
REAL He_Pressure_Start_of_Deco_Zone(16)
REAL N2_Pressure_Start_of_Deco_Zone(16)
REAL Phase_Volume_Time (16)
REAL Last_Phase_Volume_Time(16)
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Water_Vapor_Pressure
COMMON /Block_8/ Water_Vapor_Pressure
REAL Surface_Tension_Gamma, Skin_Compression_GammaC
COMMON /Block_19/ Surface_Tension_Gamma, Skin_Compression_GammaC
REAL Crit_Volume_Parameter_Lambda
COMMON /Block_20/ Crit_Volume_Parameter_Lambda
REAL Minimum_Deco_Stop_Time
COMMON /Block_21/ Minimum_Deco_Stop_Time
REAL Regeneration_Time_Constant
COMMON /Block_22/ Regeneration_Time_Constant
REAL Constant_Pressure_Other_Gases
COMMON /Block_17/ Constant_Pressure_Other_Gases
REAL Gradient_Onset_of_Imperm_Atm
COMMON /Block_14/ Gradient_Onset_of_Imperm_Atm
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
INTEGER Segment_Number
REAL Run_Time, Segment_Time
COMMON /Block_2/ Run_Time, Segment_Number, Segment_Time
REAL Ending_Ambient_Pressure
COMMON /Block_4/ Ending_Ambient_Pressure
INTEGER Mix_Number
COMMON /Block_9/ Mix_Number
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
LOGICAL Units_Equal_Fsw, Units_Equal_Msw
COMMON /Block_15/ Units_Equal_Fsw, Units_Equal_Msw
REAL Units_Factor
COMMON /Block_16/ Units_Factor
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Time_Constant(16)
COMMON /Block_1A/ Helium_Time_Constant
REAL Nitrogen_Time_Constant(16)
COMMON /Block_1B/ Nitrogen_Time_Constant
REAL Helium_Pressure(16), Nitrogen_Pressure(16)
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure
REAL Fraction_Helium(10), Fraction_Nitrogen(10)
COMMON /Block_5/ Fraction_Helium, Fraction_Nitrogen
REAL Initial_Critical_Radius_He(16)
REAL Initial_Critical_Radius_N2(16)
COMMON /Block_6/ Initial_Critical_Radius_He,
* Initial_Critical_Radius_N2
REAL Adjusted_Critical_Radius_He(16)
REAL Adjusted_Critical_Radius_N2(16)
COMMON /Block_7/ Adjusted_Critical_Radius_He,
* Adjusted_Critical_Radius_N2
REAL Max_Crushing_Pressure_He(16), Max_Crushing_Pressure_N2(16)
COMMON /Block_10/ Max_Crushing_Pressure_He,
* Max_Crushing_Pressure_N2
REAL Surface_Phase_Volume_Time(16)
COMMON /Block_11/ Surface_Phase_Volume_Time
REAL Max_Actual_Gradient(16)
COMMON /Block_12/ Max_Actual_Gradient
REAL Amb_Pressure_Onset_of_Imperm(16)
REAL Gas_Tension_Onset_of_Imperm(16)
COMMON /Block_13/ Amb_Pressure_Onset_of_Imperm,
* Gas_Tension_Onset_of_Imperm
C===============================================================================
C NAMELIST FOR PROGRAM SETTINGS (READ IN FROM ASCII TEXT FILE)
C===============================================================================
NAMELIST /Program_Settings/ Units, Altitude_Dive_Algorithm,
* Minimum_Deco_Stop_Time, Critical_Radius_N2_Microns,
* Critical_Radius_He_Microns, Critical_Volume_Algorithm,
* Crit_Volume_Parameter_Lambda,
* Gradient_Onset_of_Imperm_Atm,
* Surface_Tension_Gamma, Skin_Compression_GammaC,
* Regeneration_Time_Constant, Pressure_Other_Gases_mmHg
C===============================================================================
C ASSIGN HALF-TIME VALUES TO BUHLMANN COMPARTMENT ARRAYS
C===============================================================================
DATA Helium_Half_Time(1)/1.88/,Helium_Half_Time(2)/3.02/,
* Helium_Half_Time(3)/4.72/,Helium_Half_Time(4)/6.99/,
* Helium_Half_Time(5)/10.21/,Helium_Half_Time(6)/14.48/,
* Helium_Half_Time(7)/20.53/,Helium_Half_Time(8)/29.11/,
* Helium_Half_Time(9)/41.20/,Helium_Half_Time(10)/55.19/,
* Helium_Half_Time(11)/70.69/,Helium_Half_Time(12)/90.34/,
* Helium_Half_Time(13)/115.29/,Helium_Half_Time(14)/147.42/,
* Helium_Half_Time(15)/188.24/,Helium_Half_Time(16)/240.03/
DATA Nitrogen_Half_Time(1)/5.0/,Nitrogen_Half_Time(2)/8.0/,
* Nitrogen_Half_Time(3)/12.5/,Nitrogen_Half_Time(4)/18.5/,
* Nitrogen_Half_Time(5)/27.0/,Nitrogen_Half_Time(6)/38.3/,
* Nitrogen_Half_Time(7)/54.3/,Nitrogen_Half_Time(8)/77.0/,
* Nitrogen_Half_Time(9)/109.0/,Nitrogen_Half_Time(10)/146.0/,
* Nitrogen_Half_Time(11)/187.0/,Nitrogen_Half_Time(12)/239.0/,
* Nitrogen_Half_Time(13)/305.0/,Nitrogen_Half_Time(14)/390.0/,
* Nitrogen_Half_Time(15)/498.0/,Nitrogen_Half_Time(16)/635.0/
C===============================================================================
C OPEN FILES FOR PROGRAM INPUT/OUTPUT
C===============================================================================
OPEN (UNIT = 7, FILE = 'VPMDECO.IN', STATUS = 'UNKNOWN',
* ACCESS = 'SEQUENTIAL', FORM = 'FORMATTED')
OPEN (UNIT = 8, FILE = 'VPMDECO.OUT', STATUS = 'UNKNOWN',
* ACCESS = 'SEQUENTIAL', FORM = 'FORMATTED')
OPEN (UNIT = 10, FILE = 'VPMDECO.SET', STATUS = 'UNKNOWN',
* ACCESS = 'SEQUENTIAL', FORM = 'FORMATTED')
C===============================================================================
C BEGIN PROGRAM EXECUTION WITH OUTPUT MESSAGE TO SCREEN
C===============================================================================
OS_Command = 'CLS'
CALL SYSTEMQQ (OS_Command) !Pass "clear screen" command
PRINT *,' ' !to MS operating system
PRINT *,'PROGRAM VPMDECO'
PRINT *,' ' !asterisk indicates print to screen
C===============================================================================
C READ IN PROGRAM SETTINGS AND CHECK FOR ERRORS
C IF THERE ARE ERRORS, WRITE AN ERROR MESSAGE AND TERMINATE PROGRAM
C===============================================================================
READ (10,Program_Settings)
IF ((Units .EQ. 'fsw').OR.(Units .EQ. 'FSW')) THEN
Units_Equal_Fsw = (.TRUE.)
Units_Equal_Msw = (.FALSE.)
ELSE IF ((Units .EQ. 'msw').OR.(Units .EQ. 'MSW')) THEN
Units_Equal_Fsw = (.FALSE.)
Units_Equal_Msw = (.TRUE.)
ELSE
CALL SYSTEMQQ (OS_Command)
WRITE (*,901)
WRITE (*,900)
STOP 'PROGRAM TERMINATED'
END IF
IF ((Altitude_Dive_Algorithm .EQ. 'ON') .OR.
* (Altitude_Dive_Algorithm .EQ. 'on')) THEN
Altitude_Dive_Algorithm_Off = (.FALSE.)
ELSE IF ((Altitude_Dive_Algorithm .EQ. 'OFF') .OR.
* (Altitude_Dive_Algorithm .EQ. 'off')) THEN
Altitude_Dive_Algorithm_Off = (.TRUE.)
ELSE
WRITE (*,902)
WRITE (*,900)
STOP 'PROGRAM TERMINATED'
END IF
IF ((Critical_Radius_N2_Microns .LT. 0.2) .OR.
* (Critical_Radius_N2_Microns .GT. 1.35)) THEN
CALL SYSTEMQQ (OS_Command)
WRITE (*,903)
WRITE (*,900)
STOP 'PROGRAM TERMINATED'
END IF
IF ((Critical_Radius_He_Microns .LT. 0.2) .OR.
* (Critical_Radius_He_Microns .GT. 1.35)) THEN
CALL SYSTEMQQ (OS_Command)
WRITE (*,903)
WRITE (*,900)
STOP 'PROGRAM TERMINATED'
END IF
IF ((Critical_Volume_Algorithm .EQ. 'ON').OR.
* (Critical_Volume_Algorithm .EQ. 'on')) THEN
Critical_Volume_Algorithm_Off = (.FALSE.)
ELSE IF ((Critical_Volume_Algorithm .EQ. 'OFF').OR.
* (Critical_Volume_Algorithm .EQ. 'off')) THEN
Critical_Volume_Algorithm_Off = (.TRUE.)
ELSE
WRITE (*,904)
WRITE (*,900)
STOP 'PROGRAM TERMINATED'
END IF
C===============================================================================
C INITIALIZE CONSTANTS/VARIABLES BASED ON SELECTION OF UNITS - FSW OR MSW
C fsw = feet of seawater, a unit of pressure
C msw = meters of seawater, a unit of pressure
C===============================================================================
IF (Units_Equal_Fsw) THEN
WRITE (*,800)
Units_Word1 = 'fswg'
Units_Word2 = 'fsw/min'
Units_Factor = 33.0
Water_Vapor_Pressure = 1.607 !based on respiratory quotient of 0.8
!(Schreiner value)
END IF
IF (Units_Equal_Msw) THEN
WRITE (*,801)
Units_Word1 = 'mswg'
Units_Word2 = 'msw/min'
Units_Factor = 10.1325
Water_Vapor_Pressure = 0.493 !based on respiratory quotient of 0.8
END IF !(Schreiner value)
C===============================================================================
C INITIALIZE CONSTANTS/VARIABLES
C===============================================================================
Constant_Pressure_Other_Gases = (Pressure_Other_Gases_mmHg/760.0)
* * Units_Factor
Run_Time = 0.0
Segment_Number = 0
DO I = 1,16
Helium_Time_Constant(I) = ALOG(2.0)/Helium_Half_Time(I)
Nitrogen_Time_Constant(I) = ALOG(2.0)/Nitrogen_Half_Time(I)
Max_Crushing_Pressure_He(I) = 0.0
Max_Crushing_Pressure_N2(I) = 0.0
Max_Actual_Gradient(I) = 0.0
Surface_Phase_Volume_Time(I) = 0.0
Amb_Pressure_Onset_of_Imperm(I) = 0.0
Gas_Tension_Onset_of_Imperm(I) = 0.0
Initial_Critical_Radius_N2(I) = Critical_Radius_N2_Microns
* * 1.0E-6
Initial_Critical_Radius_He(I) = Critical_Radius_He_Microns
* * 1.0E-6
END DO
C===============================================================================
C INITIALIZE VARIABLES FOR SEA LEVEL OR ALTITUDE DIVE
C See subroutines for explanation of altitude calculations. Purposes are
C 1) to determine barometric pressure and 2) set or adjust the VPM critical
C radius variables and gas loadings, as applicable, based on altitude,
C ascent to altitude before the dive, and time at altitude before the dive
C===============================================================================
IF (Altitude_Dive_Algorithm_Off) THEN
Altitude_of_Dive = 0.0
CALL CALC_BAROMETRIC_PRESSURE (Altitude_of_Dive) !subroutine
WRITE (*,802) Altitude_of_Dive, Barometric_Pressure
DO I = 1,16
Adjusted_Critical_Radius_N2(I) = Initial_Critical_Radius_N2(I)
Adjusted_Critical_Radius_He(I) = Initial_Critical_Radius_He(I)
Helium_Pressure(I) = 0.0
Nitrogen_Pressure(I) = (Barometric_Pressure -
* Water_Vapor_Pressure)*0.79
END DO
ELSE
CALL VPM_ALTITUDE_DIVE_ALGORITHM !subroutine
END IF
C===============================================================================
C START OF REPETITIVE DIVE LOOP
C This is the largest loop in the main program and operates between Lines
C 30 and 330. If there is one or more repetitive dives, the program will
C return to this point to process each repetitive dive.
C===============================================================================
30 DO 330, WHILE (.TRUE.) !loop will run continuously until
!there is an exit statement
C===============================================================================
C INPUT DIVE DESCRIPTION AND GAS MIX DATA FROM ASCII TEXT INPUT FILE
C BEGIN WRITING HEADINGS/OUTPUT TO ASCII TEXT OUTPUT FILE
C See separate explanation of format for input file.
C===============================================================================
READ (7,805) Line1
CALL CLOCK (Year, Month, Day, Clock_Hour, Minute, M) !subroutine
WRITE (8,810)
WRITE (8,811)
WRITE (8,812)
WRITE (8,813)
WRITE (8,813)
WRITE (8,814) Month, Day, Year, Clock_Hour, Minute, M
WRITE (8,813)
WRITE (8,815) Line1
WRITE (8,813)
READ (7,*) Number_of_Mixes !check for errors in gasmixes
DO I = 1, Number_of_Mixes
READ (7,*) Fraction_Oxygen(I), Fraction_Helium(I),
* Fraction_Nitrogen(I)
Sum_of_Fractions = Fraction_Oxygen(I) + Fraction_Helium(I) +
* Fraction_Nitrogen(I)
Sum_Check = Sum_of_Fractions
IF (Sum_Check .NE. 1.0) THEN
CALL SYSTEMQQ (OS_Command)
WRITE (*,906)
WRITE (*,900)
STOP 'PROGRAM TERMINATED'
END IF
END DO
WRITE (8,820)
DO J = 1, Number_of_Mixes
WRITE (8,821) J, Fraction_Oxygen(J), Fraction_Helium(J),
* Fraction_Nitrogen(J)
END DO
WRITE (8,813)
WRITE (8,813)
WRITE (8,830)
WRITE (8,813)
WRITE (8,831)
WRITE (8,832)
WRITE (8,833) Units_Word1, Units_Word1, Units_Word2, Units_Word1
WRITE (8,834)
C===============================================================================
C DIVE PROFILE LOOP - INPUT DIVE PROFILE DATA FROM ASCII TEXT INPUT FILE
C AND PROCESS DIVE AS A SERIES OF ASCENT/DESCENT AND CONSTANT DEPTH
C SEGMENTS. THIS ALLOWS FOR MULTI-LEVEL DIVES AND UNUSUAL PROFILES. UPDATE
C GAS LOADINGS FOR EACH SEGMENT. IF IT IS A DESCENT SEGMENT, CALC CRUSHING
C PRESSURE ON CRITICAL RADII IN EACH COMPARTMENT.
C "Instantaneous" descents are not used in the VPM. All ascent/descent
C segments must have a realistic rate of ascent/descent. Unlike Haldanian
C models, the VPM is actually more conservative when the descent rate is
C slower becuase the effective crushing pressure is reduced. Also, a
C realistic actual supersaturation gradient must be calculated during
C ascents as this affects critical radii adjustments for repetitive dives.
C Profile codes: 1 = Ascent/Descent, 2 = Constant Depth, 99 = Decompress
C===============================================================================
DO WHILE (.TRUE.) !loop will run continuously until
!there is an exit statement
READ (7,*) Profile_Code
IF (Profile_Code .EQ. 1) THEN
READ (7,*) Starting_Depth, Ending_Depth, Rate, Mix_Number
CALL GAS_LOADINGS_ASCENT_DESCENT (Starting_Depth, !subroutine
* Ending_Depth, Rate)
IF (Ending_Depth .GT. Starting_Depth) THEN
CALL CALC_CRUSHING_PRESSURE (Starting_Depth, !subroutine
* Ending_Depth, Rate)
END IF
IF (Ending_Depth .GT. Starting_Depth) THEN
Word = 'Descent'
ELSE IF (Starting_Depth .GT. Ending_Depth) THEN
Word = 'Ascent '
ELSE
Word = 'ERROR'
END IF
WRITE (8,840) Segment_Number, Segment_Time, Run_Time,
* Mix_Number, Word, Starting_Depth, Ending_Depth,
* Rate
ELSE IF (Profile_Code .EQ. 2) THEN
READ (7,*) Depth, Run_Time_End_of_Segment, Mix_Number
CALL GAS_LOADINGS_CONSTANT_DEPTH (Depth, !subroutine
* Run_Time_End_of_Segment)
WRITE (8,845) Segment_Number, Segment_Time, Run_Time,
* Mix_Number, Depth
ELSE IF (Profile_Code .EQ. 99) THEN
EXIT
ELSE
CALL SYSTEMQQ (OS_Command)
WRITE (*,907)
WRITE (*,900)
STOP 'PROGRAM TERMINATED'
END IF
END DO
C===============================================================================
C BEGIN PROCESS OF ASCENT AND DECOMPRESSION
C First, calculate the regeneration of critical radii that takes place over
C the dive time. The regeneration time constant has a time scale of weeks
C so this will have very little impact on dives of normal length, but will
C have major impact for saturation dives.
C===============================================================================
CALL NUCLEAR_REGENERATION (Run_Time) !subroutine
C===============================================================================
C CALCULATE INITIAL ALLOWABLE GRADIENTS FOR ASCENT
C This is based on the maximum effective crushing pressure on critical radii
C in each compartment achieved during the dive profile.
C===============================================================================
CALL CALC_INITIAL_ALLOWABLE_GRADIENT !subroutine
C===============================================================================
C SAVE VARIABLES AT START OF ASCENT (END OF BOTTOM TIME) SINCE THESE WILL
C BE USED LATER TO COMPUTE THE FINAL ASCENT PROFILE THAT IS WRITTEN TO THE
C OUTPUT FILE.
C The VPM uses an iterative process to compute decompression schedules so
C there will be more than one pass through the decompression loop.
C===============================================================================
DO I = 1,16
He_Pressure_Start_of_Ascent(I) = Helium_Pressure(I)
N2_Pressure_Start_of_Ascent(I) = Nitrogen_Pressure(I)
END DO
Run_Time_Start_of_Ascent = Run_Time
Segment_Number_Start_of_Ascent = Segment_Number
C===============================================================================
C INPUT PARAMETERS TO BE USED FOR STAGED DECOMPRESSION AND SAVE IN ARRAYS.
C ASSIGN INITAL PARAMETERS TO BE USED AT START OF ASCENT
C The user has the ability to change mix, ascent rate, and step size in any
C combination at any depth during the ascent.
C===============================================================================
READ (7,*) Number_of_Changes
DO I = 1, Number_of_Changes
READ (7,*) Depth_Change(I), Mix_Change(I), Rate_Change(I),
* Step_Size_Change(I)
END DO
Starting_Depth = Depth_Change(1)
Mix_Number = Mix_Change(1)
Rate = Rate_Change(1)
Step_Size = Step_Size_Change(1)
C===============================================================================
C CALCULATE THE DEPTH WHERE THE DECOMPRESSION ZONE BEGINS FOR THIS PROFILE
C BASED ON THE INITIAL ASCENT PARAMETERS AND WRITE THE DEEPEST POSSIBLE
C DECOMPRESSION STOP DEPTH TO THE OUTPUT FILE
C Knowing where the decompression zone starts is very important. Below
C that depth there is no possibility for bubble formation because there
C will be no supersaturation gradients. Deco stops should never start
C below the deco zone. The deepest possible stop deco stop depth is
C defined as the next "standard" stop depth above the point where the
C leading compartment enters the deco zone. Thus, the program will not
C base this calculation on step sizes larger than 10 fsw or 3 msw. The
C deepest possible stop depth is not used in the program, per se, rather
C it is information to tell the diver where to start putting on the brakes
C during ascent. This should be prominently displayed by any deco program.
C===============================================================================
CALL CALC_START_OF_DECO_ZONE (Starting_Depth, Rate, !subroutine
* Depth_Start_of_Deco_Zone)
IF (Units_Equal_Fsw) THEN
IF (Step_Size .LT. 10.0) THEN
Rounding_Operation1 =
* (Depth_Start_of_Deco_Zone/Step_Size) - 0.5
Deepest_Possible_Stop_Depth = ANINT(Rounding_Operation1)
* * Step_Size
ELSE
Rounding_Operation1 = (Depth_Start_of_Deco_Zone/10.0)
* - 0.5
Deepest_Possible_Stop_Depth = ANINT(Rounding_Operation1)
* * 10.0
END IF
END IF
IF (Units_Equal_Msw) THEN
IF (Step_Size .LT. 3.0) THEN
Rounding_Operation1 =
* (Depth_Start_of_Deco_Zone/Step_Size) - 0.5
Deepest_Possible_Stop_Depth = ANINT(Rounding_Operation1)
* * Step_Size
ELSE
Rounding_Operation1 = (Depth_Start_of_Deco_Zone/3.0)
* - 0.5
Deepest_Possible_Stop_Depth = ANINT(Rounding_Operation1)
* * 3.0
END IF
END IF
WRITE (8,813)
WRITE (8,813)
WRITE (8,850)
WRITE (8,813)
WRITE (8,857) Depth_Start_of_Deco_Zone, Units_Word1
WRITE (8,858) Deepest_Possible_Stop_Depth, Units_Word1
WRITE (8,813)
WRITE (8,851)
WRITE (8,852)
WRITE (8,853) Units_Word1, Units_Word2, Units_Word1
WRITE (8,854)
C===============================================================================
C TEMPORARILY ASCEND PROFILE TO THE START OF THE DECOMPRESSION ZONE, SAVE
C VARIABLES AT THIS POINT, AND INITIALIZE VARIABLES FOR CRITICAL VOLUME LOOP
C The iterative process of the VPM Critical Volume Algorithm will operate
C only in the decompression zone since it deals with excess gas volume
C released as a result of supersaturation gradients (not possible below the
C decompression zone).
C===============================================================================
CALL GAS_LOADINGS_ASCENT_DESCENT (Starting_Depth, !subroutine
* Depth_Start_of_Deco_Zone, Rate)
Run_Time_Start_of_Deco_Zone = Run_Time
Deco_Phase_Volume_Time = 0.0
Last_Run_Time = 0.0
Schedule_Converged = (.FALSE.)
DO I = 1,16
Last_Phase_Volume_Time(I) = 0.0
He_Pressure_Start_of_Deco_Zone(I) = Helium_Pressure(I)
N2_Pressure_Start_of_Deco_Zone(I) = Nitrogen_Pressure(I)
Max_Actual_Gradient(I) = 0.0
END DO
C===============================================================================
C START OF CRITICAL VOLUME LOOP
C This loop operates between Lines 50 and 100. If the Critical Volume
C Algorithm is toggled "off" in the program settings, there will only be
C one pass through this loop. Otherwise, there will be two or more passes
C through this loop until the deco schedule is "converged" - that is when a
C comparison between the phase volume time of the present iteration and the
C last iteration is less than or equal to one minute. This implies that
C the volume of released gas in the most recent iteration differs from the
C "critical" volume limit by an acceptably small amount. The critical
C volume limit is set by the Critical Volume Parameter Lambda in the program
C settings (default setting is 7500 fsw-min with adjustability range from
C from 6500 to 8300 fsw-min according to Bruce Wienke).
C===============================================================================
50 DO 100, WHILE (.TRUE.) !loop will run continuously until
!there is an exit statement
C===============================================================================
C CALCULATE CURRENT DECO CEILING BASED ON ALLOWABLE SUPERSATURATION
C GRADIENTS AND SET FIRST DECO STOP. CHECK TO MAKE SURE THAT SELECTED STEP
C SIZE WILL NOT ROUND UP FIRST STOP TO A DEPTH THAT IS BELOW THE DECO ZONE.
C===============================================================================
CALL CALC_DECO_CEILING (Deco_Ceiling_Depth) !subroutine
IF (Deco_Ceiling_Depth .LE. 0.0) THEN
Deco_Stop_Depth = 0.0
ELSE
Rounding_Operation2 = (Deco_Ceiling_Depth/Step_Size) + 0.5
Deco_Stop_Depth = ANINT(Rounding_Operation2) * Step_Size
END IF
IF (Deco_Stop_Depth .GT. Depth_Start_of_Deco_Zone) THEN
WRITE (*,905)
WRITE (*,900)
STOP 'PROGRAM TERMINATED'
END IF
C===============================================================================
C PERFORM A SEPARATE "PROJECTED ASCENT" OUTSIDE OF THE MAIN PROGRAM TO MAKE
C SURE THAT AN INCREASE IN GAS LOADINGS DURING ASCENT TO THE FIRST STOP WILL
C NOT CAUSE A VIOLATION OF THE DECO CEILING. IF SO, ADJUST THE FIRST STOP
C DEEPER BASED ON STEP SIZE UNTIL A SAFE ASCENT CAN BE MADE.
C Note: this situation is a possibility when ascending from extremely deep
C dives or due to an unusual gas mix selection.
C CHECK AGAIN TO MAKE SURE THAT ADJUSTED FIRST STOP WILL NOT BE BELOW THE
C DECO ZONE.
C===============================================================================
CALL PROJECTED_ASCENT (Depth_Start_of_Deco_Zone, Rate, !subroutine
* Deco_Stop_Depth, Step_Size)
IF (Deco_Stop_Depth .GT. Depth_Start_of_Deco_Zone) THEN
WRITE (*,905)
WRITE (*,900)
STOP 'PROGRAM TERMINATED'
END IF
C===============================================================================
C HANDLE THE SPECIAL CASE WHEN NO DECO STOPS ARE REQUIRED - ASCENT CAN BE
C MADE DIRECTLY TO THE SURFACE
C Write ascent data to output file and exit the Critical Volume Loop.
C===============================================================================
IF (Deco_Stop_Depth .EQ. 0.0) THEN
DO I = 1,16
Helium_Pressure(I) = He_Pressure_Start_of_Ascent(I)
Nitrogen_Pressure(I) = N2_Pressure_Start_of_Ascent(I)
END DO
Run_Time = Run_Time_Start_of_Ascent
Segment_Number = Segment_Number_Start_of_Ascent
Starting_Depth = Depth_Change(1)
Ending_Depth = 0.0
CALL GAS_LOADINGS_ASCENT_DESCENT (Starting_Depth, !subroutine
* Ending_Depth, Rate)
WRITE (8,860) Segment_Number, Segment_Time, Run_Time,
* Mix_Number, Deco_Stop_Depth, Rate
EXIT !exit the critical volume loop at Line 100
END IF
C===============================================================================
C ASSIGN VARIABLES FOR ASCENT FROM START OF DECO ZONE TO FIRST STOP. SAVE
C FIRST STOP DEPTH FOR LATER USE WHEN COMPUTING THE FINAL ASCENT PROFILE
C===============================================================================
Starting_Depth = Depth_Start_of_Deco_Zone
First_Stop_Depth = Deco_Stop_Depth
C===============================================================================
C DECO STOP LOOP BLOCK WITHIN CRITICAL VOLUME LOOP
C This loop computes a decompression schedule to the surface during each
C iteration of the critical volume loop. No output is written from this
C loop, rather it computes a schedule from which the in-water portion of the
C total phase volume time (Deco_Phase_Volume_Time) can be extracted. Also,
C the gas loadings computed at the end of this loop are used the subroutine
C which computes the out-of-water portion of the total phase volume time
C (Surface_Phase_Volume_Time) for that schedule.
C
C Note that exit is made from the loop after last ascent is made to a deco
C stop depth that is less than or equal to zero. A final deco stop less
C than zero can happen when the user makes an odd step size change during
C ascent - such as specifying a 5 msw step size change at the 3 msw stop!
C===============================================================================
DO WHILE (.TRUE.) !loop will run continuously until
!there is an exit statement
CALL GAS_LOADINGS_ASCENT_DESCENT (Starting_Depth, !subroutine
* Deco_Stop_Depth, Rate)
IF (Deco_Stop_Depth .LE. 0.0) EXIT !exit at Line 60
IF (Number_of_Changes .GT. 1) THEN
DO I = 2, Number_of_Changes
IF (Depth_Change(I) .GE. Deco_Stop_Depth) THEN
Mix_Number = Mix_Change(I)
Rate = Rate_Change(I)
Step_Size = Step_Size_Change(I)
END IF
END DO
END IF
CALL DECOMPRESSION_STOP (Deco_Stop_Depth, Step_Size) !subroutine
Starting_Depth = Deco_Stop_Depth
Next_Stop = Deco_Stop_Depth - Step_Size
Deco_Stop_Depth = Next_Stop
Last_Run_Time = Run_Time
60 END DO !end of deco stop loop block
C===============================================================================
C COMPUTE TOTAL PHASE VOLUME TIME AND MAKE CRITICAL VOLUME COMPARISON
C The deco phase volume time is computed from the run time. The surface
C phase volume time is computed in a subroutine based on the surfacing gas
C loadings from previous deco loop block. Next the total phase volume time
C (in-water + surface) for each compartment is compared against the previous
C total phase volume time. The schedule is converged when the difference is
C less than or equal to 1 minute in any one of the 16 compartments.
C
C Note: the "phase volume time" is somewhat of a mathematical concept.
C It is the time divided out of a total integration of supersaturation
C gradient x time (in-water and surface). This integration is multiplied
C by the excess bubble number to represent the amount of free-gas released
C as a result of allowing a certain number of excess bubbles to form.
C===============================================================================
Deco_Phase_Volume_Time = Run_Time - Run_Time_Start_of_Deco_Zone
CALL CALC_SURFACE_PHASE_VOLUME_TIME !subroutine
DO I = 1,16
Phase_Volume_Time(I) = Deco_Phase_Volume_Time +
* Surface_Phase_Volume_Time(I)
Critical_Volume_Comparison = ABS(Phase_Volume_Time(I) -
* Last_Phase_Volume_Time(I))
IF (Critical_Volume_Comparison .LE. 1.0) THEN
Schedule_Converged = (.TRUE.)
END IF
END DO
C===============================================================================
C CRITICAL VOLUME DECISION TREE BETWEEN LINES 70 AND 99
C There are two options here. If the Critical Volume Agorithm setting is
C "on" and the schedule is converged, or the Critical Volume Algorithm
C setting was "off" in the first place, the program will re-assign variables
C to their values at the start of ascent (end of bottom time) and process
C a complete decompression schedule once again using all the same ascent
C parameters and first stop depth. This decompression schedule will match
C the last iteration of the Critical Volume Loop and the program will write
C the final deco schedule to the output file.
C
C Note: if the Critical Volume Agorithm setting was "off", the final deco
C schedule will be based on "Initial Allowable Supersaturation Gradients."
C If it was "on", the final schedule will be based on "Adjusted Allowable
C Supersaturation Gradients" (gradients that are "relaxed" as a result of
C the Critical Volume Algorithm).
C
C If the Critical Volume Agorithm setting is "on" and the schedule is not
C converged, the program will re-assign variables to their values at the
C start of the deco zone and process another trial decompression schedule.
C===============================================================================
70 IF ((Schedule_Converged) .OR.
* (Critical_Volume_Algorithm_Off)) THEN
DO I = 1,16
Helium_Pressure(I) = He_Pressure_Start_of_Ascent(I)
Nitrogen_Pressure(I) = N2_Pressure_Start_of_Ascent(I)
END DO
Run_Time = Run_Time_Start_of_Ascent
Segment_Number = Segment_Number_Start_of_Ascent
Starting_Depth = Depth_Change(1)
Mix_Number = Mix_Change(1)
Rate = Rate_Change(1)
Step_Size = Step_Size_Change(1)
Deco_Stop_Depth = First_Stop_Depth
Last_Run_Time = 0.0
C===============================================================================
C DECO STOP LOOP BLOCK FOR FINAL DECOMPRESSION SCHEDULE
C===============================================================================
DO WHILE (.TRUE.) !loop will run continuously until
!there is an exit statement
CALL GAS_LOADINGS_ASCENT_DESCENT (Starting_Depth, !subroutine
* Deco_Stop_Depth, Rate)
C===============================================================================
C DURING FINAL DECOMPRESSION SCHEDULE PROCESS, COMPUTE MAXIMUM ACTUAL
C SUPERSATURATION GRADIENT RESULTING IN EACH COMPARTMENT
C If there is a repetitive dive, this will be used later in the VPM
C Repetitive Algorithm to adjust the values for critical radii.
C===============================================================================
CALL CALC_MAX_ACTUAL_GRADIENT (Deco_Stop_Depth) !subroutine
WRITE (8,860) Segment_Number, Segment_Time, Run_Time,
* Mix_Number, Deco_Stop_Depth, Rate
IF (Deco_Stop_Depth .LE. 0.0) EXIT !exit at Line 80
IF (Number_of_Changes .GT. 1) THEN
DO I = 2, Number_of_Changes
IF (Depth_Change(I) .GE. Deco_Stop_Depth) THEN
Mix_Number = Mix_Change(I)
Rate = Rate_Change(I)
Step_Size = Step_Size_Change(I)
END IF
END DO
END IF
CALL DECOMPRESSION_STOP (Deco_Stop_Depth, Step_Size) !subroutine
C===============================================================================
C This next bit justs rounds up the stop time at the first stop to be in
C whole increments of the minimum stop time (to make for a nice deco table).
C===============================================================================
IF (Last_Run_Time .EQ. 0.0) THEN
Stop_Time =
* ANINT((Segment_Time/Minimum_Deco_Stop_Time) + 0.5) *
* Minimum_Deco_Stop_Time
ELSE
Stop_Time = Run_Time - Last_Run_Time
END IF
C===============================================================================
C DURING FINAL DECOMPRESSION SCHEDULE, IF MINIMUM STOP TIME PARAMETER IS A
C WHOLE NUMBER (i.e. 1 minute) THEN WRITE DECO SCHEDULE USING INTEGER
C NUMBERS (looks nicer). OTHERWISE, USE DECIMAL NUMBERS.
C Note: per the request of a noted exploration diver(!), program now allows
C a minimum stop time of less than one minute so that total ascent time can
C be minimized on very long dives. In fact, with step size set at 1 fsw or
C 0.2 msw and minimum stop time set at 0.1 minute (6 seconds), a near
C continuous decompression schedule can be computed.
C===============================================================================
IF (AINT(Minimum_Deco_Stop_Time) .EQ.
* Minimum_Deco_Stop_Time) THEN
WRITE (8,862) Segment_Number, Segment_Time, Run_Time,
* Mix_Number, INT(Deco_Stop_Depth),
* INT(Stop_Time), INT(Run_Time)
ELSE
WRITE (8,863) Segment_Number, Segment_Time, Run_Time,
* Mix_Number, Deco_Stop_Depth, Stop_Time,
* Run_Time
END IF
Starting_Depth = Deco_Stop_Depth
Next_Stop = Deco_Stop_Depth - Step_Size
Deco_Stop_Depth = Next_Stop
Last_Run_Time = Run_Time
80 END DO !end of deco stop loop block
!for final deco schedule
EXIT !exit critical volume loop at Line 100
!final deco schedule written
ELSE
C===============================================================================
C IF SCHEDULE NOT CONVERGED, COMPUTE RELAXED ALLOWABLE SUPERSATURATION
C GRADIENTS WITH VPM CRITICAL VOLUME ALGORITHM AND PROCESS ANOTHER
C ITERATION OF THE CRITICAL VOLUME LOOP
C===============================================================================
CALL CRITICAL_VOLUME (Deco_Phase_Volume_Time) !subroutine
Deco_Phase_Volume_Time = 0.0
Run_Time = Run_Time_Start_of_Deco_Zone
Starting_Depth = Depth_Start_of_Deco_Zone
Mix_Number = Mix_Change(1)
Rate = Rate_Change(1)
Step_Size = Step_Size_Change(1)
DO I = 1,16
Last_Phase_Volume_Time(I) = Phase_Volume_Time(I)
Helium_Pressure(I) = He_Pressure_Start_of_Deco_Zone(I)
Nitrogen_Pressure(I) = N2_Pressure_Start_of_Deco_Zone(I)
END DO
CYCLE !Return to start of critical volume loop
!(Line 50) to process another iteration
99 END IF !end of critical volume decision tree
100 CONTINUE !end of critical volume loop
C===============================================================================
C PROCESSING OF DIVE COMPLETE. READ INPUT FILE TO DETERMINE IF THERE IS A
C REPETITIVE DIVE. IF NONE, THEN EXIT REPETITIVE LOOP.
C===============================================================================
READ (7,*) Repetitive_Dive_Flag
IF (Repetitive_Dive_Flag .EQ. 0) THEN
EXIT !exit repetitive dive loop
!at Line 330
C===============================================================================
C IF THERE IS A REPETITIVE DIVE, COMPUTE GAS LOADINGS (OFF-GASSING) DURING
C SURFACE INTERVAL TIME. ADJUST CRITICAL RADII USING VPM REPETITIVE
C ALGORITHM. RE-INITIALIZE SELECTED VARIABLES AND RETURN TO START OF
C REPETITIVE LOOP AT LINE 30.
C===============================================================================
ELSE IF (Repetitive_Dive_Flag .EQ. 1) THEN
READ (7,*) Surface_Interval_Time
CALL GAS_LOADINGS_SURFACE_INTERVAL (Surface_Interval_Time) !subroutine
CALL VPM_REPETITIVE_ALGORITHM (Surface_Interval_Time) !subroutine
DO I = 1,16
Max_Crushing_Pressure_He(I) = 0.0
Max_Crushing_Pressure_N2(I) = 0.0
Max_Actual_Gradient(I) = 0.0
END DO
Run_Time = 0.0
Segment_Number = 0
WRITE (8,880)
WRITE (8,890)
WRITE (8,813)
CYCLE !Return to start of repetitive loop to process another dive
C===============================================================================
C WRITE ERROR MESSAGE AND TERMINATE PROGRAM IF THERE IS AN ERROR IN THE
C INPUT FILE FOR THE REPETITIVE DIVE FLAG
C===============================================================================
ELSE
CALL SYSTEMQQ (OS_Command)
WRITE (*,908)
WRITE (*,900)
STOP 'PROGRAM TERMINATED'
END IF
330 CONTINUE !End of repetitive loop
C===============================================================================
C FINAL WRITES TO OUTPUT AND CLOSE PROGRAM FILES
C===============================================================================
WRITE (*,813)
WRITE (*,871)
WRITE (*,872)
WRITE (*,813)
WRITE (8,880)
CLOSE (UNIT = 7, STATUS = 'KEEP')
CLOSE (UNIT = 8, STATUS = 'KEEP')
CLOSE (UNIT = 10, STATUS = 'KEEP')
C===============================================================================
C FORMAT STATEMENTS - PROGRAM INPUT/OUTPUT
C===============================================================================
800 FORMAT ('0UNITS = FEET OF SEAWATER (FSW)')
801 FORMAT ('0UNITS = METERS OF SEAWATER (MSW)')
802 FORMAT ('0ALTITUDE = ',1X,F7.1,4X,'BAROMETRIC PRESSURE = ',
*F6.3)
805 FORMAT (A70)
810 FORMAT ('E&a10L&l80F&l8D(s0p16.67h8.5')
811 FORMAT (26X,'DECOMPRESSION CALCULATION PROGRAM')
812 FORMAT (24X,'Developed in FORTRAN by Erik C. Baker')
814 FORMAT ('Program Run:',4X,I2.2,'-',I2.2,'-',I4,1X,'at',1X,I2.2,
* ':',I2.2,1X,A1,'m',23X,'Model: VPM 2001')
815 FORMAT ('Description:',4X,A70)
813 FORMAT (' ')
820 FORMAT ('Gasmix Summary:',24X,'FO2',4X,'FHe',4X,'FN2')
821 FORMAT (26X,'Gasmix #',I2,2X,F5.3,2X,F5.3,2X,F5.3)
830 FORMAT (36X,'DIVE PROFILE')
831 FORMAT ('Seg-',2X,'Segm.',2X,'Run',3X,'|',1X,'Gasmix',1X,'|',1X,
* 'Ascent',4X,'From',5X,'To',6X,'Rate',4X,'|',1X,'Constant')
832 FORMAT ('ment',2X,'Time',3X,'Time',2X,'|',2X,'Used',2X,'|',3X,
* 'or',5X,'Depth',3X,'Depth',4X,'+Dn/-Up',2X,'|',2X,'Depth')
833 FORMAT (2X,'#',3X,'(min)',2X,'(min)',1X,'|',4X,'#',3X,'|',1X,
* 'Descent',2X,'(',A4,')',2X,'(',A4,')',2X,'(',A7,')',1X,
* '|',2X,'(',A4,')')
834 FORMAT ('-----',1X,'-----',2X,'-----',1X,'|',1X,'------',1X,'|',
* 1X,'-------',2X,'------',2X,'------',2X,'---------',1X,
* '|',1X,'--------')
840 FORMAT (I3,3X,F5.1,1X,F6.1,1X,'|',3X,I2,3X,'|',1X,A7,F7.0,
* 1X,F7.0,3X,F7.1,3X,'|')
845 FORMAT (I3,3X,F5.1,1X,F6.1,1X,'|',3X,I2,3X,'|',36X,'|',F7.0)
850 FORMAT (31X,'DECOMPRESSION PROFILE')
851 FORMAT ('Seg-',2X,'Segm.',2X,'Run',3X,'|',1X,'Gasmix',1X,'|',1X,
* 'Ascent',3X,'Ascent',3X,'Col',3X,'|',2X,'DECO',3X,'STOP',
* 3X,'RUN')
852 FORMAT ('ment',2X,'Time',3X,'Time',2X,'|',2X,'Used',2X,'|',3X,
* 'To',6X,'Rate',4X,'Not',3X,'|',2X,'STOP',3X,'TIME',3X,
* 'TIME')
853 FORMAT (2X,'#',3X,'(min)',2X,'(min)',1X,'|',4X,'#',3X,'|',1X,
* '(',A4,')',1X,'(',A7,')',2X,'Used',2X,'|',1X,'(',A4,')',
* 2X,'(min)',2X,'(min)')
854 FORMAT ('-----',1X,'-----',2X,'-----',1X,'|',1X,'------',1X,'|',
* 1X,'------',1X,'---------',1X,'------',1X,'|',1X,
* '------',2X,'-----',2X,'-----')
857 FORMAT (10X,'Leading compartment enters the decompression zone',
* 1X,'at',F7.1,1X,A4)
858 FORMAT (17X,'Deepest possible decompression stop is',F7.1,1X,A4)
860 FORMAT (I3,3X,F5.1,1X,F6.1,1X,'|',3X,I2,3X,'|',2X,F4.0,3X,F6.1,
* 10X,'|')
862 FORMAT (I3,3X,F5.1,1X,F6.1,1X,'|',3X,I2,3X,'|',25X,'|',2X,I4,3X,
* I4,2X,I5)
863 FORMAT (I3,3X,F5.1,1X,F6.1,1X,'|',3X,I2,3X,'|',25X,'|',2X,F5.0,1X,
* F6.1,1X,F7.1)
871 FORMAT (' PROGRAM CALCULATIONS COMPLETE')
872 FORMAT ('0Output data is located in the file VPMDECO.OUT')
880 FORMAT (' ')
890 FORMAT ('REPETITIVE DIVE:')
C===============================================================================
C FORMAT STATEMENTS - ERROR MESSAGES
C===============================================================================
900 FORMAT (' ')
901 FORMAT ('0ERROR! UNITS MUST BE FSW OR MSW')
902 FORMAT ('0ERROR! ALTITUDE DIVE ALGORITHM MUST BE ON OR OFF')
903 FORMAT ('0ERROR! RADIUS MUST BE BETWEEN 0.2 AND 1.35 MICRONS')
904 FORMAT ('0ERROR! CRITICAL VOLUME ALGORITHM MUST BE ON OR OFF')
905 FORMAT ('0ERROR! STEP SIZE IS TOO LARGE TO DECOMPRESS')
906 FORMAT ('0ERROR IN INPUT FILE (GASMIX DATA)')
907 FORMAT ('0ERROR IN INPUT FILE (PROFILE CODE)')
908 FORMAT ('0ERROR IN INPUT FILE (REPETITIVE DIVE CODE)')
C===============================================================================
C END OF MAIN PROGRAM
C===============================================================================
END
C===============================================================================
C NOTE ABOUT PRESSURE UNITS USED IN CALCULATIONS:
C It is the convention in decompression calculations to compute all gas
C loadings, absolute pressures, partial pressures, etc., in the units of
C depth pressure that you are diving - either feet of seawater (fsw) or
C meters of seawater (msw). This program follows that convention with the
C the exception that all VPM calculations are performed in SI units (by
C necessity). Accordingly, there are several conversions back and forth
C between the diving pressure units and the SI units.
C===============================================================================
C===============================================================================
C FUNCTION SUBPROGRAM FOR GAS LOADING CALCULATIONS - ASCENT AND DESCENT
C===============================================================================
FUNCTION SCHREINER_EQUATION (Initial_Inspired_Gas_Pressure,
*Rate_Change_Insp_Gas_Pressure, Interval_Time, Gas_Time_Constant,
*Initial_Gas_Pressure)
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Initial_Inspired_Gas_Pressure !input
REAL Rate_Change_Insp_Gas_Pressure !input
REAL Interval_Time, Gas_Time_Constant !input
REAL Initial_Gas_Pressure !input
REAL SCHREINER_EQUATION !output
C===============================================================================
C Note: The Schreiner equation is applied when calculating the uptake or
C elimination of compartment gases during linear ascents or descents at a
C constant rate. For ascents, a negative number for rate must be used.
C===============================================================================
SCHREINER_EQUATION =
*Initial_Inspired_Gas_Pressure + Rate_Change_Insp_Gas_Pressure*
*(Interval_Time - 1.0/Gas_Time_Constant) -
*(Initial_Inspired_Gas_Pressure - Initial_Gas_Pressure -
*Rate_Change_Insp_Gas_Pressure/Gas_Time_Constant)*
*EXP (-Gas_Time_Constant*Interval_Time)
RETURN
END
C===============================================================================
C FUNCTION SUBPROGRAM FOR GAS LOADING CALCULATIONS - CONSTANT DEPTH
C===============================================================================
FUNCTION HALDANE_EQUATION (Initial_Gas_Pressure,
*Inspired_Gas_Pressure, Gas_Time_Constant, Interval_Time)
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Initial_Gas_Pressure, Inspired_Gas_Pressure !input
REAL Gas_Time_Constant, Interval_Time !input
REAL HALDANE_EQUATION !output
C===============================================================================
C Note: The Haldane equation is applied when calculating the uptake or
C elimination of compartment gases during intervals at constant depth (the
C outside ambient pressure does not change).
C===============================================================================
HALDANE_EQUATION = Initial_Gas_Pressure +
*(Inspired_Gas_Pressure - Initial_Gas_Pressure)*
*(1.0 - EXP(-Gas_Time_Constant * Interval_Time))
RETURN
END
C===============================================================================
C SUBROUTINE GAS_LOADINGS_ASCENT_DESCENT
C Purpose: This subprogram applies the Schreiner equation to update the
C gas loadings (partial pressures of helium and nitrogen) in the half-time
C compartments due to a linear ascent or descent segment at a constant rate.
C===============================================================================
SUBROUTINE GAS_LOADINGS_ASCENT_DESCENT (Starting_Depth,
* Ending_Depth, Rate)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Starting_Depth, Ending_Depth, Rate !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
INTEGER Last_Segment_Number
REAL Initial_Inspired_He_Pressure
REAL Initial_Inspired_N2_Pressure
REAL Last_Run_Time
REAL Helium_Rate, Nitrogen_Rate, Starting_Ambient_Pressure
REAL SCHREINER_EQUATION !function subprogram
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Water_Vapor_Pressure
COMMON /Block_8/ Water_Vapor_Pressure
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
INTEGER Segment_Number !both input
REAL Run_Time, Segment_Time !and output
COMMON /Block_2/ Run_Time, Segment_Number, Segment_Time
REAL Ending_Ambient_Pressure !output
COMMON /Block_4/ Ending_Ambient_Pressure
INTEGER Mix_Number
COMMON /Block_9/ Mix_Number
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Time_Constant(16)
COMMON /Block_1A/ Helium_Time_Constant
REAL Nitrogen_Time_Constant(16)
COMMON /Block_1B/ Nitrogen_Time_Constant
REAL Helium_Pressure(16), Nitrogen_Pressure(16) !both input
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure !and output
REAL Fraction_Helium(10), Fraction_Nitrogen(10)
COMMON /Block_5/ Fraction_Helium, Fraction_Nitrogen
REAL Initial_Helium_Pressure(16), Initial_Nitrogen_Pressure(16) !output
COMMON /Block_23/ Initial_Helium_Pressure,
* Initial_Nitrogen_Pressure
C===============================================================================
C CALCULATIONS
C===============================================================================
Segment_Time = (Ending_Depth - Starting_Depth)/Rate
Last_Run_Time = Run_Time
Run_Time = Last_Run_Time + Segment_Time
Last_Segment_Number = Segment_Number
Segment_Number = Last_Segment_Number + 1
Ending_Ambient_Pressure = Ending_Depth + Barometric_Pressure
Starting_Ambient_Pressure = Starting_Depth + Barometric_Pressure
Initial_Inspired_He_Pressure = (Starting_Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Helium(Mix_Number)
Initial_Inspired_N2_Pressure = (Starting_Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Nitrogen(Mix_Number)
Helium_Rate = Rate*Fraction_Helium(Mix_Number)
Nitrogen_Rate = Rate*Fraction_Nitrogen(Mix_Number)
DO I = 1,16
Initial_Helium_Pressure(I) = Helium_Pressure(I)
Initial_Nitrogen_Pressure(I) = Nitrogen_Pressure(I)
Helium_Pressure(I) = SCHREINER_EQUATION
* (Initial_Inspired_He_Pressure, Helium_Rate,
* Segment_Time, Helium_Time_Constant(I),
* Initial_Helium_Pressure(I))
Nitrogen_Pressure(I) = SCHREINER_EQUATION
* (Initial_Inspired_N2_Pressure, Nitrogen_Rate,
* Segment_Time, Nitrogen_Time_Constant(I),
* Initial_Nitrogen_Pressure(I))
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE CALC_CRUSHING_PRESSURE
C Purpose: Compute the effective "crushing pressure" in each compartment as
C a result of descent segment(s). The crushing pressure is the gradient
C (difference in pressure) between the outside ambient pressure and the
C gas tension inside a VPM nucleus (bubble seed). This gradient acts to
C reduce (shrink) the radius smaller than its initial value at the surface.
C This phenomenon has important ramifications because the smaller the radius
C of a VPM nucleus, the greater the allowable supersaturation gradient upon
C ascent. Gas loading (uptake) during descent, especially in the fast
C compartments, will reduce the magnitude of the crushing pressure. The
C crushing pressure is not cumulative over a multi-level descent. It will
C be the maximum value obtained in any one discrete segment of the overall
C descent. Thus, the program must compute and store the maximum crushing
C pressure for each compartment that was obtained across all segments of
C the descent profile.
C
C The calculation of crushing pressure will be different depending on
C whether or not the gradient is in the VPM permeable range (gas can diffuse
C across skin of VPM nucleus) or the VPM impermeable range (molecules in
C skin of nucleus are squeezed together so tight that gas can no longer
C diffuse in or out of nucleus; the gas becomes trapped and further resists
C the crushing pressure). The solution for crushing pressure in the VPM
C permeable range is a simple linear equation. In the VPM impermeable
C range, a cubic equation must be solved using a numerical method.
C
C Separate crushing pressures are tracked for helium and nitrogen because
C they can have different critical radii. The crushing pressures will be
C the same for helium and nitrogen in the permeable range of the model, but
C they will start to diverge in the impermeable range. This is due to
C the differences between starting radius, radius at the onset of
C impermeability, and radial compression in the impermeable range.
C===============================================================================
SUBROUTINE CALC_CRUSHING_PRESSURE (Starting_Depth, Ending_Depth,
* Rate)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Starting_Depth, Ending_Depth, Rate !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Starting_Ambient_Pressure, Ending_Ambient_Pressure
REAL Starting_Gas_Tension, Ending_Gas_Tension
REAL Crushing_Pressure_He, Crushing_Pressure_N2
REAL Gradient_Onset_of_Imperm, Gradient_Onset_of_Imperm_Pa
REAL Ending_Ambient_Pressure_Pa, Amb_Press_Onset_of_Imperm_Pa
REAL Gas_Tension_Onset_of_Imperm_Pa
REAL Crushing_Pressure_Pascals_He, Crushing_Pressure_Pascals_N2
REAL Starting_Gradient, Ending_Gradient
REAL A_He, B_He, C_He, Ending_Radius_He, High_Bound_He
REAL Low_Bound_He
REAL A_N2, B_N2, C_N2, Ending_Radius_N2, High_Bound_N2
REAL Low_Bound_N2
REAL Radius_Onset_of_Imperm_He, Radius_Onset_of_Imperm_N2
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Gradient_Onset_of_Imperm_Atm
COMMON /Block_14/ Gradient_Onset_of_Imperm_Atm
REAL Constant_Pressure_Other_Gases
COMMON /Block_17/ Constant_Pressure_Other_Gases
REAL Surface_Tension_Gamma, Skin_Compression_GammaC
COMMON /Block_19/ Surface_Tension_Gamma, Skin_Compression_GammaC
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
REAL Units_Factor
COMMON /Block_16/ Units_Factor
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Pressure(16), Nitrogen_Pressure(16) !input
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure
REAL Adjusted_Critical_Radius_He(16) !input
REAL Adjusted_Critical_Radius_N2(16)
COMMON /Block_7/ Adjusted_Critical_Radius_He,
* Adjusted_Critical_Radius_N2
REAL Max_Crushing_Pressure_He(16), Max_Crushing_Pressure_N2(16) !output
COMMON /Block_10/ Max_Crushing_Pressure_He,
* Max_Crushing_Pressure_N2
REAL Amb_Pressure_Onset_of_Imperm(16) !input
REAL Gas_Tension_Onset_of_Imperm(16)
COMMON /Block_13/ Amb_Pressure_Onset_of_Imperm,
* Gas_Tension_Onset_of_Imperm
REAL Initial_Helium_Pressure(16), Initial_Nitrogen_Pressure(16) !input
COMMON /Block_23/ Initial_Helium_Pressure,
* Initial_Nitrogen_Pressure
C===============================================================================
C CALCULATIONS
C First, convert the Gradient for Onset of Impermeability from units of
C atmospheres to diving pressure units (either fsw or msw) and to Pascals
C (SI units). The reason that the Gradient for Onset of Impermeability is
C given in the program settings in units of atmospheres is because that is
C how it was reported in the original research papers by Yount and
C colleauges.
C===============================================================================
Gradient_Onset_of_Imperm = Gradient_Onset_of_Imperm_Atm !convert to
* * Units_Factor !diving units
Gradient_Onset_of_Imperm_Pa = Gradient_Onset_of_Imperm_Atm !convert to
* * 101325.0 !Pascals
C===============================================================================
C Assign values of starting and ending ambient pressures for descent segment
C===============================================================================
Starting_Ambient_Pressure = Starting_Depth + Barometric_Pressure
Ending_Ambient_Pressure = Ending_Depth + Barometric_Pressure
C===============================================================================
C MAIN LOOP WITH NESTED DECISION TREE
C For each compartment, the program computes the starting and ending
C gas tensions and gradients. The VPM is different than some dissolved gas
C algorithms, Buhlmann for example, in that it considers the pressure due to
C oxygen, carbon dioxide, and water vapor in each compartment in addition to
C the inert gases helium and nitrogen. These "other gases" are included in
C the calculation of gas tensions and gradients.
C===============================================================================
DO I = 1,16
Starting_Gas_Tension = Initial_Helium_Pressure(I) +
* Initial_Nitrogen_Pressure(I) + Constant_Pressure_Other_Gases
Starting_Gradient = Starting_Ambient_Pressure -
* Starting_Gas_Tension
Ending_Gas_Tension = Helium_Pressure(I) + Nitrogen_Pressure(I)
* + Constant_Pressure_Other_Gases
Ending_Gradient = Ending_Ambient_Pressure - Ending_Gas_Tension
C===============================================================================
C Compute radius at onset of impermeability for helium and nitrogen
C critical radii
C===============================================================================
Radius_Onset_of_Imperm_He = 1.0/(Gradient_Onset_of_Imperm_Pa/
* (2.0*(Skin_Compression_GammaC-Surface_Tension_Gamma)) +
* 1.0/Adjusted_Critical_Radius_He(I))
Radius_Onset_of_Imperm_N2 = 1.0/(Gradient_Onset_of_Imperm_Pa/
* (2.0*(Skin_Compression_GammaC-Surface_Tension_Gamma)) +
* 1.0/Adjusted_Critical_Radius_N2(I))
C===============================================================================
C FIRST BRANCH OF DECISION TREE - PERMEABLE RANGE
C Crushing pressures will be the same for helium and nitrogen
C===============================================================================
IF (Ending_Gradient .LE. Gradient_Onset_of_Imperm) THEN
Crushing_Pressure_He = Ending_Ambient_Pressure -
* Ending_Gas_Tension
Crushing_Pressure_N2 = Ending_Ambient_Pressure -
* Ending_Gas_Tension
END IF
C===============================================================================
C SECOND BRANCH OF DECISION TREE - IMPERMEABLE RANGE
C Both the ambient pressure and the gas tension at the onset of
C impermeability must be computed in order to properly solve for the ending
C radius and resultant crushing pressure. The first decision block
C addresses the special case when the starting gradient just happens to be
C equal to the gradient for onset of impermeability (not very likely!).
C===============================================================================
IF (Ending_Gradient .GT. Gradient_Onset_of_Imperm) THEN
IF(Starting_Gradient .EQ. Gradient_Onset_of_Imperm) THEN
Amb_Pressure_Onset_of_Imperm(I) =
* Starting_Ambient_Pressure
Gas_Tension_Onset_of_Imperm(I) = Starting_Gas_Tension
END IF
C===============================================================================
C In most cases, a subroutine will be called to find these values using a
C numerical method.
C===============================================================================
IF(Starting_Gradient .LT. Gradient_Onset_of_Imperm) THEN
CALL ONSET_OF_IMPERMEABILITY !subroutine
* (Starting_Ambient_Pressure,
* Ending_Ambient_Pressure, Rate, I)
END IF
C===============================================================================
C Next, using the values for ambient pressure and gas tension at the onset
C of impermeability, the equations are set up to process the calculations
C through the radius root finder subroutine. This subprogram will find the
C root (solution) to the cubic equation using a numerical method. In order
C to do this efficiently, the equations are placed in the form
C Ar^3 - Br^2 - C = 0, where r is the ending radius after impermeable
C compression. The coefficients A, B, and C for helium and nitrogen are
C computed and passed to the subroutine as arguments. The high and low
C bounds to be used by the numerical method of the subroutine are also
C computed (see separate page posted on Deco List ftp site entitled
C "VPM: Solving for radius in the impermeable regime"). The subprogram
C will return the value of the ending radius and then the crushing
C pressures for helium and nitrogen can be calculated.
C===============================================================================
Ending_Ambient_Pressure_Pa =
* (Ending_Ambient_Pressure/Units_Factor) * 101325.0
Amb_Press_Onset_of_Imperm_Pa =
* (Amb_Pressure_Onset_of_Imperm(I)/Units_Factor)
* * 101325.0
Gas_Tension_Onset_of_Imperm_Pa =
* (Gas_Tension_Onset_of_Imperm(I)/Units_Factor)
* * 101325.0
B_He = 2.0*(Skin_Compression_GammaC-Surface_Tension_Gamma)
A_He = Ending_Ambient_Pressure_Pa -
* Amb_Press_Onset_of_Imperm_Pa +
* Gas_Tension_Onset_of_Imperm_Pa +
* (2.0*(Skin_Compression_GammaC-Surface_Tension_Gamma))
* /Radius_Onset_of_Imperm_He
C_He = Gas_Tension_Onset_of_Imperm_Pa *
* Radius_Onset_of_Imperm_He**3
High_Bound_He = Radius_Onset_of_Imperm_He
Low_Bound_He = B_He/A_He
CALL RADIUS_ROOT_FINDER (A_He,B_He,C_He, !subroutine
* Low_Bound_He, High_Bound_He, Ending_Radius_He)
Crushing_Pressure_Pascals_He =
* Gradient_Onset_of_Imperm_Pa +
* Ending_Ambient_Pressure_Pa -
* Amb_Press_Onset_of_Imperm_Pa +
* Gas_Tension_Onset_of_Imperm_Pa *
* (1.0-Radius_Onset_of_Imperm_He**3/Ending_Radius_He**3)
Crushing_Pressure_He =
* (Crushing_Pressure_Pascals_He/101325.0) * Units_Factor
B_N2 = 2.0*(Skin_Compression_GammaC-Surface_Tension_Gamma)
A_N2 = Ending_Ambient_Pressure_Pa -
* Amb_Press_Onset_of_Imperm_Pa +
* Gas_Tension_Onset_of_Imperm_Pa +
* (2.0*(Skin_Compression_GammaC-Surface_Tension_Gamma))
* /Radius_Onset_of_Imperm_N2
C_N2 = Gas_Tension_Onset_of_Imperm_Pa *
* Radius_Onset_of_Imperm_N2**3
High_Bound_N2 = Radius_Onset_of_Imperm_N2
Low_Bound_N2 = B_N2/A_N2
CALL RADIUS_ROOT_FINDER (A_N2,B_N2,C_N2, !subroutine
* Low_Bound_N2,High_Bound_N2, Ending_Radius_N2)
Crushing_Pressure_Pascals_N2 =
* Gradient_Onset_of_Imperm_Pa +
* Ending_Ambient_Pressure_Pa -
* Amb_Press_Onset_of_Imperm_Pa +
* Gas_Tension_Onset_of_Imperm_Pa *
* (1.0-Radius_Onset_of_Imperm_N2**3/Ending_Radius_N2**3)
Crushing_Pressure_N2 =
* (Crushing_Pressure_Pascals_N2/101325.0) * Units_Factor
END IF
C===============================================================================
C UPDATE VALUES OF MAX CRUSHING PRESSURE IN GLOBAL ARRAYS
C===============================================================================
Max_Crushing_Pressure_He(I) = MAX(Max_Crushing_Pressure_He(I),
* Crushing_Pressure_He)
Max_Crushing_Pressure_N2(I) = MAX(Max_Crushing_Pressure_N2(I),
* Crushing_Pressure_N2)
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE ONSET_OF_IMPERMEABILITY
C Purpose: This subroutine uses the Bisection Method to find the ambient
C pressure and gas tension at the onset of impermeability for a given
C compartment. Source: "Numerical Recipes in Fortran 77",
C Cambridge University Press, 1992.
C===============================================================================
SUBROUTINE ONSET_OF_IMPERMEABILITY (Starting_Ambient_Pressure,
* Ending_Ambient_Pressure, Rate, I)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
INTEGER I !input - array subscript for compartment
REAL Starting_Ambient_Pressure, Ending_Ambient_Pressure, Rate !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER J !loop counter
REAL Initial_Inspired_He_Pressure
REAL Initial_Inspired_N2_Pressure, Time
REAL Helium_Rate, Nitrogen_Rate
REAL Low_Bound, High_Bound, High_Bound_Helium_Pressure
REAL High_Bound_Nitrogen_Pressure, Mid_Range_Helium_Pressure
REAL Mid_Range_Nitrogen_Pressure, Last_Diff_Change
REAL Function_at_High_Bound, Function_at_Low_Bound
REAL Mid_Range_Time, Function_at_Mid_Range, Differential_Change
REAL Mid_Range_Ambient_Pressure, Gas_Tension_at_Mid_Range
REAL Gradient_Onset_of_Imperm
REAL Starting_Gas_Tension, Ending_Gas_Tension
REAL SCHREINER_EQUATION !function subprogram
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Water_Vapor_Pressure
COMMON /Block_8/ Water_Vapor_Pressure
REAL Gradient_Onset_of_Imperm_Atm
COMMON /Block_14/ Gradient_Onset_of_Imperm_Atm
REAL Constant_Pressure_Other_Gases
COMMON /Block_17/ Constant_Pressure_Other_Gases
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
INTEGER Mix_Number
COMMON /Block_9/ Mix_Number
REAL Units_Factor
COMMON /Block_16/ Units_Factor
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Time_Constant(16)
COMMON /Block_1A/ Helium_Time_Constant
REAL Nitrogen_Time_Constant(16)
COMMON /Block_1B/ Nitrogen_Time_Constant
REAL Fraction_Helium(10), Fraction_Nitrogen(10)
COMMON /Block_5/ Fraction_Helium, Fraction_Nitrogen
REAL Amb_Pressure_Onset_of_Imperm(16) !output
REAL Gas_Tension_Onset_of_Imperm(16)
COMMON /Block_13/ Amb_Pressure_Onset_of_Imperm,
* Gas_Tension_Onset_of_Imperm
REAL Initial_Helium_Pressure(16), Initial_Nitrogen_Pressure(16) !input
COMMON /Block_23/ Initial_Helium_Pressure,
* Initial_Nitrogen_Pressure
C===============================================================================
C CALCULATIONS
C First convert the Gradient for Onset of Impermeability to the diving
C pressure units that are being used
C===============================================================================
Gradient_Onset_of_Imperm = Gradient_Onset_of_Imperm_Atm
* * Units_Factor
C===============================================================================
C ESTABLISH THE BOUNDS FOR THE ROOT SEARCH USING THE BISECTION METHOD
C In this case, we are solving for time - the time when the ambient pressure
C minus the gas tension will be equal to the Gradient for Onset of
C Impermeabliity. The low bound for time is set at zero and the high
C bound is set at the elapsed time (segment time) it took to go from the
C starting ambient pressure to the ending ambient pressure. The desired
C ambient pressure and gas tension at the onset of impermeability will
C be found somewhere between these endpoints. The algorithm checks to
C make sure that the solution lies in between these bounds by first
C computing the low bound and high bound function values.
C===============================================================================
Initial_Inspired_He_Pressure = (Starting_Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Helium(Mix_Number)
Initial_Inspired_N2_Pressure = (Starting_Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Nitrogen(Mix_Number)
Helium_Rate = Rate*Fraction_Helium(Mix_Number)
Nitrogen_Rate = Rate*Fraction_Nitrogen(Mix_Number)
Low_Bound = 0.0
High_Bound = (Ending_Ambient_Pressure - Starting_Ambient_Pressure)
* /Rate
Starting_Gas_Tension = Initial_Helium_Pressure(I) +
* Initial_Nitrogen_Pressure(I) + Constant_Pressure_Other_Gases
Function_at_Low_Bound = Starting_Ambient_Pressure -
* Starting_Gas_Tension - Gradient_Onset_of_Imperm
High_Bound_Helium_Pressure = SCHREINER_EQUATION
* (Initial_Inspired_He_Pressure, Helium_Rate,
* High_Bound, Helium_Time_Constant(I),
* Initial_Helium_Pressure(I))
High_Bound_Nitrogen_Pressure = SCHREINER_EQUATION
* (Initial_Inspired_N2_Pressure, Nitrogen_Rate,
* High_Bound, Nitrogen_Time_Constant(I),
* Initial_Nitrogen_Pressure(I))
Ending_Gas_Tension = High_Bound_Helium_Pressure +
* High_Bound_Nitrogen_Pressure + Constant_Pressure_Other_Gases
Function_at_High_Bound = Ending_Ambient_Pressure -
* Ending_Gas_Tension - Gradient_Onset_of_Imperm
IF ((Function_at_High_Bound*Function_at_Low_Bound) .GE. 0.0) THEN
PRINT *,'ERROR! ROOT IS NOT WITHIN BRACKETS'
PAUSE
END IF
C===============================================================================
C APPLY THE BISECTION METHOD IN SEVERAL ITERATIONS UNTIL A SOLUTION WITH
C THE DESIRED ACCURACY IS FOUND
C Note: the program allows for up to 100 iterations. Normally an exit will
C be made from the loop well before that number. If, for some reason, the
C program exceeds 100 iterations, there will be a pause to alert the user.
C===============================================================================
IF (Function_at_Low_Bound .LT. 0.0) THEN
Time = Low_Bound
Differential_Change = High_Bound - Low_Bound
ELSE
Time = High_Bound
Differential_Change = Low_Bound - High_Bound
END IF
DO J = 1, 100
Last_Diff_Change = Differential_Change
Differential_Change = Last_Diff_Change*0.5
Mid_Range_Time = Time + Differential_Change
Mid_Range_Ambient_Pressure = (Starting_Ambient_Pressure +
* Rate*Mid_Range_Time)
Mid_Range_Helium_Pressure = SCHREINER_EQUATION
* (Initial_Inspired_He_Pressure, Helium_Rate,
* Mid_Range_Time, Helium_Time_Constant(I),
* Initial_Helium_Pressure(I))
Mid_Range_Nitrogen_Pressure = SCHREINER_EQUATION
* (Initial_Inspired_N2_Pressure, Nitrogen_Rate,
* Mid_Range_Time, Nitrogen_Time_Constant(I),
* Initial_Nitrogen_Pressure(I))
Gas_Tension_at_Mid_Range = Mid_Range_Helium_Pressure +
* Mid_Range_Nitrogen_Pressure + Constant_Pressure_Other_Gases
Function_at_Mid_Range = Mid_Range_Ambient_Pressure -
* Gas_Tension_at_Mid_Range - Gradient_Onset_of_Imperm
IF (Function_at_Mid_Range .LE. 0.0) Time = Mid_Range_Time
IF ((ABS(Differential_Change) .LT. 1.0E-3) .OR.
* (Function_at_Mid_Range .EQ. 0.0)) GOTO 100
END DO
PRINT *,'ERROR! ROOT SEARCH EXCEEDED MAXIMUM ITERATIONS'
PAUSE
C===============================================================================
C When a solution with the desired accuracy is found, the program jumps out
C of the loop to Line 100 and assigns the solution values for ambient
C pressure and gas tension at the onset of impermeability.
C===============================================================================
100 Amb_Pressure_Onset_of_Imperm(I) = Mid_Range_Ambient_Pressure
Gas_Tension_Onset_of_Imperm(I) = Gas_Tension_at_Mid_Range
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE RADIUS_ROOT_FINDER
C Purpose: This subroutine is a "fail-safe" routine that combines the
C Bisection Method and the Newton-Raphson Method to find the desired root.
C This hybrid algorithm takes a bisection step whenever Newton-Raphson would
C take the solution out of bounds, or whenever Newton-Raphson is not
C converging fast enough. Source: "Numerical Recipes in Fortran 77",
C Cambridge University Press, 1992.
C===============================================================================
SUBROUTINE RADIUS_ROOT_FINDER (A,B,C, Low_Bound, High_Bound,
* Ending_Radius)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL A, B, C, Low_Bound, High_Bound !input
REAL Ending_Radius !output
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Function, Derivative_of_Function, Differential_Change
REAL Last_Diff_Change, Last_Ending_Radius
REAL Radius_at_Low_Bound, Radius_at_High_Bound
REAL Function_at_Low_Bound, Function_at_High_Bound
C===============================================================================
C BEGIN CALCULATIONS BY MAKING SURE THAT THE ROOT LIES WITHIN BOUNDS
C In this case we are solving for radius in a cubic equation of the form,
C Ar^3 - Br^2 - C = 0. The coefficients A, B, and C were passed to this
C subroutine as arguments.
C===============================================================================
Function_at_Low_Bound =
* Low_Bound*(Low_Bound*(A*Low_Bound - B)) - C
Function_at_High_Bound =
* High_Bound*(High_Bound*(A*High_Bound - B)) - C
IF ((Function_at_Low_Bound .GT. 0.0).AND.
* (Function_at_High_Bound .GT. 0.0)) THEN
PRINT *,'ERROR! ROOT IS NOT WITHIN BRACKETS'
PAUSE
END IF
C===============================================================================
C Next the algorithm checks for special conditions and then prepares for
C the first bisection.
C===============================================================================
IF ((Function_at_Low_Bound .LT. 0.0).AND.
* (Function_at_High_Bound .LT. 0.0)) THEN
PRINT *,'ERROR! ROOT IS NOT WITHIN BRACKETS'
PAUSE
END IF
IF (Function_at_Low_Bound .EQ. 0.0) THEN
Ending_Radius = Low_Bound
RETURN
ELSE IF (Function_at_High_Bound .EQ. 0.0) THEN
Ending_Radius = High_Bound
RETURN
ELSE IF (Function_at_Low_Bound .LT. 0.0) THEN
Radius_at_Low_Bound = Low_Bound
Radius_at_High_Bound = High_Bound
ELSE
Radius_at_High_Bound = Low_Bound
Radius_at_Low_Bound = High_Bound
END IF
Ending_Radius = 0.5*(Low_Bound + High_Bound)
Last_Diff_Change = ABS(High_Bound-Low_Bound)
Differential_Change = Last_Diff_Change
C===============================================================================
C At this point, the Newton-Raphson Method is applied which uses a function
C and its first derivative to rapidly converge upon a solution.
C Note: the program allows for up to 100 iterations. Normally an exit will
C be made from the loop well before that number. If, for some reason, the
C program exceeds 100 iterations, there will be a pause to alert the user.
C When a solution with the desired accuracy is found, exit is made from the
C loop by returning to the calling program. The last value of ending
C radius has been assigned as the solution.
C===============================================================================
Function = Ending_Radius*(Ending_Radius*(A*Ending_Radius - B)) - C
Derivative_of_Function =
* Ending_Radius*(Ending_Radius*3.0*A - 2.0*B)
DO I = 1,100
IF((((Ending_Radius-Radius_at_High_Bound)*
* Derivative_of_Function-Function)*
* ((Ending_Radius-Radius_at_Low_Bound)*
* Derivative_of_Function-Function).GE.0.0) .OR.
* (ABS(2.0*Function).GT.
* (ABS(Last_Diff_Change*Derivative_of_Function)))) THEN
Last_Diff_Change = Differential_Change
Differential_Change = 0.5*(Radius_at_High_Bound -
* Radius_at_Low_Bound)
Ending_Radius = Radius_at_Low_Bound + Differential_Change
IF (Radius_at_Low_Bound .EQ. Ending_Radius) RETURN
ELSE
Last_Diff_Change = Differential_Change
Differential_Change = Function/Derivative_of_Function
Last_Ending_Radius = Ending_Radius
Ending_Radius = Ending_Radius - Differential_Change
IF (Last_Ending_Radius .EQ. Ending_Radius) RETURN
END IF
IF (ABS(Differential_Change) .LT. 1.0E-12) RETURN
Function =
* Ending_Radius*(Ending_Radius*(A*Ending_Radius - B)) - C
Derivative_of_Function =
* Ending_Radius*(Ending_Radius*3.0*A - 2.0*B)
IF (Function .LT. 0.0) THEN
Radius_at_Low_Bound = Ending_Radius
ELSE
Radius_at_High_Bound = Ending_Radius
END IF
END DO
PRINT *,'ERROR! ROOT SEARCH EXCEEDED MAXIMUM ITERATIONS'
PAUSE
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
END
C===============================================================================
C SUBROUTINE GAS_LOADINGS_CONSTANT_DEPTH
C Purpose: This subprogram applies the Haldane equation to update the
C gas loadings (partial pressures of helium and nitrogen) in the half-time
C compartments for a segment at constant depth.
C===============================================================================
SUBROUTINE GAS_LOADINGS_CONSTANT_DEPTH (Depth,
* Run_Time_End_of_Segment)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Depth, Run_Time_End_of_Segment !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
INTEGER Last_Segment_Number
REAL Initial_Helium_Pressure, Initial_Nitrogen_Pressure
REAL Inspired_Helium_Pressure, Inspired_Nitrogen_Pressure
REAL Ambient_Pressure, Last_Run_Time
REAL HALDANE_EQUATION !function subprogram
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Water_Vapor_Pressure
COMMON /Block_8/ Water_Vapor_Pressure
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
INTEGER Segment_Number !both input
REAL Run_Time, Segment_Time !and output
COMMON /Block_2/ Run_Time, Segment_Number, Segment_Time
REAL Ending_Ambient_Pressure !output
COMMON /Block_4/ Ending_Ambient_Pressure
INTEGER Mix_Number
COMMON /Block_9/ Mix_Number
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Time_Constant(16)
COMMON /Block_1A/ Helium_Time_Constant
REAL Nitrogen_Time_Constant(16)
COMMON /Block_1B/ Nitrogen_Time_Constant
REAL Helium_Pressure(16), Nitrogen_Pressure(16) !both input
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure !and output
REAL Fraction_Helium(10), Fraction_Nitrogen(10)
COMMON /Block_5/ Fraction_Helium, Fraction_Nitrogen
C===============================================================================
C CALCULATIONS
C===============================================================================
Segment_Time = Run_Time_End_of_Segment - Run_Time
Last_Run_Time = Run_Time_End_of_Segment
Run_Time = Last_Run_Time
Last_Segment_Number = Segment_Number
Segment_Number = Last_Segment_Number + 1
Ambient_Pressure = Depth + Barometric_Pressure
Inspired_Helium_Pressure = (Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Helium(Mix_Number)
Inspired_Nitrogen_Pressure = (Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Nitrogen(Mix_Number)
Ending_Ambient_Pressure = Ambient_Pressure
DO I = 1,16
Initial_Helium_Pressure = Helium_Pressure(I)
Initial_Nitrogen_Pressure = Nitrogen_Pressure(I)
Helium_Pressure(I) = HALDANE_EQUATION
* (Initial_Helium_Pressure, Inspired_Helium_Pressure,
* Helium_Time_Constant(I), Segment_Time)
Nitrogen_Pressure(I) = HALDANE_EQUATION
* (Initial_Nitrogen_Pressure, Inspired_Nitrogen_Pressure,
* Nitrogen_Time_Constant(I), Segment_Time)
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE NUCLEAR_REGENERATION
C Purpose: This subprogram calculates the regeneration of VPM critical
C radii that takes place over the dive time. The regeneration time constant
C has a time scale of weeks so this will have very little impact on dives of
C normal length, but will have a major impact for saturation dives.
C===============================================================================
SUBROUTINE NUCLEAR_REGENERATION (Dive_Time)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Dive_Time !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Crushing_Pressure_Pascals_He, Crushing_Pressure_Pascals_N2
REAL Ending_Radius_He, Ending_Radius_N2
REAL Crush_Pressure_Adjust_Ratio_He
REAL Crush_Pressure_Adjust_Ratio_N2
REAL Adj_Crush_Pressure_He_Pascals, Adj_Crush_Pressure_N2_Pascals
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Surface_Tension_Gamma, Skin_Compression_GammaC
COMMON /Block_19/ Surface_Tension_Gamma, Skin_Compression_GammaC
REAL Regeneration_Time_Constant
COMMON /Block_22/ Regeneration_Time_Constant
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
REAL Units_Factor
COMMON /Block_16/ Units_Factor
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Adjusted_Critical_Radius_He(16) !input
REAL Adjusted_Critical_Radius_N2(16)
COMMON /Block_7/ Adjusted_Critical_Radius_He,
* Adjusted_Critical_Radius_N2
REAL Max_Crushing_Pressure_He(16), Max_Crushing_Pressure_N2(16) !input
COMMON /Block_10/ Max_Crushing_Pressure_He,
* Max_Crushing_Pressure_N2
REAL Regenerated_Radius_He(16), Regenerated_Radius_N2(16) !output
COMMON /Block_24/ Regenerated_Radius_He, Regenerated_Radius_N2
REAL Adjusted_Crushing_Pressure_He(16) !output
REAL Adjusted_Crushing_Pressure_N2(16)
COMMON /Block_25/ Adjusted_Crushing_Pressure_He,
* Adjusted_Crushing_Pressure_N2
C===============================================================================
C CALCULATIONS
C First convert the maximum crushing pressure obtained for each compartment
C to Pascals. Next, compute the ending radius for helium and nitrogen
C critical nuclei in each compartment.
C===============================================================================
DO I = 1,16
Crushing_Pressure_Pascals_He =
* (Max_Crushing_Pressure_He(I)/Units_Factor) * 101325.0
Crushing_Pressure_Pascals_N2 =
* (Max_Crushing_Pressure_N2(I)/Units_Factor) * 101325.0
Ending_Radius_He = 1.0/(Crushing_Pressure_Pascals_He/
* (2.0*(Skin_Compression_GammaC - Surface_Tension_Gamma)) +
* 1.0/Adjusted_Critical_Radius_He(I))
Ending_Radius_N2 = 1.0/(Crushing_Pressure_Pascals_N2/
* (2.0*(Skin_Compression_GammaC - Surface_Tension_Gamma)) +
* 1.0/Adjusted_Critical_Radius_N2(I))
C===============================================================================
C A "regenerated" radius for each nucleus is now calculated based on the
C regeneration time constant. This means that after application of
C crushing pressure and reduction in radius, a nucleus will slowly grow
C back to its original initial radius over a period of time. This
C phenomenon is probabilistic in nature and depends on absolute temperature.
C It is independent of crushing pressure.
C===============================================================================
Regenerated_Radius_He(I) = Adjusted_Critical_Radius_He(I) +
* (Ending_Radius_He - Adjusted_Critical_Radius_He(I)) *
* EXP(-Dive_Time/Regeneration_Time_Constant)
Regenerated_Radius_N2(I) = Adjusted_Critical_Radius_N2(I) +
* (Ending_Radius_N2 - Adjusted_Critical_Radius_N2(I)) *
* EXP(-Dive_Time/Regeneration_Time_Constant)
C===============================================================================
C In order to preserve reference back to the initial critical radii after
C regeneration, an "adjusted crushing pressure" for the nuclei in each
C compartment must be computed. In other words, this is the value of
C crushing pressure that would have reduced the original nucleus to the
C to the present radius had regeneration not taken place. The ratio
C for adjusting crushing pressure is obtained from algebraic manipulation
C of the standard VPM equations. The adjusted crushing pressure, in lieu
C of the original crushing pressure, is then applied in the VPM Critical
C Volume Algorithm and the VPM Repetitive Algorithm.
C===============================================================================
Crush_Pressure_Adjust_Ratio_He =
* (Ending_Radius_He*(Adjusted_Critical_Radius_He(I) -
* Regenerated_Radius_He(I))) / (Regenerated_Radius_He(I) *
* (Adjusted_Critical_Radius_He(I) - Ending_Radius_He))
Crush_Pressure_Adjust_Ratio_N2 =
* (Ending_Radius_N2*(Adjusted_Critical_Radius_N2(I) -
* Regenerated_Radius_N2(I))) / (Regenerated_Radius_N2(I) *
* (Adjusted_Critical_Radius_N2(I) - Ending_Radius_N2))
Adj_Crush_Pressure_He_Pascals = Crushing_Pressure_Pascals_He *
* Crush_Pressure_Adjust_Ratio_He
Adj_Crush_Pressure_N2_Pascals = Crushing_Pressure_Pascals_N2 *
* Crush_Pressure_Adjust_Ratio_N2
Adjusted_Crushing_Pressure_He(I) =
* (Adj_Crush_Pressure_He_Pascals / 101325.0) * Units_Factor
Adjusted_Crushing_Pressure_N2(I) =
* (Adj_Crush_Pressure_N2_Pascals / 101325.0) * Units_Factor
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE CALC_INITIAL_ALLOWABLE_GRADIENT
C Purpose: This subprogram calculates the initial allowable gradients for
C helium and nitrogren in each compartment. These are the gradients that
C will be used to set the deco ceiling on the first pass through the deco
C loop. If the Critical Volume Algorithm is set to "off", then these
C gradients will determine the final deco schedule. Otherwise, if the
C Critical Volume Algorithm is set to "on", these gradients will be further
C "relaxed" by the Critical Volume Algorithm subroutine. The initial
C allowable gradients are referred to as "PssMin" in the papers by Yount
C and colleauges, i.e., the minimum supersaturation pressure gradients
C that will probe bubble formation in the VPM nuclei that started with the
C designated minimum initial radius (critical radius).
C
C The initial allowable gradients are computed directly from the
C "regenerated" radii after the Nuclear Regeneration subroutine. These
C gradients are tracked separately for helium and nitrogen.
C===============================================================================
SUBROUTINE CALC_INITIAL_ALLOWABLE_GRADIENT
IMPLICIT NONE
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Initial_Allowable_Grad_He_Pa, Initial_Allowable_Grad_N2_Pa
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Surface_Tension_Gamma, Skin_Compression_GammaC
COMMON /Block_19/ Surface_Tension_Gamma, Skin_Compression_GammaC
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
REAL Units_Factor
COMMON /Block_16/ Units_Factor
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Regenerated_Radius_He(16), Regenerated_Radius_N2(16) !input
COMMON /Block_24/ Regenerated_Radius_He, Regenerated_Radius_N2
REAL Allowable_Gradient_He(16), Allowable_Gradient_N2 (16) !output
COMMON /Block_26/ Allowable_Gradient_He, Allowable_Gradient_N2
REAL Initial_Allowable_Gradient_He(16) !output
REAL Initial_Allowable_Gradient_N2(16)
COMMON /Block_27/
* Initial_Allowable_Gradient_He, Initial_Allowable_Gradient_N2
C===============================================================================
C CALCULATIONS
C The initial allowable gradients are computed in Pascals and then converted
C to the diving pressure units. Two different sets of arrays are used to
C save the calculations - Initial Allowable Gradients and Allowable
C Gradients. The Allowable Gradients are assigned the values from Initial
C Allowable Gradients however the Allowable Gradients can be changed later
C by the Critical Volume subroutine. The values for the Initial Allowable
C Gradients are saved in a global array for later use by both the Critical
C Volume subroutine and the VPM Repetitive Algorithm subroutine.
C===============================================================================
DO I = 1,16
Initial_Allowable_Grad_N2_Pa = ((2.0*Surface_Tension_Gamma*
* (Skin_Compression_GammaC - Surface_Tension_Gamma)) /
* (Regenerated_Radius_N2(I)*Skin_Compression_GammaC))
Initial_Allowable_Grad_He_Pa = ((2.0*Surface_Tension_Gamma*
* (Skin_Compression_GammaC - Surface_Tension_Gamma)) /
* (Regenerated_Radius_He(I)*Skin_Compression_GammaC))
Initial_Allowable_Gradient_N2(I) =
* (Initial_Allowable_Grad_N2_Pa / 101325.0) * Units_Factor
Initial_Allowable_Gradient_He(I) =
* (Initial_Allowable_Grad_He_Pa / 101325.0) * Units_Factor
Allowable_Gradient_He(I) = Initial_Allowable_Gradient_He(I)
Allowable_Gradient_N2(I) = Initial_Allowable_Gradient_N2(I)
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE CALC_DECO_CEILING
C Purpose: This subprogram calculates the deco ceiling (the safe ascent
C depth) in each compartment, based on the allowable gradients, and then
C finds the deepest deco ceiling across all compartments. This deepest
C value (Deco Ceiling Depth) is then used by the Decompression Stop
C subroutine to determine the actual deco schedule.
C===============================================================================
SUBROUTINE CALC_DECO_CEILING (Deco_Ceiling_Depth)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Deco_Ceiling_Depth !output
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Gas_Loading, Weighted_Allowable_Gradient
REAL Tolerated_Ambient_Pressure
C===============================================================================
C LOCAL ARRAYS
C===============================================================================
REAL Compartment_Deco_Ceiling(16)
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Constant_Pressure_Other_Gases
COMMON /Block_17/ Constant_Pressure_Other_Gases
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Pressure(16), Nitrogen_Pressure(16) !input
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure
REAL Allowable_Gradient_He(16), Allowable_Gradient_N2 (16) !input
COMMON /Block_26/ Allowable_Gradient_He, Allowable_Gradient_N2
C===============================================================================
C CALCULATIONS
C Since there are two sets of allowable gradients being tracked, one for
C helium and one for nitrogen, a "weighted allowable gradient" must be
C computed each time based on the proportions of helium and nitrogen in
C each compartment. This proportioning follows the methodology of
C Buhlmann/Keller. If there is no helium and nitrogen in the compartment,
C such as after extended periods of oxygen breathing, then the minimum value
C across both gases will be used. It is important to note that if a
C compartment is empty of helium and nitrogen, then the weighted allowable
C gradient formula cannot be used since it will result in division by zero.
C===============================================================================
DO I = 1,16
Gas_Loading = Helium_Pressure(I) + Nitrogen_Pressure(I)
IF (Gas_Loading .GT. 0.0) THEN
Weighted_Allowable_Gradient =
* (Allowable_Gradient_He(I)* Helium_Pressure(I) +
* Allowable_Gradient_N2(I)* Nitrogen_Pressure(I)) /
* (Helium_Pressure(I) + Nitrogen_Pressure(I))
Tolerated_Ambient_Pressure = (Gas_Loading +
* Constant_Pressure_Other_Gases) - Weighted_Allowable_Gradient
ELSE
Weighted_Allowable_Gradient =
* MIN(Allowable_Gradient_He(I), Allowable_Gradient_N2(I))
Tolerated_Ambient_Pressure =
* Constant_Pressure_Other_Gases - Weighted_Allowable_Gradient
END IF
C===============================================================================
C The tolerated ambient pressure cannot be less than zero absolute, i.e.,
C the vacuum of outer space!
C===============================================================================
IF (Tolerated_Ambient_Pressure .LT. 0.0) THEN
Tolerated_Ambient_Pressure = 0.0
END IF
C===============================================================================
C The Deco Ceiling Depth is computed in a loop after all of the individual
C compartment deco ceilings have been calculated. It is important that the
C Deco Ceiling Depth (max deco ceiling across all compartments) only be
C extracted from the compartment values and not be compared against some
C initialization value. For example, if MAX(Deco_Ceiling_Depth . .) was
C compared against zero, this could cause a program lockup because sometimes
C the Deco Ceiling Depth needs to be negative (but not less than zero
C absolute ambient pressure) in order to decompress to the last stop at zero
C depth.
C===============================================================================
Compartment_Deco_Ceiling(I) =
* Tolerated_Ambient_Pressure - Barometric_Pressure
END DO
Deco_Ceiling_Depth = Compartment_Deco_Ceiling(1)
DO I = 2,16
Deco_Ceiling_Depth =
* MAX(Deco_Ceiling_Depth, Compartment_Deco_Ceiling(I))
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE CALC_MAX_ACTUAL_GRADIENT
C Purpose: This subprogram calculates the actual supersaturation gradient
C obtained in each compartment as a result of the ascent profile during
C decompression. Similar to the concept with crushing pressure, the
C supersaturation gradients are not cumulative over a multi-level, staged
C ascent. Rather, it will be the maximum value obtained in any one discrete
C step of the overall ascent. Thus, the program must compute and store the
C maximum actual gradient for each compartment that was obtained across all
C steps of the ascent profile. This subroutine is invoked on the last pass
C through the deco stop loop block when the final deco schedule is being
C generated.
C
C The max actual gradients are later used by the VPM Repetitive Algorithm to
C determine if adjustments to the critical radii are required. If the max
C actual gradient did not exceed the initial alllowable gradient, then no
C adjustment will be made. However, if the max actual gradient did exceed
C the intitial allowable gradient, such as permitted by the Critical Volume
C Algorithm, then the critical radius will be adjusted (made larger) on the
C repetitive dive to compensate for the bubbling that was allowed on the
C previous dive. The use of the max actual gradients is intended to prevent
C the repetitive algorithm from being overly conservative.
C===============================================================================
SUBROUTINE CALC_MAX_ACTUAL_GRADIENT (Deco_Stop_Depth)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Deco_Stop_Depth !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Compartment_Gradient
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Constant_Pressure_Other_Gases
COMMON /Block_17/ Constant_Pressure_Other_Gases
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Pressure(16), Nitrogen_Pressure(16) !input
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure
REAL Max_Actual_Gradient(16)
COMMON /Block_12/ Max_Actual_Gradient !output
C===============================================================================
C CALCULATIONS
C Note: negative supersaturation gradients are meaningless for this
C application, so the values must be equal to or greater than zero.
C===============================================================================
DO I = 1,16
Compartment_Gradient = (Helium_Pressure(I) +
* Nitrogen_Pressure(I) + Constant_Pressure_Other_Gases)
* - (Deco_Stop_Depth + Barometric_Pressure)
IF (Compartment_Gradient .LE. 0.0) THEN
Compartment_Gradient = 0.0
END IF
Max_Actual_Gradient(I) =
* MAX(Max_Actual_Gradient(I), Compartment_Gradient)
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE CALC_SURFACE_PHASE_VOLUME_TIME
C Purpose: This subprogram computes the surface portion of the total phase
C volume time. This is the time factored out of the integration of
C supersaturation gradient x time over the surface interval. The VPM
C considers the gradients that allow bubbles to form or to drive bubble
C growth both in the water and on the surface after the dive.
C
C This subroutine is a new development to the VPM algorithm in that it
C computes the time course of supersaturation gradients on the surface
C when both helium and nitrogen are present. Refer to separate write-up
C for a more detailed explanation of this algorithm.
C===============================================================================
SUBROUTINE CALC_SURFACE_PHASE_VOLUME_TIME
IMPLICIT NONE
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Integral_Gradient_x_Time, Decay_Time_to_Zero_Gradient
REAL Surface_Inspired_N2_Pressure
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Water_Vapor_Pressure
COMMON /Block_8/ Water_Vapor_Pressure
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Time_Constant(16)
COMMON /Block_1A/ Helium_Time_Constant
REAL Nitrogen_Time_Constant(16)
COMMON /Block_1B/ Nitrogen_Time_Constant
REAL Helium_Pressure(16), Nitrogen_Pressure(16) !input
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure
REAL Surface_Phase_Volume_Time(16) !output
COMMON /Block_11/ Surface_Phase_Volume_Time
C===============================================================================
C CALCULATIONS
C===============================================================================
Surface_Inspired_N2_Pressure = (Barometric_Pressure -
* Water_Vapor_Pressure)*0.79
DO I = 1,16
IF (Nitrogen_Pressure(I) .GT. Surface_Inspired_N2_Pressure)
* THEN
Surface_Phase_Volume_Time(I)=
* (Helium_Pressure(I)/Helium_Time_Constant(I)+
* (Nitrogen_Pressure(I)-Surface_Inspired_N2_Pressure)/
* Nitrogen_Time_Constant(I))
* /(Helium_Pressure(I) + Nitrogen_Pressure(I) -
* Surface_Inspired_N2_Pressure)
ELSE IF ((Nitrogen_Pressure(I) .LE.
* Surface_Inspired_N2_Pressure).AND.
* (Helium_Pressure(I)+Nitrogen_Pressure(I).GE.
* Surface_Inspired_N2_Pressure)) THEN
Decay_Time_to_Zero_Gradient =
* 1.0/(Nitrogen_Time_Constant(I)-Helium_Time_Constant(I))
* *ALOG((Surface_Inspired_N2_Pressure -
* Nitrogen_Pressure(I))/Helium_Pressure(I))
Integral_Gradient_x_Time =
* Helium_Pressure(I)/Helium_Time_Constant(I)*
* (1.0-EXP(-Helium_Time_Constant(I)*
* Decay_Time_to_Zero_Gradient))+
* (Nitrogen_Pressure(I)-Surface_Inspired_N2_Pressure)/
* Nitrogen_Time_Constant(I)*
* (1.0-EXP(-Nitrogen_Time_Constant(I)*
* Decay_Time_to_Zero_Gradient))
Surface_Phase_Volume_Time(I) =
* Integral_Gradient_x_Time/(Helium_Pressure(I) +
* Nitrogen_Pressure(I) - Surface_Inspired_N2_Pressure)
ELSE
Surface_Phase_Volume_Time(I) = 0.0
END IF
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE CRITICAL_VOLUME
C Purpose: This subprogram applies the VPM Critical Volume Algorithm. This
C algorithm will compute "relaxed" gradients for helium and nitrogen based
C on the setting of the Critical Volume Parameter Lambda.
C===============================================================================
SUBROUTINE CRITICAL_VOLUME (Deco_Phase_Volume_Time)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Deco_Phase_Volume_Time !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Parameter_Lambda_Pascals
REAL Adj_Crush_Pressure_He_Pascals, Adj_Crush_Pressure_N2_Pascals
REAL Initial_Allowable_Grad_He_Pa, Initial_Allowable_Grad_N2_Pa
REAL New_Allowable_Grad_He_Pascals, New_Allowable_Grad_N2_Pascals
REAL B, C
C===============================================================================
C LOCAL ARRAYS
C===============================================================================
REAL Phase_Volume_Time(16)
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Surface_Tension_Gamma, Skin_Compression_GammaC
COMMON /Block_19/ Surface_Tension_Gamma, Skin_Compression_GammaC
REAL Crit_Volume_Parameter_Lambda
COMMON /Block_20/ Crit_Volume_Parameter_Lambda
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
REAL Units_Factor
COMMON /Block_16/ Units_Factor
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Adjusted_Critical_Radius_He(16) !input
REAL Adjusted_Critical_Radius_N2(16)
COMMON /Block_7/ Adjusted_Critical_Radius_He,
* Adjusted_Critical_Radius_N2
REAL Surface_Phase_Volume_Time(16) !input
COMMON /Block_11/ Surface_Phase_Volume_Time
REAL Adjusted_Crushing_Pressure_He(16) !input
REAL Adjusted_Crushing_Pressure_N2(16)
COMMON /Block_25/ Adjusted_Crushing_Pressure_He,
* Adjusted_Crushing_Pressure_N2
REAL Allowable_Gradient_He(16), Allowable_Gradient_N2 (16) !output
COMMON /Block_26/ Allowable_Gradient_He, Allowable_Gradient_N2
REAL Initial_Allowable_Gradient_He(16) !input
REAL Initial_Allowable_Gradient_N2(16)
COMMON /Block_27/
* Initial_Allowable_Gradient_He, Initial_Allowable_Gradient_N2
C===============================================================================
C CALCULATIONS
C Note: Since the Critical Volume Parameter Lambda was defined in units of
C fsw-min in the original papers by Yount and colleauges, the same
C convention is retained here. Although Lambda is adjustable only in units
C of fsw-min in the program settings (range from 6500 to 8300 with default
C 7500), it will convert to the proper value in Pascals-min in this
C subroutine regardless of which diving pressure units are being used in
C the main program - feet of seawater (fsw) or meters of seawater (msw).
C The allowable gradient is computed using the quadratic formula (refer to
C separate write-up posted on the Deco List web site).
C===============================================================================
Parameter_Lambda_Pascals = (Crit_Volume_Parameter_Lambda/33.0)
* * 101325.0
DO I = 1,16
Phase_Volume_Time(I) = Deco_Phase_Volume_Time +
* Surface_Phase_Volume_Time(I)
END DO
DO I = 1,16
Adj_Crush_Pressure_He_Pascals =
* (Adjusted_Crushing_Pressure_He(I)/Units_Factor) * 101325.0
Initial_Allowable_Grad_He_Pa =
* (Initial_Allowable_Gradient_He(I)/Units_Factor) * 101325.0
B = Initial_Allowable_Grad_He_Pa +
* (Parameter_Lambda_Pascals*Surface_Tension_Gamma)/
* (Skin_Compression_GammaC*Phase_Volume_Time(I))
C = (Surface_Tension_Gamma*(Surface_Tension_Gamma*
* (Parameter_Lambda_Pascals*
* Adj_Crush_Pressure_He_Pascals)))
* /(Skin_Compression_GammaC*(Skin_Compression_GammaC*
* Phase_Volume_Time(I)))
New_Allowable_Grad_He_Pascals = (B + SQRT(B**2
* - 4.0*C))/2.0
Allowable_Gradient_He(I) =
* (New_Allowable_Grad_He_Pascals/101325.0)*Units_Factor
END DO
DO I = 1,16
Adj_Crush_Pressure_N2_Pascals =
* (Adjusted_Crushing_Pressure_N2(I)/Units_Factor) * 101325.0
Initial_Allowable_Grad_N2_Pa =
* (Initial_Allowable_Gradient_N2(I)/Units_Factor) * 101325.0
B = Initial_Allowable_Grad_N2_Pa +
* (Parameter_Lambda_Pascals*Surface_Tension_Gamma)/
* (Skin_Compression_GammaC*Phase_Volume_Time(I))
C = (Surface_Tension_Gamma*(Surface_Tension_Gamma*
* (Parameter_Lambda_Pascals*
* Adj_Crush_Pressure_N2_Pascals)))
* /(Skin_Compression_GammaC*(Skin_Compression_GammaC*
* Phase_Volume_Time(I)))
New_Allowable_Grad_N2_Pascals = (B + SQRT(B**2
* - 4.0*C))/2.0
Allowable_Gradient_N2(I) =
* (New_Allowable_Grad_N2_Pascals/101325.0)*Units_Factor
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE CALC_START_OF_DECO_ZONE
C Purpose: This subroutine uses the Bisection Method to find the depth at
C which the leading compartment just enters the decompression zone.
C Source: "Numerical Recipes in Fortran 77", Cambridge University Press,
C 1992.
C===============================================================================
SUBROUTINE CALC_START_OF_DECO_ZONE (Starting_Depth, Rate,
* Depth_Start_of_Deco_Zone)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Starting_Depth, Rate, Depth_Start_of_Deco_Zone !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I, J !loop counters
REAL Initial_Helium_Pressure, Initial_Nitrogen_Pressure
REAL Initial_Inspired_He_Pressure
REAL Initial_Inspired_N2_Pressure
REAL Time_to_Start_of_Deco_Zone, Helium_Rate, Nitrogen_Rate
REAL Starting_Ambient_Pressure
REAL Cpt_Depth_Start_of_Deco_Zone, Low_Bound, High_Bound
REAL High_Bound_Helium_Pressure, High_Bound_Nitrogen_Pressure
REAL Mid_Range_Helium_Pressure, Mid_Range_Nitrogen_Pressure
REAL Function_at_High_Bound, Function_at_Low_Bound, Mid_Range_Time
REAL Function_at_Mid_Range, Differential_Change, Last_Diff_Change
REAL SCHREINER_EQUATION !function subprogram
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Water_Vapor_Pressure
COMMON /Block_8/ Water_Vapor_Pressure
REAL Constant_Pressure_Other_Gases
COMMON /Block_17/ Constant_Pressure_Other_Gases
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
INTEGER Mix_Number
COMMON /Block_9/ Mix_Number
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Time_Constant(16)
COMMON /Block_1A/ Helium_Time_Constant
REAL Nitrogen_Time_Constant(16)
COMMON /Block_1B/ Nitrogen_Time_Constant
REAL Helium_Pressure(16), Nitrogen_Pressure(16)
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure
REAL Fraction_Helium(10), Fraction_Nitrogen(10)
COMMON /Block_5/ Fraction_Helium, Fraction_Nitrogen
C===============================================================================
C CALCULATIONS
C First initialize some variables
C===============================================================================
Depth_Start_of_Deco_Zone = 0.0
Starting_Ambient_Pressure = Starting_Depth + Barometric_Pressure
Initial_Inspired_He_Pressure = (Starting_Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Helium(Mix_Number)
Initial_Inspired_N2_Pressure = (Starting_Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Nitrogen(Mix_Number)
Helium_Rate = Rate * Fraction_Helium(Mix_Number)
Nitrogen_Rate = Rate * Fraction_Nitrogen(Mix_Number)
C===============================================================================
C ESTABLISH THE BOUNDS FOR THE ROOT SEARCH USING THE BISECTION METHOD
C AND CHECK TO MAKE SURE THAT THE ROOT WILL BE WITHIN BOUNDS. PROCESS
C EACH COMPARTMENT INDIVIDUALLY AND FIND THE MAXIMUM DEPTH ACROSS ALL
C COMPARTMENTS (LEADING COMPARTMENT)
C In this case, we are solving for time - the time when the gas tension in
C the compartment will be equal to ambient pressure. The low bound for time
C is set at zero and the high bound is set at the time it would take to
C ascend to zero ambient pressure (absolute). Since the ascent rate is
C negative, a multiplier of -1.0 is used to make the time positive. The
C desired point when gas tension equals ambient pressure is found at a time
C somewhere between these endpoints. The algorithm checks to make sure that
C the solution lies in between these bounds by first computing the low bound
C and high bound function values.
C===============================================================================
Low_Bound = 0.0
High_Bound = -1.0*(Starting_Ambient_Pressure/Rate)
DO 200 I = 1,16
Initial_Helium_Pressure = Helium_Pressure(I)
Initial_Nitrogen_Pressure = Nitrogen_Pressure(I)
Function_at_Low_Bound = Initial_Helium_Pressure +
* Initial_Nitrogen_Pressure + Constant_Pressure_Other_Gases
* - Starting_Ambient_Pressure
High_Bound_Helium_Pressure = SCHREINER_EQUATION
* (Initial_Inspired_He_Pressure, Helium_Rate,
* High_Bound, Helium_Time_Constant(I),
* Initial_Helium_Pressure)
High_Bound_Nitrogen_Pressure = SCHREINER_EQUATION
* (Initial_Inspired_N2_Pressure, Nitrogen_Rate,
* High_Bound, Nitrogen_Time_Constant(I),
* Initial_Nitrogen_Pressure)
Function_at_High_Bound = High_Bound_Helium_Pressure +
* High_Bound_Nitrogen_Pressure+Constant_Pressure_Other_Gases
IF ((Function_at_High_Bound * Function_at_Low_Bound) .GE. 0.0)
* THEN
PRINT *,'ERROR! ROOT IS NOT WITHIN BRACKETS'
PAUSE
END IF
C===============================================================================
C APPLY THE BISECTION METHOD IN SEVERAL ITERATIONS UNTIL A SOLUTION WITH
C THE DESIRED ACCURACY IS FOUND
C Note: the program allows for up to 100 iterations. Normally an exit will
C be made from the loop well before that number. If, for some reason, the
C program exceeds 100 iterations, there will be a pause to alert the user.
C===============================================================================
IF (Function_at_Low_Bound .LT. 0.0) THEN
Time_to_Start_of_Deco_Zone = Low_Bound
Differential_Change = High_Bound - Low_Bound
ELSE
Time_to_Start_of_Deco_Zone = High_Bound
Differential_Change = Low_Bound - High_Bound
END IF
DO 150 J = 1, 100
Last_Diff_Change = Differential_Change
Differential_Change = Last_Diff_Change*0.5
Mid_Range_Time = Time_to_Start_of_Deco_Zone +
* Differential_Change
Mid_Range_Helium_Pressure = SCHREINER_EQUATION
* (Initial_Inspired_He_Pressure, Helium_Rate,
* Mid_Range_Time, Helium_Time_Constant(I),
* Initial_Helium_Pressure)
Mid_Range_Nitrogen_Pressure = SCHREINER_EQUATION
* (Initial_Inspired_N2_Pressure, Nitrogen_Rate,
* Mid_Range_Time, Nitrogen_Time_Constant(I),
* Initial_Nitrogen_Pressure)
Function_at_Mid_Range =
* Mid_Range_Helium_Pressure +
* Mid_Range_Nitrogen_Pressure +
* Constant_Pressure_Other_Gases -
* (Starting_Ambient_Pressure + Rate*Mid_Range_Time)
IF (Function_at_Mid_Range .LE. 0.0)
* Time_to_Start_of_Deco_Zone = Mid_Range_Time
IF ((ABS(Differential_Change) .LT. 1.0E-3) .OR.
* (Function_at_Mid_Range .EQ. 0.0)) GOTO 170
150 CONTINUE
PRINT *,'ERROR! ROOT SEARCH EXCEEDED MAXIMUM ITERATIONS'
PAUSE
C===============================================================================
C When a solution with the desired accuracy is found, the program jumps out
C of the loop to Line 170 and assigns the solution value for the individual
C compartment.
C===============================================================================
170 Cpt_Depth_Start_of_Deco_Zone = (Starting_Ambient_Pressure +
* Rate*Time_to_Start_of_Deco_Zone) - Barometric_Pressure
C===============================================================================
C The overall solution will be the compartment with the maximum depth where
C gas tension equals ambient pressure (leading compartment).
C===============================================================================
Depth_Start_of_Deco_Zone = MAX(Depth_Start_of_Deco_Zone,
* Cpt_Depth_Start_of_Deco_Zone)
200 CONTINUE
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE PROJECTED_ASCENT
C Purpose: This subprogram performs a simulated ascent outside of the main
C program to ensure that a deco ceiling will not be violated due to unusual
C gas loading during ascent (on-gassing). If the deco ceiling is violated,
C the stop depth will be adjusted deeper by the step size until a safe
C ascent can be made.
C===============================================================================
SUBROUTINE PROJECTED_ASCENT (Starting_Depth, Rate,
* Deco_Stop_Depth, Step_Size)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Starting_Depth, Rate, Step_Size !input
REAL Deco_Stop_Depth !input and output
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Initial_Inspired_He_Pressure, Initial_Inspired_N2_Pressure
REAL Helium_Rate, Nitrogen_Rate
REAL Starting_Ambient_Pressure, Ending_Ambient_Pressure
REAL New_Ambient_Pressure, Segment_Time
REAL Temp_Helium_Pressure, Temp_Nitrogen_Pressure
REAL Weighted_Allowable_Gradient
REAL SCHREINER_EQUATION !function subprogram
C===============================================================================
C LOCAL ARRAYS
C===============================================================================
REAL Initial_Helium_Pressure(16), Initial_Nitrogen_Pressure(16)
REAL Temp_Gas_Loading(16), Allowable_Gas_Loading (16)
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Water_Vapor_Pressure
COMMON /Block_8/ Water_Vapor_Pressure
REAL Constant_Pressure_Other_Gases
COMMON /Block_17/ Constant_Pressure_Other_Gases
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
INTEGER Mix_Number
COMMON /Block_9/ Mix_Number
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Time_Constant(16)
COMMON /Block_1A/ Helium_Time_Constant
REAL Nitrogen_Time_Constant(16)
COMMON /Block_1B/ Nitrogen_Time_Constant
REAL Helium_Pressure(16), Nitrogen_Pressure(16) !input
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure
REAL Fraction_Helium(10), Fraction_Nitrogen(10)
COMMON /Block_5/ Fraction_Helium, Fraction_Nitrogen
REAL Allowable_Gradient_He(16), Allowable_Gradient_N2 (16) !input
COMMON /Block_26/ Allowable_Gradient_He, Allowable_Gradient_N2
C===============================================================================
C CALCULATIONS
C===============================================================================
New_Ambient_Pressure = Deco_Stop_Depth + Barometric_Pressure
Starting_Ambient_Pressure = Starting_Depth + Barometric_Pressure
Initial_Inspired_He_Pressure = (Starting_Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Helium(Mix_Number)
Initial_Inspired_N2_Pressure = (Starting_Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Nitrogen(Mix_Number)
Helium_Rate = Rate * Fraction_Helium(Mix_Number)
Nitrogen_Rate = Rate * Fraction_Nitrogen(Mix_Number)
DO I = 1,16
Initial_Helium_Pressure(I) = Helium_Pressure(I)
Initial_Nitrogen_Pressure(I) = Nitrogen_Pressure(I)
END DO
665 Ending_Ambient_Pressure = New_Ambient_Pressure
Segment_Time = (Ending_Ambient_Pressure -
* Starting_Ambient_Pressure)/Rate
DO 670 I = 1,16
Temp_Helium_Pressure = SCHREINER_EQUATION
* (Initial_Inspired_He_Pressure, Helium_Rate,
* Segment_Time, Helium_Time_Constant(I),
* Initial_Helium_Pressure(I))
Temp_Nitrogen_Pressure = SCHREINER_EQUATION
* (Initial_Inspired_N2_Pressure, Nitrogen_Rate,
* Segment_Time, Nitrogen_Time_Constant(I),
* Initial_Nitrogen_Pressure(I))
Temp_Gas_Loading(I) = Temp_Helium_Pressure +
* Temp_Nitrogen_Pressure
IF (Temp_Gas_Loading(I) .GT. 0.0) THEN
Weighted_Allowable_Gradient =
* (Allowable_Gradient_He(I)* Temp_Helium_Pressure +
* Allowable_Gradient_N2(I)* Temp_Nitrogen_Pressure) /
* Temp_Gas_Loading(I)
ELSE
Weighted_Allowable_Gradient =
* MIN(Allowable_Gradient_He(I),Allowable_Gradient_N2(I))
END IF
Allowable_Gas_Loading(I) = Ending_Ambient_Pressure +
* Weighted_Allowable_Gradient - Constant_Pressure_Other_Gases
670 CONTINUE
DO 671 I = 1,16
IF (Temp_Gas_Loading(I) .GT. Allowable_Gas_Loading(I)) THEN
New_Ambient_Pressure = Ending_Ambient_Pressure + Step_Size
Deco_Stop_Depth = Deco_Stop_Depth + Step_Size
GOTO 665
END IF
671 CONTINUE
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE DECOMPRESSION_STOP
C Purpose: This subprogram calculates the required time at each
C decompression stop.
C===============================================================================
SUBROUTINE DECOMPRESSION_STOP (Deco_Stop_Depth, Step_Size)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Deco_Stop_Depth, Step_Size !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
CHARACTER OS_Command*3
INTEGER I !loop counter
INTEGER Last_Segment_Number
REAL Ambient_Pressure
REAL Inspired_Helium_Pressure, Inspired_Nitrogen_Pressure
REAL Last_Run_Time
REAL Deco_Ceiling_Depth, Next_Stop
REAL Round_Up_Operation, Temp_Segment_Time, Time_Counter
REAL Weighted_Allowable_Gradient
REAL HALDANE_EQUATION !function subprogram
C===============================================================================
C LOCAL ARRAYS
C===============================================================================
REAL Initial_Helium_Pressure(16)
REAL Initial_Nitrogen_Pressure(16)
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Water_Vapor_Pressure
COMMON /Block_8/ Water_Vapor_Pressure
REAL Constant_Pressure_Other_Gases
COMMON /Block_17/ Constant_Pressure_Other_Gases
REAL Minimum_Deco_Stop_Time
COMMON /Block_21/ Minimum_Deco_Stop_Time
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
INTEGER Segment_Number
REAL Run_Time, Segment_Time
COMMON /Block_2/ Run_Time, Segment_Number, Segment_Time
REAL Ending_Ambient_Pressure
COMMON /Block_4/ Ending_Ambient_Pressure
INTEGER Mix_Number
COMMON /Block_9/ Mix_Number
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Time_Constant(16)
COMMON /Block_1A/ Helium_Time_Constant
REAL Nitrogen_Time_Constant(16)
COMMON /Block_1B/ Nitrogen_Time_Constant
REAL Helium_Pressure(16), Nitrogen_Pressure(16) !both input
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure !and output
REAL Fraction_Helium(10), Fraction_Nitrogen(10)
COMMON /Block_5/ Fraction_Helium, Fraction_Nitrogen
REAL Allowable_Gradient_He(16), Allowable_Gradient_N2 (16) !input
COMMON /Block_26/ Allowable_Gradient_He, Allowable_Gradient_N2
C===============================================================================
C CALCULATIONS
C===============================================================================
OS_Command = 'CLS'
Last_Run_Time = Run_Time
Round_Up_Operation = ANINT((Last_Run_Time/Minimum_Deco_Stop_Time)
* + 0.5) * Minimum_Deco_Stop_Time
Segment_Time = Round_Up_Operation - Run_Time
Run_Time = Round_Up_Operation
Temp_Segment_Time = Segment_Time
Last_Segment_Number = Segment_Number
Segment_Number = Last_Segment_Number + 1
Ambient_Pressure = Deco_Stop_Depth + Barometric_Pressure
Ending_Ambient_Pressure = Ambient_Pressure
Next_Stop = Deco_Stop_Depth - Step_Size
Inspired_Helium_Pressure = (Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Helium(Mix_Number)
Inspired_Nitrogen_Pressure = (Ambient_Pressure -
* Water_Vapor_Pressure)*Fraction_Nitrogen(Mix_Number)
C===============================================================================
C Check to make sure that program won't lock up if unable to decompress
C to the next stop. If so, write error message and terminate program.
C===============================================================================
DO I = 1,16
IF ((Inspired_Helium_Pressure + Inspired_Nitrogen_Pressure)
* .GT. 0.0) THEN
Weighted_Allowable_Gradient =
* (Allowable_Gradient_He(I)* Inspired_Helium_Pressure +
* Allowable_Gradient_N2(I)* Inspired_Nitrogen_Pressure) /
* (Inspired_Helium_Pressure + Inspired_Nitrogen_Pressure)
IF ((Inspired_Helium_Pressure + Inspired_Nitrogen_Pressure +
* Constant_Pressure_Other_Gases - Weighted_Allowable_Gradient)
* .GT. (Next_Stop + Barometric_Pressure)) THEN
CALL SYSTEMQQ (OS_Command)
WRITE (*,905) Deco_Stop_Depth
WRITE (*,906)
WRITE (*,907)
STOP 'PROGRAM TERMINATED'
END IF
END IF
END DO
700 DO 720 I = 1,16
Initial_Helium_Pressure(I) = Helium_Pressure(I)
Initial_Nitrogen_Pressure(I) = Nitrogen_Pressure(I)
Helium_Pressure(I) = HALDANE_EQUATION
* (Initial_Helium_Pressure(I), Inspired_Helium_Pressure,
* Helium_Time_Constant(I), Segment_Time)
Nitrogen_Pressure(I) = HALDANE_EQUATION
* (Initial_Nitrogen_Pressure(I), Inspired_Nitrogen_Pressure,
* Nitrogen_Time_Constant(I), Segment_Time)
720 CONTINUE
CALL CALC_DECO_CEILING (Deco_Ceiling_Depth)
IF (Deco_Ceiling_Depth .GT. Next_Stop) THEN
Segment_Time = Minimum_Deco_Stop_Time
Time_Counter = Temp_Segment_Time
Temp_Segment_Time = Time_Counter + Minimum_Deco_Stop_Time
Last_Run_Time = Run_Time
Run_Time = Last_Run_Time + Minimum_Deco_Stop_Time
GOTO 700
END IF
Segment_Time = Temp_Segment_Time
RETURN
C===============================================================================
C FORMAT STATEMENTS - ERROR MESSAGES
C===============================================================================
905 FORMAT ('0ERROR! OFF-GASSING GRADIENT IS TOO SMALL TO DECOMPRESS'
*1X,'AT THE',F6.1,1X,'STOP')
906 FORMAT ('0REDUCE STEP SIZE OR INCREASE OXYGEN FRACTION')
907 FORMAT (' ')
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
END
C===============================================================================
C SUBROUTINE GAS_LOADINGS_SURFACE_INTERVAL
C Purpose: This subprogram calculates the gas loading (off-gassing) during
C a surface interval.
C===============================================================================
SUBROUTINE GAS_LOADINGS_SURFACE_INTERVAL (Surface_Interval_Time)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Surface_Interval_Time !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Inspired_Helium_Pressure, Inspired_Nitrogen_Pressure
REAL Initial_Helium_Pressure, Initial_Nitrogen_Pressure
REAL HALDANE_EQUATION !function subprogram
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Water_Vapor_Pressure
COMMON /Block_8/ Water_Vapor_Pressure
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Helium_Time_Constant(16)
COMMON /Block_1A/ Helium_Time_Constant
REAL Nitrogen_Time_Constant(16)
COMMON /Block_1B/ Nitrogen_Time_Constant
REAL Helium_Pressure(16), Nitrogen_Pressure(16) !both input
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure !and output
C===============================================================================
C CALCULATIONS
C===============================================================================
Inspired_Helium_Pressure = 0.0
Inspired_Nitrogen_Pressure = (Barometric_Pressure -
* Water_Vapor_Pressure)*0.79
DO I = 1,16
Initial_Helium_Pressure = Helium_Pressure(I)
Initial_Nitrogen_Pressure = Nitrogen_Pressure(I)
Helium_Pressure(I) = HALDANE_EQUATION
* (Initial_Helium_Pressure, Inspired_Helium_Pressure,
* Helium_Time_Constant(I), Surface_Interval_Time)
Nitrogen_Pressure(I) = HALDANE_EQUATION
* (Initial_Nitrogen_Pressure, Inspired_Nitrogen_Pressure,
* Nitrogen_Time_Constant(I), Surface_Interval_Time)
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE VPM_REPETITIVE_ALGORITHM
C Purpose: This subprogram implements the VPM Repetitive Algorithm that was
C envisioned by Professor David E. Yount only months before his passing.
C===============================================================================
SUBROUTINE VPM_REPETITIVE_ALGORITHM (Surface_Interval_Time)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Surface_Interval_Time !input
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER I !loop counter
REAL Max_Actual_Gradient_Pascals
REAL Adj_Crush_Pressure_He_Pascals, Adj_Crush_Pressure_N2_Pascals
REAL Initial_Allowable_Grad_He_Pa, Initial_Allowable_Grad_N2_Pa
REAL New_Critical_Radius_He, New_Critical_Radius_N2
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Surface_Tension_Gamma, Skin_Compression_GammaC
COMMON /Block_19/ Surface_Tension_Gamma, Skin_Compression_GammaC
REAL Regeneration_Time_Constant
COMMON /Block_22/ Regeneration_Time_Constant
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
REAL Units_Factor
COMMON /Block_16/ Units_Factor
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Initial_Critical_Radius_He(16) !input
REAL Initial_Critical_Radius_N2(16)
COMMON /Block_6/ Initial_Critical_Radius_He,
* Initial_Critical_Radius_N2
REAL Adjusted_Critical_Radius_He(16) !output
REAL Adjusted_Critical_Radius_N2(16)
COMMON /Block_7/ Adjusted_Critical_Radius_He,
* Adjusted_Critical_Radius_N2
REAL Max_Actual_Gradient(16) !input
COMMON /Block_12/ Max_Actual_Gradient
REAL Adjusted_Crushing_Pressure_He(16) !input
REAL Adjusted_Crushing_Pressure_N2(16)
COMMON /Block_25/ Adjusted_Crushing_Pressure_He,
* Adjusted_Crushing_Pressure_N2
REAL Initial_Allowable_Gradient_He(16) !input
REAL Initial_Allowable_Gradient_N2(16)
COMMON /Block_27/
* Initial_Allowable_Gradient_He, Initial_Allowable_Gradient_N2
C===============================================================================
C CALCULATIONS
C===============================================================================
DO I = 1,16
Max_Actual_Gradient_Pascals =
* (Max_Actual_Gradient(I)/Units_Factor) * 101325.0
Adj_Crush_Pressure_He_Pascals =
* (Adjusted_Crushing_Pressure_He(I)/Units_Factor) * 101325.0
Adj_Crush_Pressure_N2_Pascals =
* (Adjusted_Crushing_Pressure_N2(I)/Units_Factor) * 101325.0
Initial_Allowable_Grad_He_Pa =
* (Initial_Allowable_Gradient_He(I)/Units_Factor) * 101325.0
Initial_Allowable_Grad_N2_Pa =
* (Initial_Allowable_Gradient_N2(I)/Units_Factor) * 101325.0
IF (Max_Actual_Gradient(I)
* .GT. Initial_Allowable_Gradient_N2(I)) THEN
New_Critical_Radius_N2 = ((2.0*Surface_Tension_Gamma*
* (Skin_Compression_GammaC - Surface_Tension_Gamma))) /
* (Max_Actual_Gradient_Pascals*Skin_Compression_GammaC -
* Surface_Tension_Gamma*Adj_Crush_Pressure_N2_Pascals)
Adjusted_Critical_Radius_N2(I) =
* Initial_Critical_Radius_N2(I) +
* (Initial_Critical_Radius_N2(I)-New_Critical_Radius_N2)*
* EXP(-Surface_Interval_Time/Regeneration_Time_Constant)
ELSE
Adjusted_Critical_Radius_N2(I) =
* Initial_Critical_Radius_N2(I)
END IF
IF (Max_Actual_Gradient(I)
* .GT. Initial_Allowable_Gradient_He(I)) THEN
New_Critical_Radius_He = ((2.0*Surface_Tension_Gamma*
* (Skin_Compression_GammaC - Surface_Tension_Gamma))) /
* (Max_Actual_Gradient_Pascals*Skin_Compression_GammaC -
* Surface_Tension_Gamma*Adj_Crush_Pressure_He_Pascals)
Adjusted_Critical_Radius_He(I) =
* Initial_Critical_Radius_He(I) +
* (Initial_Critical_Radius_He(I)-New_Critical_Radius_He)*
* EXP(-Surface_Interval_Time/Regeneration_Time_Constant)
ELSE
Adjusted_Critical_Radius_He(I) =
* Initial_Critical_Radius_He(I)
END IF
END DO
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE CALC_BAROMETRIC_PRESSURE
C Purpose: This sub calculates barometric pressure at altitude based on the
C publication "U.S. Standard Atmosphere, 1976", U.S. Government Printing
C Office, Washington, D.C. The source for this code is a Fortran 90 program
C written by Ralph L. Carmichael (retired NASA researcher) and endorsed by
C the National Geophysical Data Center of the National Oceanic and
C Atmospheric Administration. It is available for download free from
C Public Domain Aeronautical Software at: http://www.pdas.com/atmos.htm
C===============================================================================
SUBROUTINE CALC_BAROMETRIC_PRESSURE (Altitude)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
REAL Altitude !input
C===============================================================================
C LOCAL CONSTANTS
C===============================================================================
REAL Radius_of_Earth, Acceleration_of_Gravity
REAL Molecular_weight_of_Air, Gas_Constant_R
REAL Temp_at_Sea_Level, Temp_Gradient
REAL Pressure_at_Sea_Level_Fsw, Pressure_at_Sea_Level_Msw
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
REAL Pressure_at_Sea_Level, GMR_Factor
REAL Altitude_Feet, Altitude_Meters
REAL Altitude_Kilometers, Geopotential_Altitude
REAL Temp_at_Geopotential_Altitude
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
LOGICAL Units_Equal_Fsw, Units_Equal_Msw
COMMON /Block_15/ Units_Equal_Fsw, Units_Equal_Msw
REAL Barometric_Pressure !output
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C CALCULATIONS
C===============================================================================
Radius_of_Earth = 6369.0 !kilometers
Acceleration_of_Gravity = 9.80665 !meters/second^2
Molecular_weight_of_Air = 28.9644 !mols
Gas_Constant_R = 8.31432 !Joules/mol*deg Kelvin
Temp_at_Sea_Level = 288.15 !degrees Kelvin
Pressure_at_Sea_Level_Fsw = 33.0 !feet of seawater based on 101325 Pa
!at sea level (Standard Atmosphere)
Pressure_at_Sea_Level_Msw = 10.0 !meters of seawater based on 100000 Pa
!at sea level (European System)
Temp_Gradient = -6.5 !Change in Temp deg Kelvin with
!change in geopotential altitude,
!valid for first layer of atmosphere
!up to 11 kilometers or 36,000 feet
GMR_Factor = Acceleration_of_Gravity *
* Molecular_weight_of_Air / Gas_Constant_R
IF (Units_Equal_Fsw) THEN
Altitude_Feet = Altitude
Altitude_Kilometers = Altitude_Feet / 3280.839895
Pressure_at_Sea_Level = Pressure_at_Sea_Level_Fsw
END IF
IF (Units_Equal_Msw) THEN
Altitude_Meters = Altitude
Altitude_Kilometers = Altitude_Meters / 1000.0
Pressure_at_Sea_Level = Pressure_at_Sea_Level_Msw
END IF
Geopotential_Altitude = (Altitude_Kilometers * Radius_of_Earth) /
* (Altitude_Kilometers + Radius_of_Earth)
Temp_at_Geopotential_Altitude = Temp_at_Sea_Level
* + Temp_Gradient * Geopotential_Altitude
Barometric_Pressure = Pressure_at_Sea_Level *
* EXP(ALOG(Temp_at_Sea_Level / Temp_at_Geopotential_Altitude) *
* GMR_Factor / Temp_Gradient)
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
C===============================================================================
C SUBROUTINE VPM_ALTITUDE_DIVE_ALGORITHM
C Purpose: This subprogram updates gas loadings and adjusts critical radii
C (as required) based on whether or not diver is acclimatized at altitude or
C makes an ascent to altitude before the dive.
C===============================================================================
SUBROUTINE VPM_ALTITUDE_DIVE_ALGORITHM
IMPLICIT NONE
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
CHARACTER Diver_Acclimatized_at_Altitude*3, OS_Command*3
INTEGER I !loop counter
LOGICAL Diver_Acclimatized
REAL Altitude_of_Dive, Starting_Acclimatized_Altitude
REAL Ascent_to_Altitude_Hours, Hours_at_Altitude_Before_Dive
REAL Ascent_to_Altitude_Time, Time_at_Altitude_Before_Dive
REAL Starting_Ambient_Pressure, Ending_Ambient_Pressure
REAL Initial_Inspired_N2_Pressure, Rate, Nitrogen_Rate
REAL Inspired_Nitrogen_Pressure, Initial_Nitrogen_Pressure
REAL Compartment_Gradient, Compartment_Gradient_Pascals
REAL Gradient_He_Bubble_Formation, Gradient_N2_Bubble_Formation
REAL New_Critical_Radius_He, New_Critical_Radius_N2
REAL Ending_Radius_He, Ending_Radius_N2
REAL Regenerated_Radius_He, Regenerated_Radius_N2
REAL HALDANE_EQUATION !function subprogram
REAL SCHREINER_EQUATION !function subprogram
C===============================================================================
C GLOBAL CONSTANTS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Water_Vapor_Pressure
COMMON /Block_8/ Water_Vapor_Pressure
REAL Constant_Pressure_Other_Gases
COMMON /Block_17/ Constant_Pressure_Other_Gases
REAL Surface_Tension_Gamma, Skin_Compression_GammaC
COMMON /Block_19/ Surface_Tension_Gamma, Skin_Compression_GammaC
REAL Regeneration_Time_Constant
COMMON /Block_22/ Regeneration_Time_Constant
C===============================================================================
C GLOBAL VARIABLES IN NAMED COMMON BLOCKS
C===============================================================================
LOGICAL Units_Equal_Fsw, Units_Equal_Msw
COMMON /Block_15/ Units_Equal_Fsw, Units_Equal_Msw
REAL Units_Factor
COMMON /Block_16/ Units_Factor
REAL Barometric_Pressure
COMMON /Block_18/ Barometric_Pressure
C===============================================================================
C GLOBAL ARRAYS IN NAMED COMMON BLOCKS
C===============================================================================
REAL Nitrogen_Time_Constant(16)
COMMON /Block_1B/ Nitrogen_Time_Constant
REAL Helium_Pressure(16), Nitrogen_Pressure(16) !both input
COMMON /Block_3/ Helium_Pressure, Nitrogen_Pressure !and output
REAL Initial_Critical_Radius_He(16) !both input
REAL Initial_Critical_Radius_N2(16) !and output
COMMON /Block_6/ Initial_Critical_Radius_He,
* Initial_Critical_Radius_N2
REAL Adjusted_Critical_Radius_He(16) !output
REAL Adjusted_Critical_Radius_N2(16)
COMMON /Block_7/ Adjusted_Critical_Radius_He,
* Adjusted_Critical_Radius_N2
C===============================================================================
C NAMELIST FOR PROGRAM SETTINGS (READ IN FROM ASCII TEXT FILE)
C===============================================================================
NAMELIST /Altitude_Dive_Settings/ Altitude_of_Dive,
* Diver_Acclimatized_at_Altitude,
* Starting_Acclimatized_Altitude, Ascent_to_Altitude_Hours,
* Hours_at_Altitude_Before_Dive
C===============================================================================
C CALCULATIONS
C===============================================================================
OS_Command = 'CLS'
OPEN (UNIT = 12, FILE = 'ALTITUDE.SET', STATUS = 'UNKNOWN',
* ACCESS = 'SEQUENTIAL', FORM = 'FORMATTED')
READ (12,Altitude_Dive_Settings)
IF ((Units_Equal_Fsw) .AND. (Altitude_of_Dive .GT. 30000.0)) THEN
CALL SYSTEMQQ (OS_Command)
WRITE (*,900)
WRITE (*,901)
STOP 'PROGRAM TERMINATED'
END IF
IF ((Units_Equal_Msw) .AND. (Altitude_of_Dive .GT. 9144.0)) THEN
CALL SYSTEMQQ (OS_Command)
WRITE (*,900)
WRITE (*,901)
STOP 'PROGRAM TERMINATED'
END IF
IF ((Diver_Acclimatized_at_Altitude .EQ. 'YES') .OR.
* (Diver_Acclimatized_at_Altitude .EQ. 'yes')) THEN
Diver_Acclimatized = (.TRUE.)
ELSE IF ((Diver_Acclimatized_at_Altitude .EQ. 'NO') .OR.
* (Diver_Acclimatized_at_Altitude .EQ. 'no')) THEN
Diver_Acclimatized = (.FALSE.)
ELSE
CALL SYSTEMQQ (OS_Command)
WRITE (*,902)
WRITE (*,901)
STOP 'PROGRAM TERMINATED'
END IF
Ascent_to_Altitude_Time = Ascent_to_Altitude_Hours * 60.0
Time_at_Altitude_Before_Dive = Hours_at_Altitude_Before_Dive*60.0
IF (Diver_Acclimatized) THEN
CALL CALC_BAROMETRIC_PRESSURE (Altitude_of_Dive) !subroutine
WRITE (*,802) Altitude_of_Dive, Barometric_Pressure
DO I = 1,16
Adjusted_Critical_Radius_N2(I) = Initial_Critical_Radius_N2(I)
Adjusted_Critical_Radius_He(I) = Initial_Critical_Radius_He(I)
Helium_Pressure(I) = 0.0
Nitrogen_Pressure(I) = (Barometric_Pressure -
* Water_Vapor_Pressure)*0.79
END DO
ELSE
IF ((Starting_Acclimatized_Altitude .GE. Altitude_of_Dive)
* .OR. (Starting_Acclimatized_Altitude .LT. 0.0)) THEN
CALL SYSTEMQQ (OS_Command)
WRITE (*,903)
WRITE (*,904)
WRITE (*,901)
STOP 'PROGRAM TERMINATED'
END IF
CALL CALC_BAROMETRIC_PRESSURE !subroutine
* (Starting_Acclimatized_Altitude)
Starting_Ambient_Pressure = Barometric_Pressure
DO I = 1,16
Helium_Pressure(I) = 0.0
Nitrogen_Pressure(I) = (Barometric_Pressure -
* Water_Vapor_Pressure)*0.79
END DO
CALL CALC_BAROMETRIC_PRESSURE (Altitude_of_Dive) !subroutine
WRITE (*,802) Altitude_of_Dive, Barometric_Pressure
Ending_Ambient_Pressure = Barometric_Pressure
Initial_Inspired_N2_Pressure = (Starting_Ambient_Pressure
* - Water_Vapor_Pressure)*0.79
Rate = (Ending_Ambient_Pressure - Starting_Ambient_Pressure)
* / Ascent_to_Altitude_Time
Nitrogen_Rate = Rate*0.79
DO I = 1,16
Initial_Nitrogen_Pressure = Nitrogen_Pressure(I)
Nitrogen_Pressure(I) = SCHREINER_EQUATION
* (Initial_Inspired_N2_Pressure, Nitrogen_Rate,
* Ascent_to_Altitude_Time, Nitrogen_Time_Constant(I),
* Initial_Nitrogen_Pressure)
Compartment_Gradient = (Nitrogen_Pressure(I)
* + Constant_Pressure_Other_Gases)
* - Ending_Ambient_Pressure
Compartment_Gradient_Pascals =
* (Compartment_Gradient / Units_Factor) * 101325.0
Gradient_He_Bubble_Formation =
* ((2.0*Surface_Tension_Gamma*
* (Skin_Compression_GammaC - Surface_Tension_Gamma)) /
* (Initial_Critical_Radius_He(I)*Skin_Compression_GammaC))
IF (Compartment_Gradient_Pascals .GT.
* Gradient_He_Bubble_Formation) THEN
New_Critical_Radius_He = ((2.0*Surface_Tension_Gamma*
* (Skin_Compression_GammaC - Surface_Tension_Gamma))) /
* (Compartment_Gradient_Pascals*Skin_Compression_GammaC)
Adjusted_Critical_Radius_He(I) =
* Initial_Critical_Radius_He(I) +
* (Initial_Critical_Radius_He(I)-
* New_Critical_Radius_He)*
* EXP(-Time_at_Altitude_Before_Dive/
* Regeneration_Time_Constant)
Initial_Critical_Radius_He(I) =
* Adjusted_Critical_Radius_He(I)
ELSE
Ending_Radius_He = 1.0/(Compartment_Gradient_Pascals/
* (2.0*(Surface_Tension_Gamma-Skin_Compression_GammaC))
* + 1.0/Initial_Critical_Radius_He(I))
Regenerated_Radius_He =
* Initial_Critical_Radius_He(I) +
* (Ending_Radius_He - Initial_Critical_Radius_He(I)) *
* EXP(-Time_at_Altitude_Before_Dive/
* Regeneration_Time_Constant)
Initial_Critical_Radius_He(I) =
* Regenerated_Radius_He
Adjusted_Critical_Radius_He(I) =
* Initial_Critical_Radius_He(I)
END IF
Gradient_N2_Bubble_Formation =
* ((2.0*Surface_Tension_Gamma*
* (Skin_Compression_GammaC - Surface_Tension_Gamma)) /
* (Initial_Critical_Radius_N2(I)*Skin_Compression_GammaC))
IF (Compartment_Gradient_Pascals .GT.
* Gradient_N2_Bubble_Formation) THEN
New_Critical_Radius_N2 = ((2.0*Surface_Tension_Gamma*
* (Skin_Compression_GammaC - Surface_Tension_Gamma))) /
* (Compartment_Gradient_Pascals*Skin_Compression_GammaC)
Adjusted_Critical_Radius_N2(I) =
* Initial_Critical_Radius_N2(I) +
* (Initial_Critical_Radius_N2(I)-
* New_Critical_Radius_N2)*
* EXP(-Time_at_Altitude_Before_Dive/
* Regeneration_Time_Constant)
Initial_Critical_Radius_N2(I) =
* Adjusted_Critical_Radius_N2(I)
ELSE
Ending_Radius_N2 = 1.0/(Compartment_Gradient_Pascals/
* (2.0*(Surface_Tension_Gamma-Skin_Compression_GammaC))
* + 1.0/Initial_Critical_Radius_N2(I))
Regenerated_Radius_N2 =
* Initial_Critical_Radius_N2(I) +
* (Ending_Radius_N2 - Initial_Critical_Radius_N2(I)) *
* EXP(-Time_at_Altitude_Before_Dive/
* Regeneration_Time_Constant)
Initial_Critical_Radius_N2(I) =
* Regenerated_Radius_N2
Adjusted_Critical_Radius_N2(I) =
* Initial_Critical_Radius_N2(I)
END IF
END DO
Inspired_Nitrogen_Pressure = (Barometric_Pressure -
* Water_Vapor_Pressure)*0.79
DO I = 1,16
Initial_Nitrogen_Pressure = Nitrogen_Pressure(I)
Nitrogen_Pressure(I) = HALDANE_EQUATION
* (Initial_Nitrogen_Pressure, Inspired_Nitrogen_Pressure,
* Nitrogen_Time_Constant(I), Time_at_Altitude_Before_Dive)
END DO
END IF
CLOSE (UNIT = 12, STATUS = 'KEEP')
RETURN
C===============================================================================
C FORMAT STATEMENTS - PROGRAM OUTPUT
C===============================================================================
802 FORMAT ('0ALTITUDE = ',1X,F7.1,4X,'BAROMETRIC PRESSURE = ',
*F6.3)
C===============================================================================
C FORMAT STATEMENTS - ERROR MESSAGES
C===============================================================================
900 FORMAT ('0ERROR! ALTITUDE OF DIVE HIGHER THAN MOUNT EVEREST')
901 FORMAT (' ')
902 FORMAT ('0ERROR! DIVER ACCLIMATIZED AT ALTITUDE',
*1X,'MUST BE YES OR NO')
903 FORMAT ('0ERROR! STARTING ACCLIMATIZED ALTITUDE MUST BE LESS',
*1X,'THAN ALTITUDE OF DIVE')
904 FORMAT (' AND GREATER THAN OR EQUAL TO ZERO')
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
END
C===============================================================================
C SUBROUTINE CLOCK
C Purpose: This subprogram retrieves clock information from the Microsoft
C operating system so that date and time stamp can be included on program
C output.
C===============================================================================
SUBROUTINE CLOCK (Year, Month, Day, Clock_Hour, Minute, M)
IMPLICIT NONE
C===============================================================================
C ARGUMENTS
C===============================================================================
CHARACTER M*1 !output
INTEGER*2 Month, Day, Year !output
INTEGER*2 Minute, Clock_Hour !output
C===============================================================================
C LOCAL VARIABLES
C===============================================================================
INTEGER*2 Hour, Second, Hundredth
C===============================================================================
C CALCULATIONS
C===============================================================================
CALL GETDAT (Year, Month, Day) !Microsoft run-time
CALL GETTIM (Hour, Minute, Second, Hundredth) !subroutines
IF (Hour .GT. 12) THEN
Clock_Hour = Hour - 12
M = 'p'
ELSE
Clock_Hour = Hour
M = 'a'
ENDIF
C===============================================================================
C END OF SUBROUTINE
C===============================================================================
RETURN
END
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment