Skip to content

Commit

Permalink
Merge pull request firemodels#13615 from mcgratta/master
Browse files Browse the repository at this point in the history
FDS Source: Remove unnecessary FLUSH calls
  • Loading branch information
mcgratta authored Oct 23, 2024
2 parents 7ebf64e + f245567 commit 14f6838
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 115 deletions.
25 changes: 14 additions & 11 deletions Manuals/FDS_User_Guide/FDS_User_Guide.tex
Original file line number Diff line number Diff line change
Expand Up @@ -5533,7 +5533,7 @@ \subsection{Chemical Time Integration}
MAX_EQUIV_RATIO=20.0,
DO_CHEM_LOAD_BALANCE=T /
\end{lstlisting}
However, the relative and absolute tolerances for ODEs can be specified at the species level using the {\ct ODE\_REL\_ERROR} and {\ct ODE\_ABS\_ERROR} parameters. Currently, CVODE only supports absolute tolerance at the species level. The parameters {\ct EQUIV\_RATIO\_CHECK}, {\ct MIN\_EQUIV\_RATIO}, and {\ct MAX\_EQUIV\_RATIO} are optional. The purpose of {\ct EQUIV\_RATIO\_CHECK} (when true) is to save computational time by calling the chemistry solver only for cells where the equivalence ratio is within the specified {\ct MIN\_EQUIV\_RATIO} and {\ct MAX\_EQUIV\_RATIO} limits. Additionally, setting the parameter {\ct DO\_CHEM\_LOAD\_BALANCE} to true can significantly accelerate chemistry calculations by evenly distributing the chemistry workload across all MPI processes. The minimum concentration limit of a species is determined by multiplying {\ct ODE\_REL\_ERROR} to {\ct ZZ\_MIN\_GLOBAL}. Concentrations below this threshold are considered to be zero.
However, the relative and absolute tolerances for ODEs can be specified at the species level using the {\ct ODE\_REL\_ERROR} and {\ct ODE\_ABS\_ERROR} parameters. Currently, CVODE only supports absolute tolerance at the species level. The parameters {\ct EQUIV\_RATIO\_CHECK}, {\ct MIN\_EQUIV\_RATIO}, and {\ct MAX\_EQUIV\_RATIO} are optional. The purpose of {\ct EQUIV\_RATIO\_CHECK} (when true) is to save computational time by calling the chemistry solver only for cells where the equivalence ratio is within the specified {\ct MIN\_EQUIV\_RATIO} and {\ct MAX\_EQUIV\_RATIO} limits. Additionally, setting the parameter {\ct DO\_CHEM\_LOAD\_BALANCE} to true can significantly accelerate chemistry calculations by evenly distributing the chemistry workload across all MPI processes. The minimum concentration limit of a species is determined by multiplying {\ct ODE\_REL\_ERROR} to {\ct ZZ\_MIN\_GLOBAL}. Concentrations below this threshold are considered to be zero.

For CVODE, the default parameter values are as follows: {\ct FINITE\_RATE\_MIN\_TEMP}=300~$^\circ$C, {\ct ZZ\_MIN\_GLOBAL}=1E-10, {\ct ODE\_MIN\_ATOL}=1E-10, {\ct ODE\_REL\_ERROR}=1E-6, {\ct EQUIV\_RATIO\_CHECK}=F, {\ct MIN\_EQUIV\_RATIO}=0.0, {\ct MAX\_EQUIV\_RATIO}=20.0, and {\ct DO\_CHEM\_LOAD\_BALANCE}=T. To use these default values, simply add the following lines to the FDS input file:
\begin{lstlisting}
Expand Down Expand Up @@ -6417,7 +6417,7 @@ \subsubsection{Randomly Distributed Particles within a Specified Volume}
\end{lstlisting}
Note that the volume of the specified region is calculated according to the {\ct SHAPE} dimensions, regardless of whether there are solid obstructions within this region. Note also that in most applications, the number of particles, {\ct N\_PARTICLES}, is somewhat arbitrary but should be chosen to provide at least a few particles per grid cell. FDS will then automatically assign a weighting factor to each particle to ensure that the {\ct MASS\_PER\_VOLUME} is achieved. In some applications, on the other hand, it may be important to specify the number of particles. For example, if using particles to model the burning of electrical cables, you may want to specify how many cables are actually burning. The {\ct MASS\_PER\_VOLUME} can be ramped up and down in time using the ramp function {\ct RAMP\_PART} on the {\ct INIT} line.

