Skip to content

Commit adb9a34

Browse files
committed
Merge remote-tracking branch 'firemodels/master' into FireX
2 parents 7f99313 + 02f7344 commit adb9a34

File tree

19 files changed

+252
-464
lines changed

19 files changed

+252
-464
lines changed

Manuals/FDS_User_Guide/FDS_User_Guide.tex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3542,7 +3542,7 @@ \subsection{Louvered Vents}
35423542
\begin{lstlisting}
35433543
&SURF ID='LOUVER', VEL=-2.0, VEL_T=3.0,0.0, TAU_V=5., COLOR='GREEN' /
35443544
\end{lstlisting}
3545-
is a boundary condition for a louvered vent that pushes air into the space with a normal velocity of 2~m/s and a tangential velocity of 3~m/s in the first of the two tangential directions. Note that the negative sign of the normal component of velocity indicates that the fluid is injected into the computational domain. The tangential velocity of 3~m/s indicates that the flow is in the positive $y$ direction. Both the normal and tangential velocity components are ramped up with either \ct{TAU_V} or \ct{RAMP_V}, as shown in Fig.~\ref{fig:tangential_velocity}.
3545+
is a boundary condition for a louvered vent that pushes air into the space with a normal velocity of 2~m/s and a tangential velocity of 3~m/s in the first of the two tangential directions. Note that the negative sign of the normal component of velocity indicates that the fluid is injected into the computational domain. The tangential velocity of 3~m/s indicates that the flow is in the positive $y$ direction. Both the normal and tangential velocity components are ramped up with either \ct{TAU_V} or \ct{RAMP_V}, as shown in Fig.~\ref{fig:tangential_velocity}. If the boundary condition is specified with \ct{MASS_FLUX}, then \ct{VEL_T} should be specified assuming a wall normal velocity of 1~m/s. FDS will then scale the input values for \ct{VEL_T} based on the current wall velocity given by the species mass fractions, mass flux, and wall temperature.
35463546

35473547
\begin{figure}[ht!]
35483548
\begin{center}