If the volume specified by the sextuplet {\ct XB} crosses mesh boundaries, be aware that {\ct N\_PARTICLES} refers to the entire volume, not just the volume within a particular mesh. FDS will automatically compute the necessary number of particles to assign to each mesh. This is done by multiplying {\ct N\_PARTICLES} by the ratio of the volume of {\ct XB} in each mesh by the total volume of {\ct XB} as specified in the input file (i.e, if the input is larger than the domain, fewer than {\ct N\_PARTICLES} will be inserted) with the result rounded to the nearest integer (with at least one particle inserted for every mesh that contains {\ct XB}).
If the volume specified by the sextuplet {\ct XB} crosses mesh boundaries, be aware that {\ct N\_PARTICLES} refers to the entire volume, not just the volume within a particular mesh. FDS will automatically compute the necessary number of particles to assign to each mesh. This is done by multiplying {\ct N\_PARTICLES} by the ratio of the volume of {\ct XB} in each mesh by the total volume of {\ct XB} as specified in the input file (i.e, if the input is larger than the domain, fewer than {\ct N\_PARTICLES} will be inserted) with the result rounded to the nearest integer (with at least one particle inserted for every mesh that contains {\ct XB}).

Alternatively, you can specify {\ct SHAPE='CONE'}, in which case the particles will be randomly distributed within a vertical cone. This is primarily used for representing trees. The dimensions of the cone are specified via the parameters {\ct RADIUS}, {\ct HEIGHT}, and base position {\ct XYZ}. The latter is a triplet of real numbers designating the point at the center of the base of the cone. Here is an example of how one might make a tree:
\begin{lstlisting}
Expand Down Expand Up @@ -10694,7 +10694,7 @@ \subsection{Detailed Spray Properties}
The first function, $f_1(t)$, is used for the computation of various mean diameters, with associated properties defined using the following keywords on the {\ct PROP} line:
\begin{description}
\item[{\ct PDPA\_M}] is the exponent $m$ in the numerator.
\item[{\ct PDPA\_N}] is the exponent $n$ in denominator.
\item[{\ct PDPA\_N}] is the exponent $n$ in denominator.
\end{description}
If $m=n$, the exponent $1/(m-n)$ is removed from the formula.

Expand Down Expand Up @@ -14543,21 +14543,24 @@ \section{Boundary Files ({\tt .bf})}
WRITE(LUBF) QUANTITY
WRITE(LUBF) SHORT_NAME
WRITE(LUBF) UNITS
WRITE(LUBF) NPATCH
WRITE(LUBF) I1,I2,J1,J2,K1,K2,IOR,NB,NM
WRITE(LUBF) I1,I2,J1,J2,K1,K2,IOR,NB,NM
WRITE(LUBF) N_PATCH
WRITE(LUBF) I1,I2,J1,J2,K1,K2,IOR,OBST_INDEX,NM
WRITE(LUBF) I1,I2,J1,J2,K1,K2,IOR,OBST_INDEX,NM
.
. WRITE(LUBF) TIME
.
WRITE(LUBF) TIME_1
WRITE(LUBF) (((QQ(I,J,K),I=11,I2),J=J1,J2),K=K1,K2)
WRITE(LUBF) (((QQ(I,J,K),I=11,I2),J=J1,J2),K=K1,K2)
.
. WRITE(LUBF) TIME
.
WRITE(LUBF) TIME_2
WRITE(LUBF) (((QQ(I,J,K),I=11,I2),J=J1,J2),K=K1,K2)
WRITE(LUBF) (((QQ(I,J,K),I=11,I2),J=J1,J2),K=K1,K2) .
WRITE(LUBF) (((QQ(I,J,K),I=11,I2),J=J1,J2),K=K1,K2)
.
.
\end{lstlisting}
{\ct QUANTITY}, {\ct SHORT\_NAME} and {\ct UNITS} are character strings of length 30. {\ct NPATCH} is the number of planes (or ``patches'') that make up the solid boundaries plus the external walls. The sextuplet ({\ct I1,I2,J1,J2,K1,K2}) defines the cell nodes of each patch. {\ct IOR} is an integer indicating the orientation of the patch ($\pm 1,\pm 2,\pm 3$). You do not prescribe these. {\ct NB} is the number of the boundary (zero for external walls) and {\ct NM} is the number of the mesh. Note that the data is planar, thus one pair of cell nodes is the same. Presently, Smokeview is the
only program available to view the boundary files.
{\ct QUANTITY}, {\ct SHORT\_NAME} and {\ct UNITS} are character strings of length 30. {\ct N\_PATCH} is the number of planes (or ``patches'') that correspond to solid surfaces. The sextuplet ({\ct I1,I2,J1,J2,K1,K2}) defines the cell indices of each patch. For example, a patch on the lower $x$ boundary of the domain that spans cells 2 through 5 in the $y$ direction and 7 through 10 in the $z$ direction would have patch indices (0,0,1,5,6,10). Note that the boundary patches are 2-D; thus, one pair of cell indices is the same. {\ct IOR} is an integer indicating the orientation of the patch ($\pm 1,\pm 2,\pm 3$). {\ct OBST\_INDEX} refers to the solid obstruction ({\ct OBST}) to which the patch is affixed. Its value is 0 if the patch is affixed to an external boundary. {\ct NM} is the number of the mesh within which the obstruction lies. It may be different than the mesh containing the boundary data; that is, {\ct NM} is not necessarily equal to the mesh index {\ct M} in the file name. {\ct TIME\_N} and {\ct QQ} are four-byte reals.