Source/data.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2452,7 +2452,7 @@ SUBROUTINE THERMO_TABLE_LIQUID(I_TMP,CP,H_V,T_REF,T_MELT,T_BOIL,SPEC_INDEX,FUEL,
24522452
LOGICAL,INTENT(OUT) :: FUEL
24532453
TYPE (THERMO_DATA_TYPE), POINTER :: TD
24542454

2455-
!Default to water properteis
2455+
! Default to water properties
24562456

24572457
IF (SPEC_INDEX < 0) THEN
24582458
FUEL = .FALSE.

Source/vege.f90

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,9 @@ SUBROUTINE LEVEL_SET_FIRESPREAD(T,DT,NM)
430430
U_Z(2) = 0.5_EB*(U(IIG-1,JJG,KWIND)+U(IIG,JJG,KWIND))
431431
V_Z(1) = 0.5_EB*(V(IIG,JJG-1,KWIND-1)+V(IIG,JJG,KWIND-1))
432432
V_Z(2) = 0.5_EB*(V(IIG,JJG-1,KWIND)+V(IIG,JJG,KWIND))
433-
! If wind comes from first grid cell assume zero wind at ground level
433+
! If wind comes from first grid cell assume plug flow near ground level
434434
IF (KWIND==1) THEN
435-
U_Z(1) = 0._EB; V_Z(1) = 0._EB; ZWIND(1) = 0._EB
435+
U_Z(1) = U_Z(2); V_Z(1) = V_Z(2); ZWIND(1) = Z_LS(IIG,JJG)
436436
ENDIF
437437
U_LS(IIG,JJG) = U_Z(1) + (REF_WIND_HEIGHT-ZWIND(1))/(ZWIND(2)-ZWIND(1))*(U_Z(2)-U_Z(1))
438438
V_LS(IIG,JJG) = V_Z(1) + (REF_WIND_HEIGHT-ZWIND(1))/(ZWIND(2)-ZWIND(1))*(V_Z(2)-V_Z(1))

Source/velo.f90

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1816,7 +1816,7 @@ SUBROUTINE VELOCITY_BC(T,NM,APPLY_TO_ESTIMATED_VARIABLES)
18161816
REAL(EB) :: MUA,TSI,WGT,T_NOW,RAMP_T,OMW,MU_WALL,RHO_WALL,SLIP_COEF,VEL_T, &
18171817
UUP(2),UUM(2),DXX(2),MU_DUIDXJ(-2:2),DUIDXJ(-2:2),PROFILE_FACTOR,VEL_GAS,VEL_GHOST, &
18181818
MU_DUIDXJ_USE(2),DUIDXJ_USE(2),VEL_EDDY,U_TAU,Y_PLUS,U_NORM,U_WIND_LOC,V_WIND_LOC,W_WIND_LOC,&
1819-
DRAG_FACTOR,HT_SCALE_FACTOR,VEG_HT
1819+
DRAG_FACTOR,HT_SCALE_FACTOR,VEG_HT,VEL_MF
18201820
INTEGER :: NOM(2),IIO(2),JJO(2),KKO(2),IE,II,JJ,KK,IEC,IOR,IWM,IWP,ICMM,ICMP,ICPM,ICPP,ICD,ICDO,IVL,I_SGN, &
18211821
VELOCITY_BC_INDEX,IIGM,JJGM,KKGM,IIGP,JJGP,KKGP,SURF_INDEXM,SURF_INDEXP,ITMP,ICD_SGN,ICDO_SGN, &
18221822
BOUNDARY_TYPE_M,BOUNDARY_TYPE_P,IS,IS2,IWPI,IWMI,VENT_INDEX
@@ -2293,20 +2293,31 @@ SUBROUTINE VELOCITY_BC(T,NM,APPLY_TO_ESTIMATED_VARIABLES)
22932293
END SELECT
22942294

22952295
ELSE
2296-
22972296
PROFILE_FACTOR = 1._EB
2298-
IF (ABS(SF%T_IGN-T_BEGIN)<=SPACING(SF%T_IGN) .AND. SF%RAMP(TIME_VELO)%INDEX>=1) THEN
2299-
TSI = T
2300-
ELSE
2301-
TSI=T-SF%T_IGN
2297+
IF (ABS(SF%VEL) > 0._EB) THEN
2298+
IF (ABS(SF%T_IGN-T_BEGIN)<=SPACING(SF%T_IGN) .AND. SF%RAMP(TIME_VELO)%INDEX>=1) THEN
2299+
TSI = T
2300+
ELSE
2301+
TSI=T-SF%T_IGN
2302+
ENDIF
2303+
RAMP_T = EVALUATE_RAMP(TSI,SF%RAMP(TIME_VELO)%INDEX,TAU=SF%RAMP(TIME_VELO)%TAU)
2304+
IF (SF%VEL < 0._EB) THEN
2305+
IF (SF%RAMP(VELO_PROF_Z)%INDEX>0) PROFILE_FACTOR = EVALUATE_RAMP(ZC(KK),SF%RAMP(VELO_PROF_Z)%INDEX)
2306+
IF (IEC==1 .OR. (IEC==2 .AND. ICD==2)) VEL_T = RAMP_T*(PROFILE_FACTOR*(SF%VEL_T(2) + VEL_EDDY))
2307+
IF (IEC==3 .OR. (IEC==2 .AND. ICD==1)) VEL_T = RAMP_T*(PROFILE_FACTOR*(SF%VEL_T(1) + VEL_EDDY))
2308+
ELSE
2309+
IF (SF%PROFILE/=0) PROFILE_FACTOR = ABS(0.5_EB*(WCM_B1%U_NORMAL_0+WCP_B1%U_NORMAL_0)/SF%VEL)
2310+
IF (SF%RAMP(VELO_PROF_Z)%INDEX>0) PROFILE_FACTOR = EVALUATE_RAMP(ZC(KK),SF%RAMP(VELO_PROF_Z)%INDEX)
2311+
IF (IEC==1 .OR. (IEC==2 .AND. ICD==2)) VEL_T = RAMP_T*PROFILE_FACTOR*VEL_EDDY
2312+
IF (IEC==3 .OR. (IEC==2 .AND. ICD==1)) VEL_T = RAMP_T*PROFILE_FACTOR*VEL_EDDY
2313+
ENDIF
2314+
ELSE ! Mass flux BC
2315+
VEL_MF = 0.5_EB*(WCM_B1%U_NORMAL_S+WCP_B1%U_NORMAL_S)
2316+
IF (VEL_MF < 0._EB) THEN
2317+
IF (IEC==1 .OR. (IEC==2 .AND. ICD==2)) VEL_T = -SF%VEL_T(2)*VEL_MF
2318+
IF (IEC==3 .OR. (IEC==2 .AND. ICD==1)) VEL_T = -SF%VEL_T(1)*VEL_MF
2319+
ENDIF
23022320
ENDIF
2303-
IF (SF%PROFILE/=0 .AND. SF%VEL>TWO_EPSILON_EB) &
2304-
PROFILE_FACTOR = ABS(0.5_EB*(WCM_B1%U_NORMAL_0+WCP_B1%U_NORMAL_0)/SF%VEL)
2305-
IF (SF%RAMP(VELO_PROF_Z)%INDEX>0) PROFILE_FACTOR = EVALUATE_RAMP(ZC(KK),SF%RAMP(VELO_PROF_Z)%INDEX)
2306-
RAMP_T = EVALUATE_RAMP(TSI,SF%RAMP(TIME_VELO)%INDEX,TAU=SF%RAMP(TIME_VELO)%TAU)
2307-
IF (IEC==1 .OR. (IEC==2 .AND. ICD==2)) VEL_T = RAMP_T*(PROFILE_FACTOR*(SF%VEL_T(2) + VEL_EDDY))
2308-
IF (IEC==3 .OR. (IEC==2 .AND. ICD==1)) VEL_T = RAMP_T*(PROFILE_FACTOR*(SF%VEL_T(1) + VEL_EDDY))
2309-
23102321
ENDIF
23112322

23122323
! Choose the appropriate boundary condition to apply

Utilities/Python/FDS_verification_script.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
print("fan_curve..."); runpy.run_path("./scripts/fan_curve.py", run_name="__main__")
5050
print("favre_test..."); runpy.run_path("./scripts/favre_test.py", run_name="__main__")
5151
print("fds_moody_chart..."); runpy.run_path("./scripts/fds_moody_chart.py", run_name="__main__")
52+
print("fds_timing_stats..."); runpy.run_path("./scripts/fds_timing_stats.py", run_name="__main__")
5253
print("fluid_part..."); runpy.run_path("./scripts/fluid_part.py", run_name="__main__")
5354
print("freecon_sphere..."); runpy.run_path("./scripts/freecon_sphere.py", run_name="__main__")
5455
print("geom_channel_test..."); runpy.run_path("./scripts/geom_channel_test.py", run_name="__main__")
@@ -61,6 +62,7 @@
6162
print("law_of_the_wall..."); runpy.run_path("./scripts/law_of_the_wall.py", run_name="__main__")
6263
print("level_set_ellipse..."); runpy.run_path("./scripts/level_set_ellipse.py", run_name="__main__")
6364
print("mesh_transformation..."); runpy.run_path("./scripts/mesh_transformation.py", run_name="__main__")
65+
print("make_smv_images..."); runpy.run_path("./scripts/make_smv_images.py", run_name="__main__")
6466
print("mass_balance..."); runpy.run_path("./scripts/mass_balance.py", run_name="__main__")
6567
print("mass_balance_gas_volume..."); runpy.run_path("./scripts/mass_balance_gas_volume.py", run_name="__main__")
6668
print("mass_balance_reac..."); runpy.run_path("./scripts/mass_balance_reac.py", run_name="__main__")
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
2+
# Produce a table of verification case CPU times in Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/Scatterplots
3+
4+
import os
5+
import subprocess
6+
import csv
7+
8+
curdir = os.getcwd()
9+
verdir = '../../Verification/'
10+
resdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/Scatterplots/'
11+
resfile = resdir + 'fds_timing_stats.csv'
12+
13+
with open(resfile, 'w') as f:
14+
f.write('FDS Case,Wall Clock Time (s),CPU Time (s),Number of Cells,Number of Time Steps,Performance Metric (1e-6)\n')
15+
16+
with open(verdir + 'FDS_Cases.sh', 'r') as casefile:
17+
for line in casefile:
18+
if line.strip().startswith('$QFDS'):
19+
parts = line.split()
20+
if '-d' in parts:
21+
d_index = parts.index('-d')
22+
if d_index + 2 < len(parts):
23+
subdir = parts[d_index + 1]
24+
fdsfile = parts[d_index + 2]
25+
26+
# Extract base filename without extension
27+
fdsbase = verdir + subdir + '/' + os.path.splitext(fdsfile)[0]
28+
outfile = f"{fdsbase}.out"
29+
cpufile = f"{fdsbase}_cpu.csv"
30+
31+
# Check if outfile exists, try alternate name if not
32+
if not os.path.exists(outfile):
33+
outfile = f"{fdsbase}_cat.out"
34+
if not os.path.exists(outfile):
35+
continue
36+
37+
# Check if cpufile exists, try alternate name if not
38+
if not os.path.exists(cpufile):
39+
cpufile = f"{fdsbase}_cat_cpu.csv"
40+
if not os.path.exists(cpufile):
41+
continue
42+
43+
# Grep for wall clock time
44+
WALL_CLOCK_TIME_VALUE = ""
45+
with open(outfile, 'r') as f:
46+
for line in f:
47+
if "Total Elapsed Wall Clock Time (s):" in line:
48+
WALL_CLOCK_TIME_VALUE = line.strip().split()[-1]
49+
50+
# Grep for CPU time and units
51+
TOTAL_CPU_TIME = 0.0
52+
CPU_TIME_VALUES = []
53+
54+
with open(cpufile, 'r') as f:
55+
lines = f.readlines()
56+
# Skip first line (header), process rest
57+
for line in lines[1:]:
58+
if line.strip():
59+
# Get last column (split by comma)
60+
parts = line.strip().split(',')
61+
if parts:
62+
CPU_TIME_VALUES.append(parts[-1])
63+
64+
# Process each CPU time value
65+
for j in CPU_TIME_VALUES:
66+
TOTAL_CPU_TIME += eval(j)
67+
68+
CPU_TIME = TOTAL_CPU_TIME
69+
70+
# Grep for number of cells in each dimension
71+
X_CELLS = []
72+
Y_CELLS = []
73+
Z_CELLS = []
74+
75+
with open(outfile, 'r') as f:
76+
for line in f:
77+
if "Cells in the X" in line:
78+
X_CELLS.append(line.strip().split()[-1])
79+
elif "Cells in the Y" in line:
80+
Y_CELLS.append(line.strip().split()[-1])
81+
elif "Cells in the Z" in line:
82+
Z_CELLS.append(line.strip().split()[-1])
83+
84+
numx = len(X_CELLS)
85+
86+
# Sum over the number of cells (for multi-mesh cases)
87+
NUM_TOTAL_CELLS = 0
88+
for i in range(numx):
89+
XI = int(X_CELLS[i])
90+
YI = int(Y_CELLS[i])
91+
ZI = int(Z_CELLS[i])
92+
sumxyz = XI * YI * ZI
93+
NUM_TOTAL_CELLS += sumxyz
94+
95+
# Grep for number of time steps
96+
NUM_TIME_STEPS = 0
97+
time_step_lines = []
98+
with open(outfile, 'r') as f:
99+
for line in f:
100+
if "Time Step " in line:
101+
time_step_lines.append(line)
102+
103+
if time_step_lines:
104+
# Get the last occurrence
105+
last_line = time_step_lines[-1]
106+
parts = last_line.strip().split()
107+
if len(parts) >= 5:
108+
# Get the 5th element from the end (NF-4 in awk)
109+
NUM_TIME_STEPS = int(parts[-5])
110+
111+
# Calculate nondimensional performance metric
112+
# Skip over cases with no time steps
113+
if NUM_TIME_STEPS == 0:
114+
NUM_TIME_STEPS = 0
115+
PERFORMANCE = 0
116+
else:
117+
# Calculate performance metric
118+
PERFORMANCE = int(1000000 * TOTAL_CPU_TIME / (NUM_TOTAL_CELLS * NUM_TIME_STEPS))
119+
120+
# Write results to fds_timing_stats.csv file
121+
with open(resfile, 'a', newline='') as f:
122+
csv_writer = csv.writer(f)
123+
csv_writer.writerow([fdsfile,WALL_CLOCK_TIME_VALUE,CPU_TIME,NUM_TOTAL_CELLS,NUM_TIME_STEPS,PERFORMANCE])
124+
125+
126+
# Sum up the wall clock times in the second column
127+
128+
TOTAL_CPU_TIME = 0.0
129+
with open(resfile, 'r') as f:
130+
lines = f.readlines()
131+
for line in lines[1:]:
132+
if line.strip():
133+
fields = line.split(',')
134+
if len(fields) >= 3:
135+
j = fields[1].strip()
136+
TOTAL_CPU_TIME = TOTAL_CPU_TIME + eval(j)
137+
138+
# Get git short commit hash and append to tmpout
139+
140+
git_hash = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD'], cwd=curdir, universal_newlines=True).strip()
141+
142+
# Append git hash and total CPU time to fds_timing_stats.csv
143+
144+
with open(resfile, 'a') as f:
145+
f.write(git_hash + '\n')
146+
f.write(str(TOTAL_CPU_TIME) + '\n')
147+

Utilities/Python/scripts/make_smv_images.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
smokeview_path = shutil.which(shell_command)
3737

3838
for i in range(len(folder)):
39-
print(case[i])
39+
print('generating smokeview image ' + case[i])
4040
os.chdir(outdir + folder[i])
4141
if os_name == "Linux":
4242
subprocess.run(['xvfb-run','-a',smokeview_path,'-runscript',case[i]], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

Utilities/Scripts/fds_timing_stats.sh

Lines changed: 0 additions & 46 deletions
This file was deleted.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
import json
3+
import urllib.request
4+
5+
FDSURL = "https://api.github.com/repos/firemodels/fds/releases"
6+
SMVURL = "https://api.github.com/repos/firemodels/smv/releases"
7+
BUNDLE = "FDS-6.10.1_SMV-6.10.1"
8+
SMV = "SMV-6.10.5"
9+
LINUX = "_lnx.sh"
10+
OSX = "_osx.sh"
11+
WIN = "_win.exe"
12+
13+
14+
def get_downloads(filename: str, releases_url: str) -> int:
15+
"""
16+
Retrieve the download count for a given asset filename from a GitHub releases feed.
17+
Returns 0 if the asset cannot be found.
18+
"""
19+
request = urllib.request.Request(
20+
releases_url,
21+
headers={
22+
"Accept": "application/vnd.github+json",
23+
"User-Agent": "python-urllib"
24+
},
25+
)
26+
with urllib.request.urlopen(request, timeout=30) as response:
27+
releases = json.load(response)
28+
29+
for release in releases:
30+
for asset in release.get("assets", []):
31+
if asset.get("name") == filename:
32+
return int(asset.get("download_count", 0))
33+
return 0
34+
35+
36+
print("bundle downloads")
37+
print(f"FILE={BUNDLE}{LINUX} downloads={get_downloads(BUNDLE + LINUX, FDSURL)}")
38+
print(f"FILE={BUNDLE}{OSX} downloads={get_downloads(BUNDLE + OSX, FDSURL)}")
39+
print(f"FILE={BUNDLE}{WIN} downloads={get_downloads(BUNDLE + WIN, FDSURL)}")
40+
41+
print("")
42+
print("smokeview downloads")
43+
print(f"FILE={SMV}{LINUX} downloads={get_downloads(SMV + LINUX, SMVURL)}")
44+
print(f"FILE={SMV}{OSX} downloads={get_downloads(SMV + OSX, SMVURL)}")
45+
print(f"FILE={SMV}{WIN} downloads={get_downloads(SMV + WIN, SMVURL)}")
46+

Utilities/Scripts/get_download_count.sh

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)