\section{Particle Data ({\tt .prt5})}
\label{out:PART}
Expand Down
142 changes: 42 additions & 100 deletions Source/dump.f90
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ MODULE DUMP
TYPE (INITIALIZATION_TYPE), POINTER :: IN=>NULL()

PUBLIC ASSIGN_FILE_NAMES,INITIALIZE_GLOBAL_DUMPS,INITIALIZE_MESH_DUMPS,WRITE_STATUS_FILES, &
TIMINGS,FLUSH_GLOBAL_BUFFERS,FLUSH_LOCAL_BUFFERS,READ_RESTART,WRITE_DIAGNOSTICS, &
TIMINGS,FLUSH_GLOBAL_BUFFERS,READ_RESTART,WRITE_DIAGNOSTICS, &
WRITE_SMOKEVIEW_FILE,DUMP_MESH_OUTPUTS,UPDATE_GLOBAL_OUTPUTS,DUMP_DEVICES,DUMP_HRR,&
DUMP_MASS,DUMP_CONTROLS,INITIALIZE_DIAGNOSTIC_FILE,DUMP_RESTART,DUMP_HVAC,&
DUMP_GEOM,UPDATE_DEVICES_2,WRITE_DEVC_CTRL_LOG
Expand Down Expand Up @@ -1025,42 +1025,42 @@ SUBROUTINE INITIALIZE_MESH_DUMPS(NM)

! Initialize isosurface file

DO N=1,N_ISOF
IS => ISOSURFACE_FILE(N)
IF (.NOT. APPEND) THEN
OPEN(ABS(LU_ISOF(N,NM)),FILE=FN_ISOF(N,NM),FORM='UNFORMATTED',STATUS='REPLACE')
IF (IS%INDEX2 /= -1 ) THEN
OPEN(ABS(LU_ISOF2(N,NM)),FILE=FN_ISOF2(N,NM),FORM='UNFORMATTED',STATUS='REPLACE')
ENDIF
IF (M%N_STRINGS+5>M%N_STRINGS_MAX) CALL RE_ALLOCATE_STRINGS(NM)
M%N_STRINGS = M%N_STRINGS + 1
IF (IS%INDEX2 .EQ. -1 ) THEN
WRITE(M%STRING(M%N_STRINGS),'(A,I6,1X,I6,1X,E13.6)') 'ISOG',NM,IS%SKIP,IS%DELTA
ELSE
WRITE(M%STRING(M%N_STRINGS),'(A,I6,1X,I6,1X,E13.6)') 'TISOG',NM,IS%SKIP,IS%DELTA
ENDIF
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(FN_ISOF(N,NM)) ! geometry
IF (IS%INDEX2 /= -1 ) THEN
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(FN_ISOF2(N,NM)) ! data
ENDIF
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(IS%SMOKEVIEW_LABEL) ! labels for geometry
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(IS%SMOKEVIEW_BAR_LABEL)
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(OUTPUT_QUANTITY(IS%INDEX)%UNITS)
IF (IS%INDEX2 /= -1 ) THEN
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(IS%SMOKEVIEW_LABEL2) ! labels for data
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(IS%SMOKEVIEW_BAR_LABEL2)
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(OUTPUT_QUANTITY(IS%INDEX2)%UNITS)
ENDIF
DO N=1,N_ISOF
IS => ISOSURFACE_FILE(N)
IF (.NOT. APPEND) THEN
OPEN(ABS(LU_ISOF(N,NM)),FILE=FN_ISOF(N,NM),FORM='UNFORMATTED',STATUS='REPLACE')
IF (IS%INDEX2 /= -1 ) OPEN(ABS(LU_ISOF2(N,NM)),FILE=FN_ISOF2(N,NM),FORM='UNFORMATTED',STATUS='REPLACE')
IF (M%N_STRINGS+5>M%N_STRINGS_MAX) CALL RE_ALLOCATE_STRINGS(NM)
M%N_STRINGS = M%N_STRINGS + 1
IF (IS%INDEX2 .EQ. -1 ) THEN
WRITE(M%STRING(M%N_STRINGS),'(A,I6,1X,I6,1X,E13.6)') 'ISOG',NM,IS%SKIP,IS%DELTA
ELSE
WRITE(M%STRING(M%N_STRINGS),'(A,I6,1X,I6,1X,E13.6)') 'TISOG',NM,IS%SKIP,IS%DELTA
ENDIF
ENDDO
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(FN_ISOF(N,NM)) ! geometry
IF (IS%INDEX2 /= -1 ) THEN
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(FN_ISOF2(N,NM)) ! data
ENDIF
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(IS%SMOKEVIEW_LABEL) ! labels for geometry
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(IS%SMOKEVIEW_BAR_LABEL)
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(OUTPUT_QUANTITY(IS%INDEX)%UNITS)
IF (IS%INDEX2 /= -1 ) THEN
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(IS%SMOKEVIEW_LABEL2) ! labels for data
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(IS%SMOKEVIEW_BAR_LABEL2)
M%N_STRINGS = M%N_STRINGS + 1
WRITE(M%STRING(M%N_STRINGS),'(1X,A)') TRIM(OUTPUT_QUANTITY(IS%INDEX2)%UNITS)
ENDIF
CLOSE(ABS(LU_ISOF(N,NM)))
IF (IS%INDEX2 /= -1 ) CLOSE(ABS(LU_ISOF2(N,NM)))
ENDIF
ENDDO

! Initialize Smoke3d file

Expand Down Expand Up @@ -4240,6 +4240,9 @@ SUBROUTINE DUMP_ISOF(T,DT,NM)

ENDIF INDEX2_IF

OPEN(ABS(LU_ISOF(N,NM)),FILE=FN_ISOF(N,NM),FORM='UNFORMATTED',STATUS='OLD',POSITION='APPEND')
IF (IS%INDEX2 /= -1 ) OPEN(ABS(LU_ISOF2(N,NM)),FILE=FN_ISOF2(N,NM),FORM='UNFORMATTED',STATUS='OLD',POSITION='APPEND')

IF (IS%DEBUG) THEN
TIME_FACTOR = MAX(0.05_EB, (STIME - T_BEGIN)/(T_END - T_BEGIN))
ISO_LEVEL(1) = REAL(TIME_FACTOR*(ZF_MAX-ZS_MIN)/2.0_EB, FB)
Expand All @@ -4251,6 +4254,9 @@ SUBROUTINE DUMP_ISOF(T,DT,NM)
IS%VALUE(1:IS%N_VALUES), IS%N_VALUES, IBLK, IS%SKIP, IS%DELTA, XPLT, IBP1, YPLT, JBP1, ZPLT, KBP1)
ENDIF

CLOSE(ABS(LU_ISOF(N,NM)))
IF (IS%INDEX2 /= -1 ) CLOSE(ABS(LU_ISOF2(N,NM)))

ENDDO ISOF_LOOP

END SUBROUTINE DUMP_ISOF
Expand Down Expand Up @@ -10540,70 +10546,6 @@ SUBROUTINE FLUSH_GLOBAL_BUFFERS
END SUBROUTINE FLUSH_GLOBAL_BUFFERS


!> \brief Periodically purge output files associated with mesh NM
!> \param NM Mesh number

SUBROUTINE FLUSH_LOCAL_BUFFERS(NM)

USE COMP_FUNCTIONS, ONLY : CURRENT_TIME
INTEGER, INTENT(IN) :: NM
INTEGER :: N
REAL(EB) :: TNOW

TNOW = CURRENT_TIME()

IF (PARTICLE_FILE) THEN
INQUIRE(UNIT=LU_PART(NM),OPENED=OPN)
IF (OPN) FLUSH(LU_PART(NM))
INQUIRE(UNIT=LU_PART(NM+NMESHES),OPENED=OPN)
IF (OPN) FLUSH(LU_PART(NM+NMESHES))
ENDIF

DO N=1,MESHES(NM)%N_SLCF
INQUIRE(UNIT=LU_SLCF(N,NM),OPENED=OPN)
IF (OPN) FLUSH(LU_SLCF(N,NM))
INQUIRE(UNIT=LU_SLCF(N+N_SLCF_MAX,NM),OPENED=OPN)
IF (OPN) FLUSH(LU_SLCF(N+N_SLCF_MAX,NM))
INQUIRE(UNIT=LU_SLCF(N+2*N_SLCF_MAX,NM),OPENED=OPN)
IF (OPN) FLUSH(LU_SLCF(N+2*N_SLCF_MAX,NM))
ENDDO

DO N=1,N_ISOF
INQUIRE(UNIT=ABS(LU_ISOF(N,NM)),OPENED=OPN)
IF (OPN) FLUSH(ABS(LU_ISOF(N,NM)))
INQUIRE(UNIT=ABS(LU_ISOF2(N,NM)),OPENED=OPN)
IF (OPN) FLUSH(ABS(LU_ISOF2(N,NM)))
ENDDO

DO N=1,N_SMOKE3D
INQUIRE(UNIT=LU_SMOKE3D(N,NM),OPENED=OPN)
IF (OPN) FLUSH(LU_SMOKE3D(N,NM))
INQUIRE(UNIT=LU_SMOKE3D(N+N_SMOKE3D,NM),OPENED=OPN)
IF (OPN) FLUSH(LU_SMOKE3D(N+N_SMOKE3D,NM))
IF (SMOKE3D_16) THEN
INQUIRE(UNIT=LU_SMOKE3D(N+2*N_SMOKE3D,NM),OPENED=OPN)
IF (OPN) FLUSH(LU_SMOKE3D(N+2*N_SMOKE3D,NM))
ENDIF
ENDDO

DO N=1,N_BNDF
INQUIRE(UNIT=LU_BNDF(N,NM),OPENED=OPN)
IF (OPN) FLUSH(LU_BNDF(N,NM))
INQUIRE(UNIT=LU_BNDF(N+N_BNDF,NM),OPENED=OPN)
IF (OPN) FLUSH(LU_BNDF(N+N_BNDF,NM))
ENDDO

DO N=1,N_PROF
IF (PROFILE(N)%MESH==NM) THEN
INQUIRE(UNIT=LU_PROF(N),OPENED=OPN)
IF (OPN) FLUSH(LU_PROF(N))
ENDIF
ENDDO

T_USED(7) = T_USED(7) + CURRENT_TIME() - TNOW
END SUBROUTINE FLUSH_LOCAL_BUFFERS


!> \brief Print out detector activation times and total elapsed time into .out file.

SUBROUTINE TIMINGS
Expand Down
4 changes: 0 additions & 4 deletions Source/main.f90
Original file line number Diff line number Diff line change
Expand Up @@ -985,10 +985,6 @@ PROGRAM FDS
IF (FLUSH_FILE_BUFFERS) THEN
IF (T>=FLSH_CLOCK(FLSH_COUNTER(1))) THEN
IF (MY_RANK==0) CALL FLUSH_GLOBAL_BUFFERS
CALL MPI_BARRIER(MPI_COMM_WORLD,IERR) ! Force all processes to sync up before dumping buffers
DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX
CALL FLUSH_LOCAL_BUFFERS(NM)
ENDDO
FLSH_COUNTER(1) = FLSH_COUNTER(1) + 1
ENDIF
ENDIF
Expand Down

0 comments on commit 14f6838

Please sign in to comment.