diff --git a/Manuals/FDS_User_Guide/FIGURES/FDS_User_Guide_Cartesian_Particle_Drawing.pdf b/Manuals/FDS_User_Guide/FIGURES/FDS_User_Guide_Cartesian_Particle_Drawing.pdf deleted file mode 100644 index ac8f35aecd1..00000000000 Binary files a/Manuals/FDS_User_Guide/FIGURES/FDS_User_Guide_Cartesian_Particle_Drawing.pdf and /dev/null differ diff --git a/Manuals/FDS_User_Guide/FIGURES/FDS_User_Guide_Cylindrical_Particle_Drawing.pdf b/Manuals/FDS_User_Guide/FIGURES/FDS_User_Guide_Cylindrical_Particle_Drawing.pdf deleted file mode 100644 index 974970cb88f..00000000000 Binary files a/Manuals/FDS_User_Guide/FIGURES/FDS_User_Guide_Cylindrical_Particle_Drawing.pdf and /dev/null differ diff --git a/Manuals/FDS_User_Guide/FIGURES/FDS_User_Guide_Sphere_Particle_Drawing.pdf b/Manuals/FDS_User_Guide/FIGURES/FDS_User_Guide_Sphere_Particle_Drawing.pdf deleted file mode 100644 index 8172b688413..00000000000 Binary files a/Manuals/FDS_User_Guide/FIGURES/FDS_User_Guide_Sphere_Particle_Drawing.pdf and /dev/null differ diff --git a/Manuals/FDS_User_Guide/FIGURES/Fan_Curve.pdf b/Manuals/FDS_User_Guide/FIGURES/Fan_Curve.pdf deleted file mode 100644 index c53893a6e47..00000000000 Binary files a/Manuals/FDS_User_Guide/FIGURES/Fan_Curve.pdf and /dev/null differ diff --git a/Manuals/FDS_User_Guide/FIGURES/piece_wise_linear.pdf b/Manuals/FDS_User_Guide/FIGURES/piece_wise_linear.pdf deleted file mode 100644 index 3c6dbdb6a91..00000000000 Binary files a/Manuals/FDS_User_Guide/FIGURES/piece_wise_linear.pdf and /dev/null differ diff --git a/Manuals/FDS_User_Guide/FIGURES/polygonal.pdf b/Manuals/FDS_User_Guide/FIGURES/polygonal.pdf deleted file mode 100644 index c5603fef470..00000000000 Binary files a/Manuals/FDS_User_Guide/FIGURES/polygonal.pdf and /dev/null differ diff --git a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_0_phimax_22p5.pdf b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_0_phimax_22p5.pdf index 0b6d5117984..135db66b217 100644 Binary files a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_0_phimax_22p5.pdf and b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_0_phimax_22p5.pdf differ diff --git a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_0_phimax_45.pdf b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_0_phimax_45.pdf index 0239cd761a9..8ea6b148c3c 100644 Binary files a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_0_phimax_45.pdf and b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_0_phimax_45.pdf differ diff --git a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_10_phimax_22p5.pdf b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_10_phimax_22p5.pdf index 8381d06b93f..6f1359a700e 100644 Binary files a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_10_phimax_22p5.pdf and b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_10_phimax_22p5.pdf differ diff --git a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_10_phimax_45.pdf b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_10_phimax_45.pdf index 45a6b9d53d3..f2e5c99602d 100644 Binary files a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_10_phimax_45.pdf and b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_10_phimax_45.pdf differ diff --git a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_20_phimax_22p5.pdf b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_20_phimax_22p5.pdf index 3dcb688d302..054ea0a175c 100644 Binary files a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_20_phimax_22p5.pdf and b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_20_phimax_22p5.pdf differ diff --git a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_20_phimax_45.pdf b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_20_phimax_45.pdf index 72bb909b30b..224fa10cbd0 100644 Binary files a/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_20_phimax_45.pdf and b/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_20_phimax_45.pdf differ diff --git a/Manuals/FDS_Verification_Guide/FDS_Verification_Guide.tex b/Manuals/FDS_Verification_Guide/FDS_Verification_Guide.tex index 2d77418fb5c..e16775d9be6 100644 --- a/Manuals/FDS_Verification_Guide/FDS_Verification_Guide.tex +++ b/Manuals/FDS_Verification_Guide/FDS_Verification_Guide.tex @@ -1245,7 +1245,7 @@ \section{2-D Vortex Simulation (\texorpdfstring{\ct{vort2d}}{vort2d})} \textbf{Max Gould, NIST SURF student}\\ \textbf{Ragini Acharya, United Technologies Research Center}\\ -\noindent In this section we present another case that demonstrates the second-order accuracy of the FDS transport algorithm. We consider the analytically stable flow field consisting of a single vortex advected by a uniform flow, a test case developed by CERFACS\footnote{Centre Europ\'een de Recherche et de Formation Avanc\'ee en Calcul Scientifique} \cite{cerfacs_test}. Maintaining the geometry of the vortex over time provides a good measure of the order of accuracy of the transport scheme. +\noindent In this section another case is presented case that demonstrates the second-order accuracy of the FDS transport algorithm. Consider the analytically stable flow field consisting of a single vortex advected by a uniform flow, a test case developed by CERFACS\footnote{Centre Europ\'een de Recherche et de Formation Avanc\'ee en Calcul Scientifique} \cite{cerfacs_test}. Maintaining the geometry of the vortex over time provides a good measure of the order of accuracy of the transport scheme. \begin{figure}[h!] \centering @@ -1287,9 +1287,9 @@ \section{2-D Vortex Simulation (\texorpdfstring{\ct{vort2d}}{vort2d})} u (x,z) &\equiv& U_{0} + \frac{\partial}{\partial z} \Psi_{0} = U_{0} - \frac{\Gamma \ z}{R_{c}^{2}} \exp \left[ - \frac{x^{2} + z^{2}}{2 \ R_{c}^{2}} \right], \\ w (x,z) &\equiv& - \frac{\partial}{\partial x} \Psi_{0} = \frac{\Gamma \ x}{R_{c}^{2}} \exp \left[ - \frac{x^{2} + z^{2}}{2 \ R_{c}^{2}} \right], \end{eqnarray} -where $u$ and $w$ refer to velocity in the $x$ and $z$-directions, respectively. For our purposes we need only analyze one component of the velocity field. We will focus our attention on the $u$-component of velocity. +where $u$ and $w$ refer to velocity in the $x$ and $z$-directions, respectively. It is sufficient to analyze the $u$-component of velocity. -We define the computational domain as a two-dimensional square region, $L=0.3112$~m on a side, with periodic boundary conditions. The domain is discretized for a range of square, two-dimensional meshes of $40^{2}$, $80^{2}$, $160^{2}$, and $320^{2}$ grid cells. For the purposes of this test, we set the flow parameters as +The computational domain is a two-dimensional square region, $L=0.3112$~m on a side, with periodic boundary conditions. The domain is discretized for a range of square, two-dimensional meshes of $40^{2}$, $80^{2}$, $160^{2}$, and $320^{2}$ grid cells. The flow parameters are \[ \begin{array}{lll} U_{0} &&= 35 \ \mathrm{m/s} \\ @@ -1297,23 +1297,22 @@ \section{2-D Vortex Simulation (\texorpdfstring{\ct{vort2d}}{vort2d})} \Gamma &= 0.04 \ U_{0} \ R_{c} \ \sqrt{e} &= 0.0359157 \end{array} \] -The constant flow field and periodic boundary conditions cause the vortex to repeatedly pass through the computational domain. The ``pass-through'' time, $t_{f}$, is defined as the time period required for the stable vortex to return to its original position, +The constant flow field and periodic boundary conditions cause the vortex to repeatedly pass through the computational domain. The ``pass-through'' time, $t_{\rm f}$, is defined as the time period required for the stable vortex to return to its original position, \begin{equation*} -t_{f} = L / U_{0} \simeq 8.8914 \times 10^{-3} \ \mathrm{s}. +t_{\rm f} = L / U_{0} \simeq 8.8914 \times 10^{-3} \ \mathrm{s} \end{equation*} -To ensure that the numerical solution converges to the analytical solution, we set the time step, $\dt$, so that the Courant-Friedrichs-Lewy (CFL) number is 0.5. - +To ensure that the numerical solution converges to the analytical solution, the time step, $\dt$, is chosen so that the Courant-Friedrichs-Lewy (CFL) number is 0.5. \begin{figure}[h] \begin{tabular*}{\textwidth}{l@{\extracolsep{\fill}}r} \includegraphics[height=2.2in]{SCRIPT_FIGURES/vort2d_80_uzgraph} & \includegraphics[height=2.2in]{SCRIPT_FIGURES/vort2d_160_uzgraph} \end{tabular*} - \caption[Velocity in the \ct{vort2d} test case]{$u$-velocity along the $z$-axis at $x=0$ plotted for each of the vortex's first four loops through the computational domain. (Left) $80^{2}$ grid cell model. (Right) $160^{2}$ grid cell model.} + \caption[Velocity in the \ct{vort2d} test case]{$u$-velocity along the $z$-axis at $x=0$ plotted for each of the vortex's first three passes through the computational domain. (Left) $80^{2}$ grid cell model. (Right) $160^{2}$ grid cell model.} \label{fig_vort2d_axisvelocity} \end{figure} -A plot of $u$-velocity values just along the $z$-axis provides a simple characterization of the vortex geometry. The extent to which this geometry changes over time provides a qualitative measure of the accuracy of the transport algorithm. Figure \ref{fig_vort2d_axisvelocity} displays these plots for two different grid resolutions. Each line represents a plot taken for a different number of flow-through times such that the red lines represent the vortex after it has undergone the most passes through the computational domain while the green lines represent the vortex in the initial phase. The broken black line represents the analytical solution. As the vortex undergoes more passes through the computational domain, its velocity profile diverges further and further from the analytical profile. While divergence still occurs on the finer mesh, the extent to which it diverges after the same number of flow-through times is significantly smaller. +A plot of $u$-velocity along the $z$-axis provides a simple characterization of the vortex geometry. The extent to which this geometry changes over time provides a qualitative measure of the accuracy of the transport algorithm. Figure~\ref{fig_vort2d_axisvelocity} displays these plots for two different grid resolutions. Each curve represents the state of the vortex at each flow-through time. The black curve represents the analytical solution for which the numerical solution has been initialized. As the vortex undergoes more passes through the computational domain, its velocity profile diverges from the analytical profile. While divergence still occurs on the finer mesh, the extent to which it diverges after the same number of flow-through times is significantly smaller. \begin{figure}[h!] \centering @@ -1322,7 +1321,7 @@ \section{2-D Vortex Simulation (\texorpdfstring{\ct{vort2d}}{vort2d})} \label{fig_vort2d_error} \end{figure} -The rate with which the simulated profiles converge to the analytical one defines the order of accuracy of the numerical scheme. In Fig.~\ref{fig_vort2d_error} we plot the rms error of the numerical solution as a function of the grid resolution. The three colored curves represent the rms error at three different pass-through times. The broken and solid black lines represent the plot gradient corresponding to first and second order error respectively. While the error increases with each flow-through time, the gradients of the lines are roughly parallel to the solid black line, indicating second-order accuracy of the numerical scheme. +The rate with which the simulated profiles converge to the analytical one defines the order of accuracy of the numerical scheme. In Fig.~\ref{fig_vort2d_error} the error of the numerical solution is plotted as a function of the grid resolution. The three colored curves represent the error at three different pass-through times. The broken and solid black lines represent the plot gradient corresponding to first and second order error respectively. While the error increases with each flow-through time, the gradients of the lines are roughly parallel to the solid black line, indicating second-order accuracy of the numerical scheme. To analyze the stability of the vortex at times other than discrete multiples of the pass-through time, consider the time-dependent potential field and its corresponding $u$-velocity component: \begin{equation} @@ -1333,7 +1332,7 @@ \section{2-D Vortex Simulation (\texorpdfstring{\ct{vort2d}}{vort2d})} \label{eqn_uvel_timedep} u (x,z,t) = U_{0} - \Psi_{0} \ \frac{z}{R_{c}^{2}} \exp \left[\frac{2 \ U_{0} \ x \ t - U_{0}^{2} \ t^{2}}{2 \ R_{c}^{2}} \right]. \end{equation} -In Fig.~\ref{fig_vort2d_pointvelocity}, we show the $u$-velocity at a single point, on the lower left fringe of the vortex, for two different mesh resolutions, $80^{2}$ and $160^{2}$. A mesh resolution of $320^{2}$ grid cells produces a plot (not shown) that is, to the eye, a perfect match out to four pass-through times. +In Fig.~\ref{fig_vort2d_pointvelocity}, the $u$-velocity at a single point on the lower left fringe of the vortex is plotted for two different mesh resolutions, $80^{2}$ and $160^{2}$. A mesh resolution of $320^{2}$ grid cells produces a plot (not shown) that is, to the eye, a perfect match out to four pass-through times. \begin{figure}[h!] \begin{tabular*}{\textwidth}{l@{\extracolsep{\fill}}r} @@ -1491,7 +1490,7 @@ \subsection{Fire Plume using Constant Specific Heat Ratio (\texorpdfstring{\ct{f \subsection{Evaporation with Constant Specific Heat Ratio (\texorpdfstring{\ct{water_evap_1_const_gamma}}{water\_evap\_1\_const\_gamma})} \label{water_evap_1_const_gamma} -This test case is a replica of \ct{water_evaporation_1} in Sec.~\ref{water_evaporation_1} using constant specific heat ratio. A 1 \si{m^3} box is initially filled with dry air at 200 \si{\degreeCelsius} and mono-disperse water droplets totaling 0.01 kg in mass initially at 20 \si{\degreeCelsius}. In this case, all the water evaporates. The final gas temperature may be computed from energy conservation. Pressure change may be computed from the ideal gas law. Results are shown in Fig.~\ref{water_evap_1_const_gamma_plots}. Details of the expected results may be found in \ct{water_evap_1_const_gamma.m} in the \ct{Utilities/Matlab/scripts/} directory in the FDS repository \cite{FDS-SMV_repository}. +This test case is a replica of \ct{water_evaporation_1} in Sec.~\ref{water_evaporation_1} using constant specific heat ratio. A 1 \si{m^3} box is initially filled with dry air at 200 \si{\degreeCelsius} and mono-disperse water droplets totaling 0.01 kg in mass initially at 20 \si{\degreeCelsius}. In this case, all the water evaporates. The final gas temperature may be computed from energy conservation. Pressure change may be computed from the ideal gas law. Results are shown in Fig.~\ref{water_evap_1_const_gamma_plots}. Details of the expected results may be found in \ct{water_evap_1_const_gamma.py} in the \ct{Utilities/Python/scripts/} directory in the FDS repository \cite{FDS-SMV_repository}. \begin{figure}[ht!] \noindent @@ -7828,6 +7827,7 @@ \chapter{Outputs} \section{Statistical Quantities} \subsection{RMS, Co-Variance, and Cross-Correlation (\texorpdfstring{\ct{rms\_cov\_corr}}{rms\_cov\_corr})} +\label{rms_cov_corr} FDS can output the root mean square (RMS), co-variance, and cross-correlation for both point and line \ct{DEVC} outputs. To test these outputs a 1 m$^3$ box with open sides and a 10 cm grid size is defined with two inlet vents centered on adjacent faces. This results in two orthogonal flow streams that collide at the center of the box and exit diagonally. Within the diagonal portion of the flow, are placed point measurements for the FDS outputs of the u-velocity RMS, the u-velocity/w-velocity co-variance, and the u-velocity/w-velocity cross-correlation. diff --git a/Source/ccib.f90 b/Source/ccib.f90 index edf6d44a04a..561e3f1d59c 100644 --- a/Source/ccib.f90 +++ b/Source/ccib.f90 @@ -107,7 +107,7 @@ MODULE CC_SCALARS CC_CUTCELL_VELOCITY,CC_CUTFACE_VELOCITY,CC_RESTORE_UVW_UNLINKED,& CHECK_CFLVN_LINKED_CELLS,ADD_Q_DOT_CUTCELLS,CFACE_THERMAL_GASVARS,& CFACE_PREDICT_NORMAL_VELOCITY,COMPUTE_LINKED_CUTFACE_BAROCLINIC,& - COPY_CC_UNKH_TO_HS, COPY_CC_HS_TO_UNKH, COPY_UNST_DM_TO_CART, CUTFACE_VELOCITIES, & + COPY_CC_UNKH_TO_HS, COPY_CC_MUNKH_TO_UNKH, COPY_UNST_DM_TO_CART, CUTFACE_VELOCITIES, & GET_CFACE_OPEN_BC_COEF,GET_FN_DIVERGENCE_CUTCELL,GET_OPENBC_TANGENTIAL_CUTFACE_VEL,& GET_CUTCELL_DDDT,GET_H_CUTFACES,GET_H_MATRIX_CC,GET_H_GUARD_CUTCELL,GET_CRTCFCC_INT_STENCILS,GET_RCFACES_H, & GET_CC_MATRIXGRAPH_H,GET_CC_IROW,GET_CC_UNKH,GET_CUTCELL_HP, GET_LINKED_FV, GET_PRES_CFACE_BCS, & @@ -21750,16 +21750,14 @@ SUBROUTINE NUMBER_UNKH_CUTCELLS(FLAG12,NM,IPZ,NUNKH_LC) RETURN END SUBROUTINE NUMBER_UNKH_CUTCELLS -! ------------------- COPY_CC_HS_TO_UNKH ---------------------------- +! ------------------- COPY_CC_MUNKH_TO_UNKH ---------------------------- -SUBROUTINE COPY_CC_HS_TO_UNKH(NM) - -INTEGER, INTENT(IN) :: NM +SUBROUTINE COPY_CC_MUNKH_TO_UNKH ! Local Variables: -INTEGER :: NOM,ICC,II,JJ,KK,IOR,IW,IIO,JJO,KKO +INTEGER :: NOM,ICC,IW,IIO,JJO,KKO,II,JJ,KK TYPE (OMESH_TYPE), POINTER :: OM - +TYPE (BOUNDARY_COORD_TYPE), POINTER :: BC ! Loop over external wall cells: EXTERNAL_WALL_LOOP: DO IW=1,N_EXTERNAL_WALL_CELLS @@ -21767,11 +21765,6 @@ SUBROUTINE COPY_CC_HS_TO_UNKH(NM) EWC=>EXTERNAL_WALL(IW) IF (WC%BOUNDARY_TYPE/=INTERPOLATED_BOUNDARY) CYCLE EXTERNAL_WALL_LOOP - BC => BOUNDARY_COORD(WC%BC_INDEX) - II = BC%II - JJ = BC%JJ - KK = BC%KK - IOR = BC%IOR NOM = EWC%NOM OM => OMESH(NOM) @@ -21779,15 +21772,35 @@ SUBROUTINE COPY_CC_HS_TO_UNKH(NM) KKO=EWC%KKO_MIN JJO=EWC%JJO_MIN IIO=EWC%IIO_MIN - + BC => BOUNDARY_COORD(WC%BC_INDEX) + II = BC%II; JJ = BC%JJ; KK = BC%KK; ICC=CCVAR(II,JJ,KK,CC_IDCC) - IF (ICC > 0) THEN ! Cut-cells on this guard-cell Cartesian cell. - MESHES(NM)%CUT_CELL(ICC)%UNKH(1) = INT(OM%HS(IIO,JJO,KKO)) + CUT_CELL(ICC)%UNKH(1) = OM%MUNKH(IIO,JJO,KKO) ELSE - MESHES(NM)%CCVAR(II,JJ,KK,CC_UNKH) = INT(OM%HS(IIO,JJO,KKO)) + CCVAR(II,JJ,KK,CC_UNKH) = OM%MUNKH(IIO,JJO,KKO) ENDIF + ! ! Loop over all cells in mesh NOM that correspond to this boundary face (supports grid refinement): + ! DO KKO = EWC%KKO_MIN, EWC%KKO_MAX + ! DO JJO = EWC%JJO_MIN, EWC%JJO_MAX + ! DO IIO = EWC%IIO_MIN, EWC%IIO_MAX + + ! ! Check if this cell in mesh NOM is a cut-cell: + ! ICC = MESHES(NOM)%CCVAR(IIO,JJO,KKO,CC_IDCC) + + ! IF (ICC > 0) THEN + ! ! Copy to cut-cell storage in mesh NOM: + ! MESHES(NOM)%CUT_CELL(ICC)%UNKH(1) = OM%MUNKH(IIO,JJO,KKO) + ! ELSE + ! ! Copy to regular cell storage in mesh NOM: + ! MESHES(NOM)%CCVAR(IIO,JJO,KKO,CC_UNKH) = OM%MUNKH(IIO,JJO,KKO) + ! ENDIF + + ! ENDDO + ! ENDDO + ! ENDDO + ENDDO EXTERNAL_WALL_LOOP ! Loop over external wall cells: @@ -21801,7 +21814,7 @@ SUBROUTINE COPY_CC_HS_TO_UNKH(NM) ENDDO EXTERNAL_WALL_LOOP2 RETURN -END SUBROUTINE COPY_CC_HS_TO_UNKH +END SUBROUTINE COPY_CC_MUNKH_TO_UNKH ! ------------------- COPY_CC_UNKH_TO_HS ---------------------------- diff --git a/Source/main.f90 b/Source/main.f90 index efce8a0b701..0230165604f 100644 --- a/Source/main.f90 +++ b/Source/main.f90 @@ -1743,15 +1743,19 @@ SUBROUTINE GLOBAL_MATRIX_REASSIGN(FORCE_REASSIGN) CALL ULMAT_SOLVER_SETUP(NM) ENDDO CALL STOP_CHECK(1) - CASE (UGLMAT_FLAG,GLMAT_FLAG) - IF(ALLOCATED(ZONE_SOLVE)) CALL FINISH_GLMAT_SOLVER - CALL GLMAT_SOLVER_SETUP(1) - CALL STOP_CHECK(1) - CALL MESH_EXCHANGE(3) ! Exchange guard cell info for CCVAR(I,J,K,CGSC) -> HS. - CALL GLMAT_SOLVER_SETUP(2) - CALL MESH_EXCHANGE(3) ! Exchange guard cell info for CCVAR(I,J,K,UNKH) -> HS. - CALL GLMAT_SOLVER_SETUP(3) - CALL STOP_CHECK(1) + CASE (UGLMAT_FLAG,GLMAT_FLAG) + IF(ALLOCATED(ZONE_SOLVE)) CALL FINISH_GLMAT_SOLVER + CALL GLMAT_SOLVER_SETUP(-1) ! Initialize EWC_TYPE, copy wall types to HS + CALL STOP_CHECK(1) + CALL MESH_EXCHANGE(3) ! Exchange guard cell info for IS_WALLT -> HS + CALL GLMAT_SOLVER_SETUP(0) ! Process coarse faces, copy updated wall types to HS + CALL MESH_EXCHANGE(3) ! Re-exchange guard cell info for IS_WALLT -> HS + CALL GLMAT_SOLVER_SETUP(1) + CALL MESH_EXCHANGE(3) ! Exchange guard cell info for CCVAR(I,J,K,CGSC) -> HS + CALL GLMAT_SOLVER_SETUP(2) + CALL MESH_EXCHANGE(3) ! Exchange guard cell info for CCVAR(I,J,K,UNKH) -> HS + CALL GLMAT_SOLVER_SETUP(3) + CALL STOP_CHECK(1) END SELECT OBST_CREATED_OR_REMOVED = .FALSE. ENDIF diff --git a/Source/pres.f90 b/Source/pres.f90 index 2a9a545535f..b3e7f47b91c 100644 --- a/Source/pres.f90 +++ b/Source/pres.f90 @@ -3074,7 +3074,7 @@ MODULE GLOBMAT_SOLVER USE COMPLEX_GEOMETRY, ONLY : CALL_FOR_GLMAT, CC_CGSC,CC_FGSC, CC_UNKH, CC_NCVARS, & NM_START,IPARM,NNZ_ROW_H,CALL_FROM_GLMAT_SETUP USE CC_SCALARS, ONLY : GET_H_CUTFACES, GET_BOUNDFACE_GEOM_INFO_H, ADD_INPLACE_NNZ_H_WHLDOM, & - COPY_CC_HS_TO_UNKH, COPY_CC_UNKH_TO_HS + COPY_CC_MUNKH_TO_UNKH, COPY_CC_UNKH_TO_HS #ifdef WITH_MKL USE MKL_CLUSTER_SPARSE_SOLVER @@ -3095,6 +3095,7 @@ MODULE GLOBMAT_SOLVER INTEGER, PARAMETER :: IS_CGSC = 1 ! Face media type: IS_GASPHASE, IS_SOLID or IS_CUTCFE. INTEGER, PARAMETER :: IS_UNKH = 2 ! H unknown number. INTEGER, PARAMETER :: IS_NCVARS = 2 ! Number of face variables in MESHES(NM)%CCVAR. +INTEGER, PARAMETER :: IS_WALLT = 100 ! Wall cell type. INTEGER, SAVE :: ILO_CELL,IHI_CELL,JLO_CELL,JHI_CELL,KLO_CELL,KHI_CELL INTEGER, SAVE :: ILO_FACE,IHI_FACE,JLO_FACE,JHI_FACE,KLO_FACE,KHI_FACE @@ -3140,6 +3141,24 @@ MODULE GLOBMAT_SOLVER CONTAINS +! --------------------------- COMPUTE_GUARD_CELL_INDEXES ----------------------- + +PURE SUBROUTINE COMPUTE_GUARD_CELL_INDEXES(IOR_IN, IIO, JJO, KKO, II_NOM, JJ_NOM, KK_NOM) +! Compute the guard cell location in the neighboring mesh based on orientation +INTEGER, INTENT(IN) :: IOR_IN, IIO, JJO, KKO +INTEGER, INTENT(OUT) :: II_NOM, JJ_NOM, KK_NOM + +SELECT CASE(IOR_IN) +CASE( IAXIS); II_NOM = IIO + 1; JJ_NOM = JJO; KK_NOM = KKO +CASE(-IAXIS); II_NOM = IIO - 1; JJ_NOM = JJO; KK_NOM = KKO +CASE( JAXIS); II_NOM = IIO; JJ_NOM = JJO + 1; KK_NOM = KKO +CASE(-JAXIS); II_NOM = IIO; JJ_NOM = JJO - 1; KK_NOM = KKO +CASE( KAXIS); II_NOM = IIO; JJ_NOM = JJO; KK_NOM = KKO + 1 +CASE(-KAXIS); II_NOM = IIO; JJ_NOM = JJO; KK_NOM = KKO - 1 +END SELECT + +END SUBROUTINE COMPUTE_GUARD_CELL_INDEXES + ! --------------------------- GLMAT_SOLVER ------------------------------------- SUBROUTINE GLMAT_SOLVER(T,DT) @@ -3492,6 +3511,11 @@ SUBROUTINE GLMAT_SOLVER_SETUP(STAGE_FLAG) ! Local Variables: LOGICAL :: SUPPORTED_MESH=.TRUE. +LOGICAL :: FINE_INTERPOLATED_FLG, FINE_SOLID_FLG +INTEGER :: NM,IW,IIO,JJO,KKO,II_NOM,JJ_NOM,KK_NOM +TYPE(WALL_TYPE), POINTER :: WC +TYPE(BOUNDARY_COORD_TYPE), POINTER :: BC +TYPE(EXTERNAL_WALL_TYPE), POINTER :: EWC IF (FREEZE_VELOCITY) RETURN ! Fixed velocity soln. i.e. PERIODIC_TEST=102 => FREEZE_VELOCITY=.TRUE. IF (SOLID_PHASE_ONLY) RETURN @@ -3512,20 +3536,105 @@ SUBROUTINE GLMAT_SOLVER_SETUP(STAGE_FLAG) IF(PRES_ON_WHOLE_DOMAIN) N_ZONE_GLOBMAT = 0 SELECT CASE(STAGE_FLAG) -CASE(1) +CASE(-1) ! Initialization of EWC_TYPE array: + + CALL_FROM_GLMAT_SETUP = .TRUE. + + ! Factor to drop DY(J) in cylindrical coordinates. Soln assumes DTheta=1. + CYL_FCT = 0._EB; IF (CYLINDRICAL) CYL_FCT = 1._EB + + ! Check for unsupported mesh configurations: + CALL CHECK_UNSUPPORTED_MESH(SUPPORTED_MESH) + IF (.NOT.SUPPORTED_MESH) RETURN - CALL_FROM_GLMAT_SETUP = .TRUE. + ITERATE_PRESSURE = .TRUE. ! Although there is no need to do pressure iterations to drive down velocity error + ! on wall cells (i.e. the solution should give the right unique dH/dxn), leave it + ! .TRUE. to write out velocity error diagnostics. - ! Factor to drop DY(J) in cylindrical coordinates. Soln assumes DTheta=1. - CYL_FCT = 0._EB; IF (CYLINDRICAL) CYL_FCT = 1._EB + ! Copy external wall cells types to HS: + CALL COPY_CCVAR_IN_HS(IS_WALLT) - ! Check for unsupported mesh configurations: - CALL CHECK_UNSUPPORTED_MESH(SUPPORTED_MESH) - IF (.NOT.SUPPORTED_MESH) RETURN +CASE(0) + ! Copy external wall cells types from HS to OMESH%EWC_TYPE: + CALL COPY_HS_IN_CCVAR(IS_WALLT) - ITERATE_PRESSURE = .TRUE. ! Although there is no need to do pressure iterations to drive down velocity error - ! on wall cells (i.e. the solution should give the right unique dH/dxn), leave it - ! .TRUE. to write out velocity error diagnostics. + ! Here the INTERPOLATED coarse side faces note if at least one fine face is INTERPOLATED and one SOLID, set to SOLID. + MESH_LOOP_1: DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX + CALL POINT_TO_MESH(NM) + DO IW=1,N_EXTERNAL_WALL_CELLS + WC => WALL(IW) + BC => BOUNDARY_COORD(WC%BC_INDEX) + EWC => EXTERNAL_WALL(IW) + IF(WC%BOUNDARY_TYPE==INTERPOLATED_BOUNDARY .AND. EWC%NOM > 0 .AND. EWC%AREA_RATIO>0.9_EB) THEN + IF(ALLOCATED(OMESH(EWC%NOM)%EWC_TYPE)) THEN + ! Only coarse mesh side checked for one INTERPOLATED fine side face and one SOLID fine side face + FINE_INTERPOLATED_FLG = .FALSE. + FINE_SOLID_FLG = .FALSE. + DO KKO = EWC%KKO_MIN, EWC%KKO_MAX + DO JJO = EWC%JJO_MIN, EWC%JJO_MAX + DO IIO = EWC%IIO_MIN, EWC%IIO_MAX + ! Compute guard cell location in neighboring mesh + CALL COMPUTE_GUARD_CELL_INDEXES(BC%IOR, IIO, JJO, KKO, II_NOM, JJ_NOM, KK_NOM) + IF(OMESH(EWC%NOM)%EWC_TYPE(II_NOM,JJ_NOM,KK_NOM) == INTERPOLATED_BOUNDARY) THEN + FINE_INTERPOLATED_FLG = .TRUE. + ELSE + FINE_SOLID_FLG = .TRUE. + ENDIF + ENDDO + ENDDO + ENDDO + IF(FINE_INTERPOLATED_FLG .AND. FINE_SOLID_FLG) WC%BOUNDARY_TYPE = SOLID_BOUNDARY + ENDIF + ENDIF + ENDDO + ENDDO MESH_LOOP_1 + + ! Copy external wall cells types to HS: + CALL COPY_CCVAR_IN_HS(IS_WALLT) + +CASE(1) + + ! Copy external wall cells types from HS to OMESH%EWC_TYPE: + CALL COPY_HS_IN_CCVAR(IS_WALLT) + + ! Here for INTERPOLATED fine side faces note if coarse side face is SOLID, if so set their type to SOLID + MESH_LOOP_2: DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX + CALL POINT_TO_MESH(NM) + DO IW=1,N_EXTERNAL_WALL_CELLS + WC => WALL(IW) + BC => BOUNDARY_COORD(WC%BC_INDEX) + EWC => EXTERNAL_WALL(IW) + IF(WC%BOUNDARY_TYPE==SOLID_BOUNDARY .AND. EWC%NOM > 0) THEN + IF(ALLOCATED(OMESH(EWC%NOM)%EWC_TYPE) .AND. EWC%AREA_RATIO>0.9_EB) THEN + ! SOLID coarse face looks for INTERPOLATED fine side faces, if found sets EWC_TYPE to SOLID. + DO KKO = EWC%KKO_MIN, EWC%KKO_MAX + DO JJO = EWC%JJO_MIN, EWC%JJO_MAX + DO IIO = EWC%IIO_MIN, EWC%IIO_MAX + ! Compute guard cell location in neighboring mesh + CALL COMPUTE_GUARD_CELL_INDEXES(BC%IOR, IIO, JJO, KKO, II_NOM, JJ_NOM, KK_NOM) + IF(OMESH(EWC%NOM)%EWC_TYPE(II_NOM,JJ_NOM,KK_NOM) == INTERPOLATED_BOUNDARY) & + OMESH(EWC%NOM)%EWC_TYPE(II_NOM,JJ_NOM,KK_NOM) = SOLID_BOUNDARY + ENDDO + ENDDO + ENDDO + ENDIF + ELSEIF(WC%BOUNDARY_TYPE==INTERPOLATED_BOUNDARY) THEN + IF(ALLOCATED(OMESH(EWC%NOM)%EWC_TYPE) .AND. EWC%AREA_RATIO<0.9_EB) THEN + ! Only fine mesh side checked for SOLID_BOUNDARY coarse side faces. + DO KKO = EWC%KKO_MIN, EWC%KKO_MAX + DO JJO = EWC%JJO_MIN, EWC%JJO_MAX + DO IIO = EWC%IIO_MIN, EWC%IIO_MAX + ! Compute guard cell location in neighboring mesh + CALL COMPUTE_GUARD_CELL_INDEXES(BC%IOR, IIO, JJO, KKO, II_NOM, JJ_NOM, KK_NOM) + IF(OMESH(EWC%NOM)%EWC_TYPE(II_NOM,JJ_NOM,KK_NOM) == SOLID_BOUNDARY) & + WC%BOUNDARY_TYPE = SOLID_BOUNDARY + ENDDO + ENDDO + ENDDO + ENDIF + ENDIF + ENDDO + ENDDO MESH_LOOP_2 ! Test for CC_IBM, define CGSC and UNKH locations in CCVAR: IF (CC_IBM) THEN @@ -3608,7 +3717,6 @@ SUBROUTINE CHECK_UNSUPPORTED_MESH(SUPPORTED_MESH) #endif USE MESH_POINTERS USE GLOBAL_CONSTANTS, ONLY : N_MPI_PROCESSES -USE TRAN, ONLY : TRANS LOGICAL, INTENT(OUT) :: SUPPORTED_MESH @@ -3625,64 +3733,50 @@ SUBROUTINE CHECK_UNSUPPORTED_MESH(SUPPORTED_MESH) SUPPORTED_MESH = .TRUE. -! 1. Stretched grids which is untested: -GLMAT_IF_1 : IF(PRES_FLAG==GLMAT_FLAG) THEN -TRN_ME(1:2) = 0 -MESH_LOOP_TRN : DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX - TRN_ME(1) = TRN_ME(1) + TRANS(NM)%NOCMAX -ENDDO MESH_LOOP_TRN -TRN_ME(2)=TRN_ME(1) -IF (N_MPI_PROCESSES > 1) CALL MPI_ALLREDUCE(TRN_ME(1),TRN_ME(2),1,MPI_INTEGER,MPI_SUM,MPI_COMM_WORLD,IERR) -IF (TRN_ME(2) > 0) THEN ! There is a TRNX, TRNY or TRNZ line defined for stretched grids. Not Unsupported. - IF (MY_RANK == 0) WRITE(LU_ERR,*) 'GLMAT Setup Error : Stretched grids currently unsupported.' - SUPPORTED_MESH = .FALSE. - STOP_STATUS = SETUP_STOP - RETURN -ENDIF -ENDIF GLMAT_IF_1 - IF (NMESHES == 1) RETURN -! 2. Two different cell sizes in mesh (i.e. different refinement levels): -NM = 1 -IF (MY_RANK==PROCESS(NM)) THEN - CALL POINT_TO_MESH(NM) - DX_P(IAXIS) = DX(1) - DX_P(JAXIS) = DY(1) - DX_P(KAXIS) = DZ(1) -ENDIF -IF (N_MPI_PROCESSES > 1) CALL MPI_BCAST(DX_P(1),3,MPI_DOUBLE_PRECISION,PROCESS(NM),MPI_COMM_WORLD,IERR) -! Find domain sizes to define relative epsilon: -MIN_XS(1:3) = (/ MESHES(NM)%XS, MESHES(NM)%YS, MESHES(NM)%ZS /) -MAX_XF(1:3) = (/ MESHES(NM)%XF, MESHES(NM)%YF, MESHES(NM)%ZF /) -DO NM=2,NMESHES - MIN_XS(1) = MIN(MIN_XS(1),MESHES(NM)%XS) - MIN_XS(2) = MIN(MIN_XS(2),MESHES(NM)%YS) - MIN_XS(3) = MIN(MIN_XS(3),MESHES(NM)%ZS) - MAX_XF(1) = MAX(MAX_XF(1),MESHES(NM)%XF) - MAX_XF(2) = MAX(MAX_XF(2),MESHES(NM)%YF) - MAX_XF(3) = MAX(MAX_XF(3),MESHES(NM)%ZF) -ENDDO -LX = MAX(MAX_XF(1)-MIN_XS(1),1._EB) -LY = MAX(MAX_XF(2)-MIN_XS(2),1._EB) -LZ = MAX(MAX_XF(3)-MIN_XS(3),1._EB) -TRN_ME(1:2) = 0 -MESH_LOOP_CELL : DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX - CALL POINT_TO_MESH(NM) - IF(ABS(DX_P(IAXIS)-DX(1)) > 10._EB*TWO_EPSILON_EB*LX) TRN_ME(1) = TRN_ME(1) + 1 - IF(ABS(DX_P(JAXIS)-DY(1)) > 10._EB*TWO_EPSILON_EB*LY) TRN_ME(1) = TRN_ME(1) + 1 - IF(ABS(DX_P(KAXIS)-DZ(1)) > 10._EB*TWO_EPSILON_EB*LZ) TRN_ME(1) = TRN_ME(1) + 1 -ENDDO MESH_LOOP_CELL -TRN_ME(2)=TRN_ME(1) -IF (N_MPI_PROCESSES > 1) CALL MPI_ALLREDUCE(TRN_ME(1),TRN_ME(2),1,MPI_INTEGER,MPI_SUM,MPI_COMM_WORLD,IERR) -IF (TRN_ME(2) > 0) THEN ! Meshes at different refinement levels. Not Unsupported. - IF (MY_RANK == 0) WRITE(LU_ERR,*) 'GLMAT Setup Error : Meshes at different refinement levels unsupported.' - SUPPORTED_MESH = .FALSE. - STOP_STATUS = SETUP_STOP - RETURN +! 1. For now unsupported: CC_IBM and two different cell sizes in mesh (i.e. different refinement levels): +IF(CC_IBM) THEN + NM = 1 + IF (MY_RANK==PROCESS(NM)) THEN + CALL POINT_TO_MESH(NM) + DX_P(IAXIS) = DX(1) + DX_P(JAXIS) = DY(1) + DX_P(KAXIS) = DZ(1) + ENDIF + IF (N_MPI_PROCESSES > 1) CALL MPI_BCAST(DX_P(1),3,MPI_DOUBLE_PRECISION,PROCESS(NM),MPI_COMM_WORLD,IERR) + ! Find domain sizes to define relative epsilon: + MIN_XS(1:3) = (/ MESHES(NM)%XS, MESHES(NM)%YS, MESHES(NM)%ZS /) + MAX_XF(1:3) = (/ MESHES(NM)%XF, MESHES(NM)%YF, MESHES(NM)%ZF /) + DO NM=2,NMESHES + MIN_XS(1) = MIN(MIN_XS(1),MESHES(NM)%XS) + MIN_XS(2) = MIN(MIN_XS(2),MESHES(NM)%YS) + MIN_XS(3) = MIN(MIN_XS(3),MESHES(NM)%ZS) + MAX_XF(1) = MAX(MAX_XF(1),MESHES(NM)%XF) + MAX_XF(2) = MAX(MAX_XF(2),MESHES(NM)%YF) + MAX_XF(3) = MAX(MAX_XF(3),MESHES(NM)%ZF) + ENDDO + LX = MAX(MAX_XF(1)-MIN_XS(1),1._EB) + LY = MAX(MAX_XF(2)-MIN_XS(2),1._EB) + LZ = MAX(MAX_XF(3)-MIN_XS(3),1._EB) + TRN_ME(1:2) = 0 + MESH_LOOP_CELL : DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX + CALL POINT_TO_MESH(NM) + IF(ABS(DX_P(IAXIS)-DX(1)) > 10._EB*TWO_EPSILON_EB*LX) TRN_ME(1) = TRN_ME(1) + 1 + IF(ABS(DX_P(JAXIS)-DY(1)) > 10._EB*TWO_EPSILON_EB*LY) TRN_ME(1) = TRN_ME(1) + 1 + IF(ABS(DX_P(KAXIS)-DZ(1)) > 10._EB*TWO_EPSILON_EB*LZ) TRN_ME(1) = TRN_ME(1) + 1 + ENDDO MESH_LOOP_CELL + TRN_ME(2)=TRN_ME(1) + IF (N_MPI_PROCESSES > 1) CALL MPI_ALLREDUCE(TRN_ME(1),TRN_ME(2),1,MPI_INTEGER,MPI_SUM,MPI_COMM_WORLD,IERR) + IF (TRN_ME(2) > 0) THEN ! Meshes at different refinement levels. Not Unsupported. + IF (MY_RANK == 0) WRITE(LU_ERR,*) 'GLMAT Setup Error : Meshes at different refinement levels unsupported.' + SUPPORTED_MESH = .FALSE. + STOP_STATUS = SETUP_STOP + RETURN + ENDIF ENDIF -! 3. Two (or more) disjoint domains, where at least one has all Neumann BCs and one has some Dirichlet bcs. +! 2. Two (or more) disjoint domains, where at least one has all Neumann BCs and one has some Dirichlet bcs. ! This is a topological problem that would require different Matrix types (i.e. one positive definite and one ! indefinite), which would require separate solutions. ! A possible approach to look at is to solve the whole system as indefinite, and then substract a constant in @@ -3808,12 +3902,13 @@ SUBROUTINE COPY_H_OMESH_TO_MESH USE COMP_FUNCTIONS, ONLY: CURRENT_TIME USE CC_SCALARS, ONLY: GET_H_GUARD_CUTCELL ! Local Variables: -INTEGER :: NM,NOM,II,JJ,KK,IOR,IW,IIO,JJO,KKO +INTEGER :: NM,NOM,II,JJ,KK,IOR,IW,IIO,JJO,KKO,IIG,JJG,KKG,II_NOM,JJ_NOM,KK_NOM TYPE (OMESH_TYPE), POINTER :: OM TYPE (WALL_TYPE), POINTER :: WC TYPE (BOUNDARY_COORD_TYPE), POINTER :: BC TYPE (EXTERNAL_WALL_TYPE), POINTER :: EWC LOGICAL :: FLG +REAL(EB) :: H_EXTERNAL_MEAN, DX_INT, DX_EXT, WEIGHT_INT, WEIGHT_EXT, NCELLS_EXT, H_FACE IF (CC_IBM) CALL_FOR_GLMAT = .FALSE. @@ -3845,34 +3940,65 @@ SUBROUTINE COPY_H_OMESH_TO_MESH IF (WC%BOUNDARY_TYPE/=INTERPOLATED_BOUNDARY) CYCLE EXTERNAL_WALL_LOOP_1 ENDIF - II = BC%II - JJ = BC%JJ - KK = BC%KK - IOR = BC%IOR - NOM = EWC%NOM + II = BC%II; JJ = BC%JJ; KK = BC%KK + IIG = BC%IIG; JJG = BC%JJG; KKG = BC%KKG + IOR = BC%IOR; NOM = EWC%NOM; IF(NOM < 1) CYCLE + ! Here if NOM==0 means it is an OBST laying on an external boundary -> CYCLE - IF(NOM < 1) CYCLE OM => OMESH(NOM) - ! This assumes all meshes at the same level of refinement: - KKO=EWC%KKO_MIN - JJO=EWC%JJO_MIN - IIO=EWC%IIO_MIN + IF (CC_IBM) THEN + ! This assumes all meshes at the same level of refinement: For now. + KKO=EWC%KKO_MIN + JJO=EWC%JJO_MIN + IIO=EWC%IIO_MIN + H(II,JJ,KK) = OM%H(IIO,JJO,KKO) + CYCLE EXTERNAL_WALL_LOOP_1 + ENDIF + ! GRID REFINEMENT: Compute mean H accounting for boundary types + H_EXTERNAL_MEAN = 0._EB + NCELLS_EXT = 0._EB + DO KKO = EWC%KKO_MIN, EWC%KKO_MAX + DO JJO = EWC%JJO_MIN, EWC%JJO_MAX + DO IIO = EWC%IIO_MIN, EWC%IIO_MAX + IF(.NOT.PRES_ON_WHOLE_DOMAIN .AND. OM%MUNKH(IIO,JJO,KKO) <= 0) CYCLE + + ! Compute guard cell location in neighboring mesh based on IOR + CALL COMPUTE_GUARD_CELL_INDEXES(IOR, IIO, JJO, KKO, II_NOM, JJ_NOM, KK_NOM) + + ! Check boundary type and use appropriate value + IF (OM%EWC_TYPE(II_NOM,JJ_NOM,KK_NOM) == INTERPOLATED_BOUNDARY) THEN + ! Use actual external cell value (gradient continuity) + H_EXTERNAL_MEAN = H_EXTERNAL_MEAN + OM%H(IIO,JJO,KKO) + ELSE + ! Use internal cell value (zero gradient assumption) + H_EXTERNAL_MEAN = H_EXTERNAL_MEAN + H(IIG,JJG,KKG) + ENDIF + NCELLS_EXT = NCELLS_EXT + 1._EB + ENDDO + ENDDO + ENDDO + H_EXTERNAL_MEAN = H_EXTERNAL_MEAN / NCELLS_EXT + + ! Get cell sizes for distance-weighted interpolation SELECT CASE(IOR) - CASE( IAXIS) - H(II,JJ,KK) = OM%H(IIO,JJO,KKO) - CASE(-IAXIS) - H(II,JJ,KK) = OM%H(IIO,JJO,KKO) - CASE( JAXIS) - H(II,JJ,KK) = OM%H(IIO,JJO,KKO) - CASE(-JAXIS) - H(II,JJ,KK) = OM%H(IIO,JJO,KKO) - CASE( KAXIS) - H(II,JJ,KK) = OM%H(IIO,JJO,KKO) - CASE(-KAXIS) - H(II,JJ,KK) = OM%H(IIO,JJO,KKO) + CASE( IAXIS,-IAXIS) + DX_INT = DX(IIG) + DX_EXT = MESHES(NOM)%DX(EWC%IIO_MIN) + CASE( JAXIS,-JAXIS) + DX_INT = DY(JJG) + DX_EXT = MESHES(NOM)%DY(EWC%JJO_MIN) + CASE( KAXIS,-KAXIS) + DX_INT = DZ(KKG) + DX_EXT = MESHES(NOM)%DZ(EWC%KKO_MIN) END SELECT + + ! Distance-weighted interpolation at face, then extrapolation to guard cell center + WEIGHT_EXT = DX_INT / (DX_INT + DX_EXT) + WEIGHT_INT = DX_EXT / (DX_INT + DX_EXT) + H_FACE = WEIGHT_INT * H(IIG,JJG,KKG) + WEIGHT_EXT * H_EXTERNAL_MEAN + H(II,JJ,KK) = H(IIG,JJG,KKG) + 2.0_EB * (H_FACE - H(IIG,JJG,KKG)) ENDDO EXTERNAL_WALL_LOOP_1 @@ -3904,34 +4030,64 @@ SUBROUTINE COPY_H_OMESH_TO_MESH IF (WC%BOUNDARY_TYPE/=INTERPOLATED_BOUNDARY) CYCLE EXTERNAL_WALL_LOOP_2 ENDIF - II = BC%II - JJ = BC%JJ - KK = BC%KK - IOR = BC%IOR - NOM = EWC%NOM + II = BC%II; JJ = BC%JJ; KK = BC%KK + IIG = BC%IIG; JJG = BC%JJG; KKG = BC%KKG + IOR = BC%IOR; NOM = EWC%NOM; IF(NOM < 1) CYCLE ! Here if NOM==0 means it is an OBST laying on an external boundary -> CYCLE - IF(NOM < 1) CYCLE OM => OMESH(NOM) - ! This assumes all meshes at the same level of refinement: - KKO=EWC%KKO_MIN - JJO=EWC%JJO_MIN - IIO=EWC%IIO_MIN + IF (CC_IBM) THEN + ! This assumes all meshes at the same level of refinement: For now. + KKO=EWC%KKO_MIN + JJO=EWC%JJO_MIN + IIO=EWC%IIO_MIN + HS(II,JJ,KK) = OM%HS(IIO,JJO,KKO) + CYCLE EXTERNAL_WALL_LOOP_2 + ENDIF + ! GRID REFINEMENT: Compute mean HS accounting for boundary types + H_EXTERNAL_MEAN = 0._EB + NCELLS_EXT = 0._EB + DO KKO = EWC%KKO_MIN, EWC%KKO_MAX + DO JJO = EWC%JJO_MIN, EWC%JJO_MAX + DO IIO = EWC%IIO_MIN, EWC%IIO_MAX + IF(.NOT.PRES_ON_WHOLE_DOMAIN .AND. OM%MUNKH(IIO,JJO,KKO) <= 0) CYCLE + + ! Compute guard cell location in neighboring mesh based on IOR + CALL COMPUTE_GUARD_CELL_INDEXES(IOR, IIO, JJO, KKO, II_NOM, JJ_NOM, KK_NOM) + + ! Check boundary type and use appropriate value + IF (OM%EWC_TYPE(II_NOM,JJ_NOM,KK_NOM) == INTERPOLATED_BOUNDARY) THEN + ! Use actual external cell value (gradient continuity) + H_EXTERNAL_MEAN = H_EXTERNAL_MEAN + OM%HS(IIO,JJO,KKO) + ELSE + ! Use internal cell value (zero gradient assumption) + H_EXTERNAL_MEAN = H_EXTERNAL_MEAN + HS(IIG,JJG,KKG) + ENDIF + NCELLS_EXT = NCELLS_EXT + 1._EB + ENDDO + ENDDO + ENDDO + H_EXTERNAL_MEAN = H_EXTERNAL_MEAN / NCELLS_EXT + + ! Get cell sizes for distance-weighted interpolation SELECT CASE(IOR) - CASE( IAXIS) - HS(II,JJ,KK) = OM%HS(IIO,JJO,KKO) - CASE(-IAXIS) - HS(II,JJ,KK) = OM%HS(IIO,JJO,KKO) - CASE( JAXIS) - HS(II,JJ,KK) = OM%HS(IIO,JJO,KKO) - CASE(-JAXIS) - HS(II,JJ,KK) = OM%HS(IIO,JJO,KKO) - CASE( KAXIS) - HS(II,JJ,KK) = OM%HS(IIO,JJO,KKO) - CASE(-KAXIS) - HS(II,JJ,KK) = OM%HS(IIO,JJO,KKO) + CASE( IAXIS,-IAXIS) + DX_INT = DX(IIG) + DX_EXT = MESHES(NOM)%DX(EWC%IIO_MIN) + CASE( JAXIS,-JAXIS) + DX_INT = DY(JJG) + DX_EXT = MESHES(NOM)%DY(EWC%JJO_MIN) + CASE( KAXIS,-KAXIS) + DX_INT = DZ(KKG) + DX_EXT = MESHES(NOM)%DZ(EWC%KKO_MIN) END SELECT + + ! Distance-weighted interpolation at face, then extrapolation to guard cell center + WEIGHT_EXT = DX_INT / (DX_INT + DX_EXT) + WEIGHT_INT = DX_EXT / (DX_INT + DX_EXT) + H_FACE = WEIGHT_INT * HS(IIG,JJG,KKG) + WEIGHT_EXT * H_EXTERNAL_MEAN + HS(II,JJ,KK) = HS(IIG,JJG,KKG) + 2.0_EB * (H_FACE - HS(IIG,JJG,KKG)) ENDDO EXTERNAL_WALL_LOOP_2 @@ -3953,70 +4109,129 @@ SUBROUTINE COPY_HS_IN_CCVAR(VAR_CC) INTEGER, INTENT(IN) :: VAR_CC ! Local Variables: -INTEGER :: NM,NOM,II,JJ,KK,IOR,IW,IIO,JJO,KKO -TYPE (OMESH_TYPE), POINTER :: OM -TYPE (WALL_TYPE), POINTER :: WC -TYPE (BOUNDARY_COORD_TYPE), POINTER :: BC -TYPE (EXTERNAL_WALL_TYPE), POINTER :: EWC -LOGICAL :: FLG - -MESH_LOOP : DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX +INTEGER :: NM,NOM +LOGICAL, PARAMETER :: WRITE_EWC_TYPE = .FALSE. +! GRID REFINEMENT: Allocate OMESH arrays for GSCH, MUNKH, and EWC_TYPE if needed +DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX CALL POINT_TO_MESH(NM) + DO NOM=1,NMESHES + IF (.NOT.ALLOCATED(OMESH(NOM)%HS)) CYCLE + + ! Allocate GSCH if not already allocated (same bounds as HS): + IF (VAR_CC==CGSC .AND. .NOT.ALLOCATED(OMESH(NOM)%GSCH)) THEN + ALLOCATE(OMESH(NOM)%GSCH(LBOUND(OMESH(NOM)%HS,1):UBOUND(OMESH(NOM)%HS,1), & + LBOUND(OMESH(NOM)%HS,2):UBOUND(OMESH(NOM)%HS,2), & + LBOUND(OMESH(NOM)%HS,3):UBOUND(OMESH(NOM)%HS,3))) + ENDIF + + ! Allocate MUNKH if not already allocated (same bounds as HS): + IF (VAR_CC==UNKH .AND. .NOT.ALLOCATED(OMESH(NOM)%MUNKH)) THEN + ALLOCATE(OMESH(NOM)%MUNKH(LBOUND(OMESH(NOM)%HS,1):UBOUND(OMESH(NOM)%HS,1), & + LBOUND(OMESH(NOM)%HS,2):UBOUND(OMESH(NOM)%HS,2), & + LBOUND(OMESH(NOM)%HS,3):UBOUND(OMESH(NOM)%HS,3))) + ENDIF + + ! Allocate EWC_TYPE if not already allocated (same bounds as HS): + IF (VAR_CC==IS_WALLT .AND. .NOT.ALLOCATED(OMESH(NOM)%EWC_TYPE)) THEN + ALLOCATE(OMESH(NOM)%EWC_TYPE(LBOUND(OMESH(NOM)%HS,1):UBOUND(OMESH(NOM)%HS,1), & + LBOUND(OMESH(NOM)%HS,2):UBOUND(OMESH(NOM)%HS,2), & + LBOUND(OMESH(NOM)%HS,3):UBOUND(OMESH(NOM)%HS,3))) + ENDIF + + ! Copy HS data to appropriate OMESH array: + IF (VAR_CC==CGSC .AND. ALLOCATED(OMESH(NOM)%GSCH)) THEN + OMESH(NOM)%GSCH(:,:,:) = INT(OMESH(NOM)%HS(:,:,:)) + ELSEIF (VAR_CC==UNKH .AND. ALLOCATED(OMESH(NOM)%MUNKH)) THEN + OMESH(NOM)%MUNKH(:,:,:) = INT(OMESH(NOM)%HS(:,:,:)) + ELSEIF (VAR_CC==IS_WALLT .AND. ALLOCATED(OMESH(NOM)%EWC_TYPE)) THEN + OMESH(NOM)%EWC_TYPE(:,:,:) = INT(OMESH(NOM)%HS(:,:,:)) + ENDIF + ENDDO +ENDDO - ! - IF (CC_IBM .AND. VAR_CC==UNKH) THEN - - CALL COPY_CC_HS_TO_UNKH(NM) - - ELSE - - ! Loop over external wall cells: - EXTERNAL_WALL_LOOP: DO IW=1,N_EXTERNAL_WALL_CELLS +! GRID REFINEMENT: Handle CC_IBM case if needed +IF (CC_IBM .AND. VAR_CC==UNKH) THEN + DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX + CALL POINT_TO_MESH(NM) + CALL COPY_CC_MUNKH_TO_UNKH + ENDDO +ENDIF - WC=>WALL(IW) - BC=>BOUNDARY_COORD(WC%BC_INDEX) - EWC=>EXTERNAL_WALL(IW) - IF (PRES_ON_WHOLE_DOMAIN) THEN - ! Matrix connectivities kept in cases of BOUNDARY_TYPE=INTERPOLATED_BOUNDARY, NULL_BOUNDARY, or - ! SOLID_BOUNDARY where there is an OMESH, case of OBSTS right in the boundary of meshes. - FLG = WC%BOUNDARY_TYPE==INTERPOLATED_BOUNDARY .OR. WC%BOUNDARY_TYPE==NULL_BOUNDARY - FLG = FLG .OR. (WC%BOUNDARY_TYPE==SOLID_BOUNDARY .AND. EWC%NOM > 0) - IF (.NOT.FLG) CYCLE EXTERNAL_WALL_LOOP - ELSE - ! Case of solving for H only on the gas phase, connectivity kept only for INTERPOLATED_BOUNDARY. - IF (WC%BOUNDARY_TYPE/=INTERPOLATED_BOUNDARY) CYCLE EXTERNAL_WALL_LOOP - ENDIF +! Zero out HS after using it +IF (VAR_CC == UNKH) THEN + DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX + CALL POINT_TO_MESH(NM) + HS(:,:,:) = 0._EB + ENDDO +ENDIF - II = BC%II - JJ = BC%JJ - KK = BC%KK - IOR = BC%IOR - NOM = EWC%NOM - ! Here if NOM==0 means it is an OBST laying on an external boundary -> CYCLE - IF(NOM < 1) CYCLE EXTERNAL_WALL_LOOP - OM => OMESH(NOM) +! DIAGNOSTIC: Write out OMESH%EWC_TYPE for external wall cells +IF (WRITE_EWC_TYPE .AND. VAR_CC == IS_WALLT) CALL WRITE_EWC_TYPE_DIAGNOSTIC - ! This assumes all meshes at the same level of refinement: - KKO=EWC%KKO_MIN - JJO=EWC%JJO_MIN - IIO=EWC%IIO_MIN +RETURN +END SUBROUTINE COPY_HS_IN_CCVAR - CCVAR(II,JJ,KK,VAR_CC) = INT(OM%HS(IIO,JJO,KKO)) +! --------------------------- WRITE_EWC_TYPE_DIAGNOSTIC ----------------------------- - ENDDO EXTERNAL_WALL_LOOP +SUBROUTINE WRITE_EWC_TYPE_DIAGNOSTIC - ENDIF +USE MESH_POINTERS - IF (VAR_CC == UNKH) THEN - HS(:,:,:) = 0._EB - ENDIF +! Local Variables: +INTEGER :: NM,NOM,IW,IIG,JJG,KKG,IOR,IIO,JJO,KKO,BNDRY_TYPE,II_NOM,JJ_NOM,KK_NOM +TYPE(WALL_TYPE), POINTER :: WC +TYPE(BOUNDARY_COORD_TYPE), POINTER :: BC +TYPE(EXTERNAL_WALL_TYPE), POINTER :: EWC -ENDDO MESH_LOOP +DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX + CALL POINT_TO_MESH(NM) + + EXTERNAL_WALL_LOOP_DIAG: DO IW=1,N_EXTERNAL_WALL_CELLS + WC => WALL(IW) + BC => BOUNDARY_COORD(WC%BC_INDEX) + EWC => EXTERNAL_WALL(IW) + + ! Skip if no neighboring mesh + NOM = EWC%NOM; IF (NOM < 1) CYCLE + + ! Get internal cell indices + IIG = BC%IIG; JJG = BC%JJG; KKG = BC%KKG + IOR = BC%IOR + + ! Check if OMESH%EWC_TYPE is allocated + IF (.NOT.ALLOCATED(OMESH(NOM)%EWC_TYPE)) THEN + WRITE(0,*) 'WARNING: MESH',NM,'IW=',IW,'OMESH(',NOM,')%EWC_TYPE NOT ALLOCATED' + CYCLE + ENDIF + + ! Loop over all external cells in neighboring mesh + DO KKO = EWC%KKO_MIN, EWC%KKO_MAX + DO JJO = EWC%JJO_MIN, EWC%JJO_MAX + DO IIO = EWC%IIO_MIN, EWC%IIO_MAX + + ! Compute guard cell location in neighboring mesh based on IOR + CALL COMPUTE_GUARD_CELL_INDEXES(IOR, IIO, JJO, KKO, II_NOM, JJ_NOM, KK_NOM) + + BNDRY_TYPE = OMESH(NOM)%EWC_TYPE(II_NOM,JJ_NOM,KK_NOM) + + ! Only print if boundary type is defined (not IS_UNDEFINED) + IF (BNDRY_TYPE /= IS_UNDEFINED) THEN + WRITE(0,'(A,I3,A,I5,A,3I4,A,I2,A,I3,A,3I4,A,3I4,A,I3)') & + 'MESH',NM,' IW=',IW,' INT(',IIG,JJG,KKG,') IOR=',IOR, & + ' -> MESH',NOM,' EXT(',IIO,JJO,KKO,') GUARD(',II_NOM,JJ_NOM,KK_NOM,') TYPE=',BNDRY_TYPE + ENDIF + + ENDDO + ENDDO + ENDDO + + ENDDO EXTERNAL_WALL_LOOP_DIAG + +ENDDO RETURN -END SUBROUTINE COPY_HS_IN_CCVAR - +END SUBROUTINE WRITE_EWC_TYPE_DIAGNOSTIC ! ------------------------------- COPY_CCVAR_IN_HS ---------------------------------- @@ -4026,14 +4241,29 @@ SUBROUTINE COPY_CCVAR_IN_HS(VAR_CC) INTEGER, INTENT(IN) :: VAR_CC ! Local Variables: -INTEGER :: NM +INTEGER :: NM,IW,II,JJ,KK +TYPE(WALL_TYPE), POINTER :: WC +TYPE(BOUNDARY_COORD_TYPE), POINTER :: BC DO NM=LOWER_MESH_INDEX,UPPER_MESH_INDEX CALL POINT_TO_MESH(NM) - HS(0:IBP1,0:JBP1,0:KBP1) = REAL(CCVAR(0:IBP1,0:JBP1,0:KBP1,VAR_CC),EB) - - ! Now cut-cells add their single Cartesian UNKH value in HS: - IF(CC_IBM .AND. VAR_CC==UNKH) CALL COPY_CC_UNKH_TO_HS(NM) + + ! Special case for IS_WALLT: populate HS from WALL array instead of CCVAR + IF (VAR_CC == IS_WALLT) THEN + HS(:,:,:) = REAL(IS_UNDEFINED,EB) ! Initialize + DO IW=1,N_EXTERNAL_WALL_CELLS + WC => WALL(IW) + BC => BOUNDARY_COORD(WC%BC_INDEX) + II = BC%II; JJ = BC%JJ; KK = BC%KK + HS(II,JJ,KK) = REAL(WC%BOUNDARY_TYPE,EB) + ENDDO + ELSE + ! Standard case: copy from CCVAR to HS + HS(0:IBP1,0:JBP1,0:KBP1) = REAL(CCVAR(0:IBP1,0:JBP1,0:KBP1,VAR_CC),EB) + + ! Now cut-cells add their single Cartesian UNKH value in HS: + IF(CC_IBM .AND. VAR_CC==UNKH) CALL COPY_CC_UNKH_TO_HS(NM) + ENDIF ENDDO @@ -4601,7 +4831,7 @@ SUBROUTINE GET_BCS_H_MATRIX USE CC_SCALARS, ONLY : GET_CC_UNKH, GET_CFACE_OPEN_BC_COEF ! Local Variables: -INTEGER :: NM,NM1,JLOC,JCOL,IND(LOW_IND:HIGH_IND),IND_LOC(LOW_IND:HIGH_IND),IERR,IIG,JJG,KKG,II,JJ,KK,IW,ILH,JLH,KLH,IRC +INTEGER :: NM,NM1,JLOC,JCOL,IND(LOW_IND:HIGH_IND),IND_LOC(LOW_IND:HIGH_IND),IERR,IIG,JJG,KKG,IW,ILH,JLH,KLH,IRC REAL(EB):: AF,IDX,BIJ TYPE(WALL_TYPE), POINTER :: WC TYPE (BOUNDARY_COORD_TYPE), POINTER :: BC @@ -4625,7 +4855,6 @@ SUBROUTINE GET_BCS_H_MATRIX IIG = BC%IIG; JJG = BC%JJG; KKG = BC%KKG IF((.NOT.CC_IBM .AND. CCVAR(IIG,JJG,KKG,UNKH)<1) & .OR. ZONE_SOLVE(PRESSURE_ZONE(IIG,JJG,KKG))%CONNECTED_ZONE_PARENT/=IPZ) CYCLE - II = BC%II; JJ = BC%JJ; KK = BC%KK ! Unknowns on related cells: IF(CCVAR(IIG,JJG,KKG,CGSC)==IS_GASPHASE .OR. PRES_ON_WHOLE_DOMAIN) THEN IND(LOW_IND) = CCVAR(IIG,JJG,KKG,UNKH) ! internal cell. @@ -4701,13 +4930,18 @@ SUBROUTINE GET_H_MATRIX REAL(EB), POINTER, DIMENSION(:) :: DX1,DX2,DX3 INTEGER :: I,J,K,I1,I2,I3,IIP,JJP,KKP,IIM,JJM,KKM INTEGER :: ILOC,JLOC,IROW,JCOL,IND(LOW_IND:HIGH_IND),IND_LOC(LOW_IND:HIGH_IND) -REAL(EB):: AF,IDX,BIJ,KFACE(1:2,1:2) +REAL(EB):: AF,IDX,BIJ,KFACE(1:2,1:2) ! KFACE still used for regular internal faces TYPE(CC_REGFACE_TYPE), POINTER, DIMENSION(:) :: RGF TYPE(WALL_TYPE), POINTER :: WC TYPE (BOUNDARY_COORD_TYPE), POINTER :: BC TYPE (EXTERNAL_WALL_TYPE), POINTER :: EWC INTEGER :: IIG,JJG,KKG,II,JJ,KK,IOR,LOCROW,IW -INTEGER :: WC_JD(1:2,1:2) +INTEGER :: IIO,JJO,KKO,NOM ! Grid refinement: loop indices and neighboring mesh number +INTEGER :: II_NOM,JJ_NOM,KK_NOM ! Grid refinement: guard cell indices in neighboring mesh +INTEGER :: IUNK_INT,IUNK_EXT,IROW_INT ! Grid refinement: unknown numbers for internal and external cells +REAL(EB):: AF_INT,AF_EXT,DX_INT,DX_EXT ! Grid refinement: areas and distances for both cells +TYPE(MESH_TYPE), POINTER :: M2 ! Grid refinement: pointer to neighboring mesh +TYPE(OMESH_TYPE), POINTER :: OM ! Grid refinement: pointer to OMESH data LOGICAL :: FLG IPZ_LOOP : DO IPZ=0,N_ZONE_GLOBMAT @@ -4802,61 +5036,153 @@ SUBROUTINE GET_H_MATRIX ! Next, Wall faces of type INTERPOLATED_BOUNDARY or PERIODIC_BOUNDARY: ! Here We have to do something about WALL cells that are also cut-faces, who wins? Make cut-faces take precedence. + ! + ! MODIFICATION FOR GRID REFINEMENT: + ! Loop over ALL cells in neighboring mesh and compute flux coupling coefficients for each. + ! Column indices are searched on-the-fly (no pre-storage needed). + ! LOCROW = LOW_IND WALL_LOOP_1 : DO IW=1,N_EXTERNAL_WALL_CELLS WC => WALL(IW) BC => BOUNDARY_COORD(WC%BC_INDEX) EWC=>EXTERNAL_WALL(IW) + FLG = WC%BOUNDARY_TYPE==PERIODIC_BOUNDARY .OR. WC%BOUNDARY_TYPE==INTERPOLATED_BOUNDARY IF(PRES_ON_WHOLE_DOMAIN) & FLG = FLG .OR. WC%BOUNDARY_TYPE==NULL_BOUNDARY .OR. (WC%BOUNDARY_TYPE==SOLID_BOUNDARY .AND. EWC%NOM > 0) IF ( .NOT.FLG .OR. EWC%NOM<1) CYCLE ! Here if NOM==0 means it is an OBST laying on an external boundary -> CYCLE - IIG = BC%IIG; JJG = BC%JJG; KKG = BC%KKG + + IIG = BC%IIG; JJG = BC%JJG; KKG = BC%KKG; II = BC%II; JJ = BC%JJ; KK = BC%KK; IF(ZONE_SOLVE(PRESSURE_ZONE(IIG,JJG,KKG))%CONNECTED_ZONE_PARENT/=IPZ) CYCLE - - WC_JD(1,1) = WC%JD11_INDEX - WC_JD(1,2) = WC%JD12_INDEX - WC_JD(2,1) = WC%JD21_INDEX - WC_JD(2,2) = WC%JD22_INDEX - - II = BC%II; JJ = BC%JJ; KK = BC%KK; IOR = BC%IOR - ! Check if CC_IBM -> If either IIG,JJG,KKG or II,JJ,KK cell is type IS_CUTCFE or IS_SOLID cycle: + + IOR = BC%IOR + + ! Check if CC_IBM -> If IIG,JJG,KKG cell is type IS_CUTCFE or IS_SOLID cycle: IF ( .NOT.PRES_ON_WHOLE_DOMAIN .AND. CC_IBM ) THEN - IF(CCVAR(II ,JJ ,KK ,CC_CGSC) /= IS_GASPHASE) CYCLE IF(CCVAR(IIG,JJG,KKG,CC_CGSC) /= IS_GASPHASE) CYCLE ENDIF + + ! IUNK_INT and IROW_INT: + IUNK_INT = CCVAR(IIG,JJG,KKG,UNKH) ! internal. + IROW_INT = IUNK_INT - ZSL%UNKH_IND(NM1) - ! Unknowns on related cells: - IND(LOW_IND) = CCVAR(IIG,JJG,KKG,UNKH) ! internal. - IND(HIGH_IND) = CCVAR(II,JJ,KK,UNKH) ! guard-cell. - IND_LOC(LOW_IND) = IND(LOW_IND) - ZSL%UNKH_IND(NM1) ! All row indexes must refer to ind_loc. - IND_LOC(HIGH_IND)= IND(HIGH_IND)- ZSL%UNKH_IND(NM1) + ! Get neighboring mesh information: + NOM = EWC%NOM + M2 => MESHES(NOM) + OM => OMESH(NOM) + + ! Distance from internal cell center to boundary face (half cell width): SELECT CASE(IOR) CASE( IAXIS) - AF = ((1._EB-CYL_FCT)*DY(JJG) + CYL_FCT*R(IIG-1)) * DZ(KKG); IDX= 1._EB/DXN(IIG-1) + DX_INT = 0.5_EB * DXN(IIG-1) CASE(-IAXIS) - AF = ((1._EB-CYL_FCT)*DY(JJG) + CYL_FCT*R(IIG )) * DZ(KKG); IDX= 1._EB/DXN(IIG) + DX_INT = 0.5_EB * DXN(IIG) CASE( JAXIS) - AF = DX(IIG)*DZ(KKG); IDX= 1._EB/DYN(JJG-1) + DX_INT = 0.5_EB * DYN(JJG-1) CASE(-JAXIS) - AF = DX(IIG)*DZ(KKG); IDX= 1._EB/DYN(JJG) + DX_INT = 0.5_EB * DYN(JJG) CASE( KAXIS) - AF = ((1._EB-CYL_FCT)*DY(JJG) + CYL_FCT*RC(IIG ))* DX(IIG); IDX= 1._EB/DZN(KKG-1) + DX_INT = 0.5_EB * DZN(KKG-1) CASE(-KAXIS) - AF = ((1._EB-CYL_FCT)*DY(JJG) + CYL_FCT*RC(IIG ))* DX(IIG); IDX= 1._EB/DZN(KKG) + DX_INT = 0.5_EB * DZN(KKG) END SELECT - ! Now add to Adiff corresponding coeff: - BIJ = IDX*AF - ! Cols ind(1) ind(2) - KFACE(1,1)= BIJ; KFACE(1,2)=-BIJ ! Row ind(1) - KFACE(2,1)=-BIJ; KFACE(2,2)= BIJ ! Row ind(2) - ILOC = LOCROW ! Local row number in Kface, only for cell IIG,JJG,KKG. - DO JLOC = LOW_IND,HIGH_IND ! Local col number in Kface, JD - IROW = IND_LOC(ILOC) ! Unknown number. - JCOL = WC_JD(ILOC,JLOC) - ZSL%ROW_H(IROW)%D(JCOL) = ZSL%ROW_H(IROW)%D(JCOL) + KFACE(ILOC,JLOC) - ENDDO + + ! Loop over ALL cells in the neighboring mesh that share this boundary face: + DO KKO = EWC%KKO_MIN, EWC%KKO_MAX + DO JJO = EWC%JJO_MIN, EWC%JJO_MAX + DO IIO = EWC%IIO_MIN, EWC%IIO_MAX + + ! Get unknown number for external cell in neighboring mesh: + IUNK_EXT = OM%MUNKH(IIO,JJO,KKO) + + ! For UGLMAT, skip if external cell is solid: + IF ( .NOT.PRES_ON_WHOLE_DOMAIN .AND.IUNK_EXT <= 0) CYCLE + + ! GRID REFINEMENT: Compute guard cell location in neighboring mesh based on IOR + CALL COMPUTE_GUARD_CELL_INDEXES(IOR, IIO, JJO, KKO, II_NOM, JJ_NOM, KK_NOM) + + ! Check if external cell has INTERPOLATED_BOUNDARY type + ! If not INTERPOLATED_BOUNDARY, skip (zero coefficient, no flux coupling) + IF (ALLOCATED(OM%EWC_TYPE)) THEN + IF (OM%EWC_TYPE(II_NOM,JJ_NOM,KK_NOM) /= INTERPOLATED_BOUNDARY) CYCLE + ENDIF + + ! Area of INTERNAL cell face (current mesh): + SELECT CASE(IOR) + CASE( IAXIS, -IAXIS) + IF (CYLINDRICAL) THEN + AF_INT = ((1._EB-CYL_FCT)*DY(JJG) + CYL_FCT*R(IIG)) * DZ(KKG) + ELSE + AF_INT = DY(JJG) * DZ(KKG) + ENDIF + CASE( JAXIS, -JAXIS) + AF_INT = DX(IIG) * DZ(KKG) + CASE( KAXIS, -KAXIS) + IF (CYLINDRICAL) THEN + AF_INT = ((1._EB-CYL_FCT)*DY(JJG) + CYL_FCT*RC(IIG)) * DX(IIG) + ELSE + AF_INT = DX(IIG) * DY(JJG) + ENDIF + END SELECT + + ! Area of EXTERNAL cell face (other mesh): + SELECT CASE(IOR) + CASE( IAXIS, -IAXIS) + IF (CYLINDRICAL) THEN + AF_EXT = ((1._EB-CYL_FCT)*M2%DY(JJO) + CYL_FCT*M2%R(IIO)) * M2%DZ(KKO) + ELSE + AF_EXT = M2%DY(JJO) * M2%DZ(KKO) + ENDIF + CASE( JAXIS, -JAXIS) + AF_EXT = M2%DX(IIO) * M2%DZ(KKO) + CASE( KAXIS, -KAXIS) + IF (CYLINDRICAL) THEN + AF_EXT = ((1._EB-CYL_FCT)*M2%DY(JJO) + CYL_FCT*M2%RC(IIO)) * M2%DX(IIO) + ELSE + AF_EXT = M2%DX(IIO) * M2%DY(JJO) + ENDIF + END SELECT + + ! Use the MINIMUM area (actual contact/intersection area): + AF = MIN(AF_INT, AF_EXT) + + ! Distance from boundary face to external cell center (half cell width): + SELECT CASE(IOR) + CASE( IAXIS, -IAXIS) + DX_EXT = 0.5_EB * M2%DXN(IIO) + CASE( JAXIS, -JAXIS) + DX_EXT = 0.5_EB * M2%DYN(JJO) + CASE( KAXIS, -KAXIS) + DX_EXT = 0.5_EB * M2%DZN(KKO) + END SELECT + + ! Inverse of total distance between cell centers: + IDX = 1._EB / (DX_INT + DX_EXT) + + ! Flux coupling coefficient: + BIJ = IDX * AF + + ! (1) Add to DIAGONAL of internal cell row: + DO JLOC = 1, ZSL%ROW_H(IROW_INT)%NNZ + IF (IUNK_INT == ZSL%ROW_H(IROW_INT)%JD(JLOC)) THEN + ZSL%ROW_H(IROW_INT)%D(JLOC) = ZSL%ROW_H(IROW_INT)%D(JLOC) + BIJ + EXIT + ENDIF + ENDDO + + ! (2) Add to OFF-DIAGONAL coupling to external cell: + DO JLOC = 1, ZSL%ROW_H(IROW_INT)%NNZ + IF (IUNK_EXT == ZSL%ROW_H(IROW_INT)%JD(JLOC)) THEN + ZSL%ROW_H(IROW_INT)%D(JLOC) = ZSL%ROW_H(IROW_INT)%D(JLOC) - BIJ + EXIT + ENDIF + ENDDO + + ENDDO ! IIO loop + ENDDO ! JJO loop + ENDDO ! KKO loop + ENDDO WALL_LOOP_1 ! Contribution to Laplacian matrix from RC and cut-faces: @@ -4884,13 +5210,14 @@ SUBROUTINE GET_MATRIXGRAPH_H_WHLDOM INTEGER :: NM INTEGER :: X1AXIS,IFACE,I,I1,J,K,IND(LOW_IND:HIGH_IND),IND_LOC(LOW_IND:HIGH_IND) INTEGER :: LOCROW,IIND,NII,ILOC -INTEGER :: NREG,IIM,JJM,KKM,IIP,JJP,KKP,LOW_FACE,HIGH_FACE,IW,II,JJ,KK,IIG,JJG,KKG,ICF +INTEGER :: NREG,IIM,JJM,KKM,IIP,JJP,KKP,LOW_FACE,HIGH_FACE,IW,IIG,JJG,KKG,II,JJ,KK,ICF TYPE(CC_REGFACE_TYPE), POINTER, DIMENSION(:) :: RGF TYPE(CC_RCFACE_TYPE), POINTER :: RCF TYPE(WALL_TYPE), POINTER :: WC TYPE (BOUNDARY_COORD_TYPE), POINTER :: BC TYPE(EXTERNAL_WALL_TYPE), POINTER :: EWC -INTEGER :: WC_JD(1:2,1:2) +INTEGER :: IIO,JJO,KKO,NOM ! Grid refinement: loop indices and neighboring mesh number +INTEGER :: II_NOM,JJ_NOM,KK_NOM ! Grid refinement: guard cell indices in neighboring mesh LOGICAL :: FLG ! Write number of pressure unknowns to output: @@ -4996,6 +5323,11 @@ SUBROUTINE GET_MATRIXGRAPH_H_WHLDOM ! Next, Wall faces of type INTERPOLATED_BOUNDARY or PERIODIC_BOUNDARY: ! Here We have to do something about WALL cells that are also cut-faces, who wins? Make cut-faces take precedence. + ! + ! MODIFICATION FOR GRID REFINEMENT: + ! Loop over ALL cells in the neighboring mesh (EWC%IIO_MIN:IIO_MAX, etc.) to handle cases where + ! one coarse cell in this mesh connects to multiple fine cells in the neighboring mesh. + ! LOCROW = LOW_IND WALL_LOOP_1 : DO IW=1,N_EXTERNAL_WALL_CELLS WC => WALL(IW) @@ -5005,19 +5337,57 @@ SUBROUTINE GET_MATRIXGRAPH_H_WHLDOM IF(PRES_ON_WHOLE_DOMAIN) & FLG = FLG .OR. WC%BOUNDARY_TYPE==NULL_BOUNDARY .OR. (WC%BOUNDARY_TYPE==SOLID_BOUNDARY .AND. EWC%NOM > 0) IF ( .NOT.FLG .OR. EWC%NOM<1) CYCLE ! Here if NOM==0 means it is an OBST laying on an external boundary -> CYCLE - IIG = BC%IIG; JJG = BC%JJG; KKG = BC%KKG; II = BC%II; JJ = BC%JJ; KK = BC%KK + + IIG = BC%IIG; JJG = BC%JJG; KKG = BC%KKG; II = BC%II; JJ = BC%JJ; KK = BC%KK; IF(ZONE_SOLVE(PRESSURE_ZONE(IIG,JJG,KKG))%CONNECTED_ZONE_PARENT/=IPZ) CYCLE - ! Check if CC_IBM -> If either IIG,JJG,KKG or II,JJ,KK cell is type IS_CUTCFE or IS_SOLID cycle: + + ! Check if CC_IBM -> If IIG,JJG,KKG cell is type IS_CUTCFE or IS_SOLID cycle: + ! for cut-faces, RC_faces this will be taken care of in GET_CC_MATRIXGRAPH_H IF (CC_IBM) THEN - IF(CCVAR(II ,JJ ,KK ,CC_CGSC) /= IS_GASPHASE) CYCLE - IF(CCVAR(IIG,JJG,KKG,CC_CGSC) /= IS_GASPHASE) CYCLE + IF(CCVAR(IIG,JJG,KKG,CC_CGSC) /= IS_GASPHASE) CYCLE ENDIF - ! Unknowns on related cells: - IND(LOW_IND) = CCVAR(IIG,JJG,KKG,UNKH) ! internal. - IND(HIGH_IND) = CCVAR(II,JJ,KK,UNKH) ! guard-cell. - IND_LOC(LOW_IND) = IND(LOW_IND) - ZSL%UNKH_IND(NM_START) ! All row indexes must refer to ind_loc. - IND_LOC(HIGH_IND)= IND(HIGH_IND)- ZSL%UNKH_IND(NM_START) - CALL ADD_INPLACE_NNZ_H_WHLDOM(LOCROW,LOCROW,IND,IND_LOC,IPZ) + + ! Get the neighboring mesh number: + NOM = EWC%NOM + + ! Loop over ALL cells in the neighboring mesh that share this boundary face. + ! For same refinement: IIO_MIN==IIO_MAX (single cell) + ! For 2:1 refinement: IIO_MIN to IIO_MAX spans 2 cells in one direction (4 cells for face, 8 for edge) + ! For 4:1 refinement: spans 4 cells in one direction (16 cells for face) + ! + DO KKO = EWC%KKO_MIN, EWC%KKO_MAX + DO JJO = EWC%JJO_MIN, EWC%JJO_MAX + DO IIO = EWC%IIO_MIN, EWC%IIO_MAX + + ! For UGLMAT, check if the external cell is gas phase: + IF(.NOT.PRES_ON_WHOLE_DOMAIN .AND. OMESH(NOM)%MUNKH(IIO,JJO,KKO) <= 0) CYCLE + + ! GRID REFINEMENT: Compute guard cell location in neighboring mesh based on IOR + CALL COMPUTE_GUARD_CELL_INDEXES(BC%IOR, IIO, JJO, KKO, II_NOM, JJ_NOM, KK_NOM) + + ! Check if external cell has INTERPOLATED_BOUNDARY type + ! If not INTERPOLATED_BOUNDARY, skip (no connectivity, zero gradient) + IF (ALLOCATED(OMESH(NOM)%EWC_TYPE)) THEN + IF (OMESH(NOM)%EWC_TYPE(II_NOM,JJ_NOM,KK_NOM) /= INTERPOLATED_BOUNDARY) CYCLE + ENDIF + + ! Unknown numbers on related cells: + IND(LOW_IND) = CCVAR(IIG,JJG,KKG,UNKH) ! internal cell in this mesh + IND(HIGH_IND) = OMESH(NOM)%MUNKH(IIO,JJO,KKO) ! cell in neighboring mesh + + ! Convert to local row numbering: + IND_LOC(LOW_IND) = IND(LOW_IND) - ZSL%UNKH_IND(NM_START) + IND_LOC(HIGH_IND) = IND(HIGH_IND) - ZSL%UNKH_IND(NM_START) + + ! Add this connectivity to the matrix graph. + ! This function adds IND(HIGH_IND) to the column list (JD array) of row IND(LOW_IND), + ! and vice versa for symmetric matrices. + CALL ADD_INPLACE_NNZ_H_WHLDOM(LOCROW,LOCROW,IND,IND_LOC,IPZ) + + ENDDO ! IIO loop + ENDDO ! JJO loop + ENDDO ! KKO loop + ENDDO WALL_LOOP_1 ! Finally Add nonzeros corresponding to RC_FACE, CUT_FACE @@ -5085,44 +5455,6 @@ SUBROUTINE GET_MATRIXGRAPH_H_WHLDOM NULLIFY(RGF) ENDDO AXIS_LOOP_2 - ! Now Wall faces column locations: - LOCROW = LOW_IND - WALL_LOOP_2 : DO IW=1,N_EXTERNAL_WALL_CELLS+N_INTERNAL_WALL_CELLS - WC => WALL(IW) - BC => BOUNDARY_COORD(WC%BC_INDEX) - WC_JD(1:2,1:2) = IS_UNDEFINED - IF (.NOT.PRES_ON_WHOLE_DOMAIN .AND. WC%BOUNDARY_TYPE==NULL_BOUNDARY) CYCLE - IF(IW <= N_EXTERNAL_WALL_CELLS) THEN - ! Here if NOM==0 means it is an OBST laying on an external boundary -> CYCLE - EWC=>EXTERNAL_WALL(IW); IF(EWC%NOM < 1) CYCLE - ENDIF - IIG = BC%IIG; JJG = BC%JJG; KKG = BC%KKG; II = BC%II; JJ = BC%JJ; KK = BC%KK - IF((.NOT.CC_IBM .AND. CCVAR(IIG,JJG,KKG,UNKH)<1) & - .OR. ZONE_SOLVE(PRESSURE_ZONE(IIG,JJG,KKG))%CONNECTED_ZONE_PARENT/=IPZ) CYCLE - ! Check if CC_IBM -> If either IIG,JJG,KKG or II,JJ,KK cell is type IS_CUTCFE or IS_SOLID cycle: - IF (CC_IBM) THEN - IF(CCVAR(II ,JJ ,KK ,CC_CGSC) /= IS_GASPHASE) CYCLE - IF(CCVAR(IIG,JJG,KKG,CC_CGSC) /= IS_GASPHASE) CYCLE - ENDIF - ! Unknowns on related cells: - IND(LOW_IND) = CCVAR(IIG,JJG,KKG,UNKH) ! internal. - IND(HIGH_IND) = CCVAR(II,JJ,KK,UNKH) ! guard-cell. - IND_LOC(LOW_IND) = IND(LOW_IND) - ZSL%UNKH_IND(NM_START) ! All row indexes must refer to ind_loc. - IND_LOC(HIGH_IND)= IND(HIGH_IND)- ZSL%UNKH_IND(NM_START) - DO IIND=LOW_IND,HIGH_IND - NII = ZSL%ROW_H(IND_LOC(LOCROW))%NNZ - DO ILOC=1,NII - IF ( IND(IIND) == ZSL%ROW_H(IND_LOC(LOCROW))%JD(ILOC) ) THEN - WC_JD(LOCROW,IIND) = ILOC - EXIT - ENDIF - ENDDO - ENDDO - WC%JD11_INDEX = WC_JD(1,1) - WC%JD12_INDEX = WC_JD(1,2) - WC%JD21_INDEX = WC_JD(2,1) - WC%JD22_INDEX = WC_JD(2,2) - ENDDO WALL_LOOP_2 ! Finally cut-face: IF (CC_IBM) CALL GET_CC_MATRIXGRAPH_H(NM,NM_START,IPZ,.FALSE.) ENDDO MESH_LOOP_2 @@ -5671,7 +6003,7 @@ SUBROUTINE FINISH_GLMAT_SOLVER #endif ! Local variables: -INTEGER :: MAXFCT, MNUM, PHASE, NRHS, ERROR, MSGLVL +INTEGER :: MAXFCT, MNUM, PHASE, NRHS, ERROR, MSGLVL, NOM #ifdef WITH_MKL INTEGER :: PERM(1) #endif @@ -5706,6 +6038,13 @@ SUBROUTINE FINISH_GLMAT_SOLVER #endif ENDIF +! Deallocate OMESH arrays used for grid refinement: +DO NOM=1,NMESHES + IF (ALLOCATED(OMESH(NOM)%GSCH)) DEALLOCATE(OMESH(NOM)%GSCH) + IF (ALLOCATED(OMESH(NOM)%MUNKH)) DEALLOCATE(OMESH(NOM)%MUNKH) + IF (ALLOCATED(OMESH(NOM)%EWC_TYPE)) DEALLOCATE(OMESH(NOM)%EWC_TYPE) +ENDDO + DEALLOCATE(ZONE_SOLVE) RETURN diff --git a/Source/radi.f90 b/Source/radi.f90 index a342e288794..52010cf4ef0 100644 --- a/Source/radi.f90 +++ b/Source/radi.f90 @@ -3292,9 +3292,9 @@ SUBROUTINE INIT_RADIATION END SELECT CALL SUB_RADCAL(AMEAN,AP0,RADIANCE,TRANSMISSIVITY) IF (PATH_LENGTH > 0.0_EB) THEN - RADCAL_SPECIES2KAPPA(NS,J,K,1) = MIN(AMEAN,AP0)/BBF + RADCAL_SPECIES2KAPPA(NS,J,K,IBND) = MIN(AMEAN,AP0)/BBF ELSE ! zero path length - RADCAL_SPECIES2KAPPA(NS,J,K,1) = AP0/BBF + RADCAL_SPECIES2KAPPA(NS,J,K,IBND) = AP0/BBF ENDIF END DO RADCAL_SPECIES_LOOP ENDDO Y_LOOP_Z diff --git a/Source/type.f90 b/Source/type.f90 index 53b295b268c..222b067b9e5 100644 --- a/Source/type.f90 +++ b/Source/type.f90 @@ -1047,7 +1047,7 @@ MODULE TYPES INTEGER, ALLOCATABLE, DIMENSION(:) :: ICC_UNKZ_CT_S, ICC_UNKZ_CC_S, ICC_UNKZ_CT_R, ICC_UNKZ_CC_R,& ICF_UFFB_CF_S, ICF_UFFB_CF_R INTEGER, ALLOCATABLE, DIMENSION(:) :: UNKZ_CT_S, UNKZ_CC_S, UNKZ_CT_R, UNKZ_CC_R - INTEGER, ALLOCATABLE, DIMENSION(:,:,:) :: MUNKH,GSCH + INTEGER, ALLOCATABLE, DIMENSION(:,:,:) :: MUNKH,GSCH,EWC_TYPE ! Face variables data (velocities): INTEGER, ALLOCATABLE, DIMENSION(:) :: IIO_FC_R,JJO_FC_R,KKO_FC_R,AXS_FC_R,IIO_FC_S,JJO_FC_S,KKO_FC_S,AXS_FC_S diff --git a/Utilities/Matlab/FDS_validation_script.m b/Utilities/Matlab/FDS_validation_script.m index 29293c8a7d9..6d139d8b75c 100644 --- a/Utilities/Matlab/FDS_validation_script.m +++ b/Utilities/Matlab/FDS_validation_script.m @@ -29,25 +29,6 @@ restoredefaultpath addpath 'scripts' -% Scripts that run prior to dataplot - -NIST_deposition_gauge -flame_height -NIST_RSE -sippola_aerosol_deposition -layer_height -NIST_NRC_Corner_Effects -%fm_datacenter_scatter -LNG_Dispersion -LNG_wind_profiles -FM_Vertical_Wall_Flames -umd_line_burner_process -%Askervein_Hill -UWO_Wind_Tunnel -FM_Burner -Crown_Fires -ranz_marshall -Phoenix_LNG_Fires % Dataplot and scatplot options diff --git a/Utilities/Matlab/FDS_verification_dataplot_inputs.csv b/Utilities/Matlab/FDS_verification_dataplot_inputs.csv index 35be83d3c26..0e0db8f2dfa 100644 --- a/Utilities/Matlab/FDS_verification_dataplot_inputs.csv +++ b/Utilities/Matlab/FDS_verification_dataplot_inputs.csv @@ -736,7 +736,6 @@ d,velocity_bc_test,Flowfields/velocity_bc_test_git.txt,Flowfields/velocity_bc_te d,velocity_bc_test,Flowfields/velocity_bc_test_git.txt,Flowfields/velocity_bc_test_line.csv,2,3,x1p,Pres1,Thin Plate (Pres1),k-,-6,21,,-6,21,-1.00E+09,1.00E+09,0,Flowfields/velocity_bc_test_line.csv,2,3,x1p,Pres2|Pres3,Solid Block (Pres2)|Thick Plate (Pres3),r-|g-,-6,21,,-6,21,-1.00E+09,1.00E+09,0,Centerline Pressure (velocity\_bc\_test),Distance (m),Pressure (Pa),-5,20,1,-0.5,1,1,no,0.05 0.90,SouthEast,,1,linear,FDS_Verification_Guide/SCRIPT_FIGURES/velocity_bc_test_pres,Absolute Error,mean_1_2,0.05,Flowfields,kd,k,TeX d,volume_flow_1,Flowfields/volume_flow_1_git.txt,Flowfields/volume_flow.csv,1,2,Time,vflow,Expected,ko,0,100000,,50,100,-1.00E+09,1.00E+09,0,Flowfields/volume_flow_1_devc.csv,2,3,Time,vflow,FDS,k-,0,100000,,50,100,-1.00E+09,1.00E+09,0,Flow Test (volume\_flow\_1),Time (s),Volume Flow (m³/s),0,100,1,0,0.015,1,no,0.05 0.90,SouthEast,,1,linear,FDS_User_Guide/SCRIPT_FIGURES/volume_flow_1,Relative Error,mean,0.01,Flowfields,kd,k,TeX d,volume_flow_2,Flowfields/volume_flow_2_git.txt,Flowfields/volume_flow.csv,1,2,Time,vflow,Expected,ko,0,100000,,50,100,-1.00E+09,1.00E+09,0,Flowfields/volume_flow_2_devc.csv,2,3,Time,vflow,FDS,k-,0,100000,,50,100,-1.00E+09,1.00E+09,0,Flow Test (volume\_flow\_2),Time (s),Volume Flow (m³/s),0,100,1,0,0.015,1,no,0.05 0.90,SouthEast,,1,linear,FDS_User_Guide/SCRIPT_FIGURES/volume_flow_2,Relative Error,mean,0.01,Flowfields,kd,k,TeX -d,vort2d,NS_Analytical_Solution/vort2d_40_git.txt,NS_Analytical_Solution/vort2d_error.csv,1,2,dx,dxmod|dx^2,O(\deltax)|O(\deltax²),k--|k-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,NS_Analytical_Solution/vort2d_error.csv,1,2,dx,rms1|rms2|rms3,FDS (RMS error at t=0.0089 s)|FDS (RMS error at t=0.0178 s)|FDS (RMS error at t=0.0267 s),g*-|co-|r^-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Convergence (vort2d),Grid Spacing (m),RMS Error (m/s),0.0009,0.009,1,0.001,1,1,no,0.03 0.90,SouthEast,,1,loglog,FDS_Verification_Guide/SCRIPT_FIGURES/vort2d_error,N/A,end,0,NS Analytical Solution,kd,k,TeX d,water_evap_1_const_gamma,Sprinklers_and_Sprays/water_evap_1_const_gamma_git.txt,Sprinklers_and_Sprays/water_evap_1_const_gamma.csv,1,2,Time,Rel. Hum,Exact (Rel. Hum),ko,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Sprinklers_and_Sprays/water_evap_1_const_gamma_devc.csv,2,3,Time,humid,FDS (humid),k-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Relative Humidity (water\_evap\_1\_const\_gamma),Time (s),Humidity (%),0,10,1,0,3,1,no,0.05 0.90,SouthEast,,1,linear,FDS_Verification_Guide/SCRIPT_FIGURES/water_evap_1_const_gamma_humidity,Relative Error,end,0.01,Sprinklers and Sprays,kd,k,TeX d,water_evap_1_const_gamma,Sprinklers_and_Sprays/water_evap_1_const_gamma_git.txt,Sprinklers_and_Sprays/water_evap_1_const_gamma.csv,1,2,Time,h_gas|h_water,Expected (h\_gas)|Exact (h\_water),go|ro,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Sprinklers_and_Sprays/water_evap_1_const_gamma_devc.csv,2,3,Time,h_gas|h_water,FDS (h\_gas)|FDS (h\_water),g-|r-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Enthalpy Change (water\_evap\_1\_const\_gamma),Time (s),Enthalpy (kJ),0,10,1,-50,50,1,no,0.05 0.90,East,,1,linear,FDS_Verification_Guide/SCRIPT_FIGURES/water_evap_1_const_gamma_enthalpy,Relative Error,end,0.01,Sprinklers and Sprays,kd,k,TeX d,water_evap_1_const_gamma,Sprinklers_and_Sprays/water_evap_1_const_gamma_git.txt,Sprinklers_and_Sprays/water_evap_1_const_gamma.csv,1,2,Time,dens,Exact (dens),ko,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Sprinklers_and_Sprays/water_evap_1_const_gamma_devc.csv,2,3,Time,dens,FDS (dens),k-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Density Change (water\_evap\_1\_const\_gamma),Time (s),Density (kg/m³),0,10,1,0,0.015,1,no,0.05 0.90,SouthEast,,1,linear,FDS_Verification_Guide/SCRIPT_FIGURES/water_evap_1_const_gamma_density,Relative Error,end,0.01,Sprinklers and Sprays,kd,k,TeX @@ -831,3 +830,7 @@ f,anca-couce,Pyrolysis/anca-couce-fig2_2p5K_git.txt,Pyrolysis/Anca-Couce-fig1.cs s,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, g,sphere_leak,Complex_Geometry/sphere_leak_git.txt,Complex_Geometry/sphere_leak.csv,1,2,Time,Pressure,Exact,ko,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Complex_Geometry/sphere_leak_devc.csv,2,3,Time,Pressure,FDS,k-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Pressure Rise (sphere\_leak),Time (s),Pressure (Pa),0,100,1,0,5000,1,no,0.05 0.90,SouthEast,,1,linear,FDS_User_Guide/SCRIPT_FIGURES/sphere_leak,Relative Error,max,0.05,Pressure Effects,k+,k,TeX d,sphere_radiate,Complex_Geometry/sphere_radiate_git.txt,Complex_Geometry/sphere_radiate.csv,1,2,Time,HF,Exact,ko,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Complex_Geometry/sphere_radiate_devc.csv,2,3,Time,HF1,FDS,k-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Heat Flux (sphere\_radiate),Time (s),Heat Flux (kW/m²),0,0.01,1,0,8,1,no,0.05 0.90,SouthEast,,1,linear,FDS_Verification_Guide/SCRIPT_FIGURES/sphere_radiate,Relative Error,max,0.07,Radiation,bs,b,TeX +s,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +d,rms_cov_corr,Controls/rms_cov_corr_git.txt,Controls/rms_cov_corr.csv,1,2,Time,urms,Analytic,k-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Controls/rms_cov_corr_devc.csv,2,3,Time,U-RMS,FDS,r-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,U-RMS (rms\_cov\_cor),Time (s),$u$ rms (m/s),0,1000,1,0.14,0.22,1,no,0.05 0.90,SouthEast,,1,linear,FDS_Verification_Guide/SCRIPT_FIGURES/rms_cov_corr_rms2,Relative Error,end,0.01,rmscovcorr,yd,b,TeX +d,rms_cov_corr,Controls/rms_cov_corr_git.txt,Controls/rms_cov_corr.csv,1,2,Time,uwcov,Analytic,k-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Controls/rms_cov_corr_devc.csv,2,3,Time,U-W COV,FDS,r-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,U-W COV (rms\_cov\_cor),Time (s),$uw$ covariance (m$^2$/s$^2$),0,1000,1,-0.15,0.15,1,no,0.05 0.90,SouthEast,,1,linear,FDS_Verification_Guide/SCRIPT_FIGURES/rms_cov_corr_cov2,Relative Error,end,0.01,rmscovcorr,yd,b,TeX +d,rms_cov_corr,Controls/rms_cov_corr_git.txt,Controls/rms_cov_corr.csv,1,2,Time,uwcorr,Analytic,k-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,Controls/rms_cov_corr_devc.csv,2,3,Time,U-W CORR,FDS,r-,0,100000,,0,100000,-1.00E+09,1.00E+09,0,U-W CORR (rms\_cov\_cor),Time (s),$uw$ cross correlation,0,1000,1,-1,1,1,no,0.05 0.90,SouthEast,,1,linear,FDS_Verification_Guide/SCRIPT_FIGURES/rms_cov_corr_corr2,Relative Error,end,0.01,rmscovcorr,yd,b,TeX diff --git a/Utilities/Matlab/FDS_verification_script.m b/Utilities/Matlab/FDS_verification_script.m index 419e7b68663..3e17f8c2767 100644 --- a/Utilities/Matlab/FDS_verification_script.m +++ b/Utilities/Matlab/FDS_verification_script.m @@ -25,18 +25,7 @@ % Scripts to run prior to dataplot -disp('radiation_box...'); radiation_box -disp('radiation_plane_layer...'); radiation_plane_layer -disp('ns2d...'); ns2d -disp('vort2d...'); vort2d -disp('ashrae_7...'); ashrae_7 -disp('flame_species...'); flame_species -disp('cat_propane_depo...'); cat_propane_depo -disp('burke_schumann...'); burke_schumann disp('convective_cooling_convergence...'); convective_cooling_convergence -disp('random_walk_soln...'); random_walk_soln -disp('water_evap_1_const_gamma...'); water_evap_1_const_gamma -disp('vegetation_absorb...'); vegetation_absorb % Dataplot and scatplot options @@ -62,36 +51,15 @@ % Special cases disp('compression_wave...'); compression_wave -disp('fluid_part...'); fluid_part -disp('extinction...'); extinction -disp('fan_curve...'); fan_curve -disp('mesh_transformation...'); mesh_transformation -disp('synthetic_eddy_method...'); synthetic_eddy_method -disp('shunn_mms_error...'); shunn_mms_error -disp('shunn_cc_mms_error...'); shunn_cc_mms_error disp('rotcube_cc_mms_error...'); rotcube_cc_mms_error -disp('openmp_timing_benchmarks...'); openmp_timing_benchmarks -disp('rms_cov_corr...'); rms_cov_corr -disp('hot_layer_collapse...'); hot_layer_collapse -disp('radiating_polygon...'); radiating_polygon -disp('favre_test...'); favre_test -disp('scaling_tests...'); scaling_tests -disp('hvac_mass_transport...'); hvac_mass_transport -disp('particle_size_distribution...'); particle_size_distribution -disp('mass_balance...'); mass_balance disp('mass_balance_reac...'); mass_balance_reac disp('mass_balance_gas_volume...'); mass_balance_gas_volume -disp('ht3d_sphere...'); ht3d_sphere disp('geom_positive_errors...'); geom_positive_errors disp('geom_channel_test...'); geom_channel_test -disp('atmospheric_boundary_layer...'); atmospheric_boundary_layer -disp('level_set_ellipse...'); level_set_ellipse disp('htc_forced...'); htc_forced disp('natconh...'); natconh disp('natconv...'); natconv disp('freecon_sphere...'); freecon_sphere disp('nat_conv_hot_plate...'); nat_conv_hot_plate -disp('impinging_jet...'); impinging_jet -disp('part_drag_profile...'); part_drag_profile display('verification scripts completed successfully!') diff --git a/Utilities/Matlab/scripts/Crown_Fires.m b/Utilities/Matlab/scripts/Crown_Fires.m deleted file mode 100644 index 6433abec247..00000000000 --- a/Utilities/Matlab/scripts/Crown_Fires.m +++ /dev/null @@ -1,35 +0,0 @@ -% McGrattan -% 10-29-2019 -% Crown_Fires.m -% -% Read the Crown_Fires _devc.csv files and determine the rate of spread based on the time history of front position. -% Write the results to a file that will be plotted via dataplot.m - -close all -clear all - -outdir = '../../../out/Crown_Fires/'; -file_name = dir([outdir,'*_cat_devc.csv']); -n_files = length(file_name); - -for i=1:n_files; - - M = importdata([outdir file_name(i).name],',',2); - indices = find(700<=M.data(:,2) & M.data(:,2)<=900 & M.data(:,1)>30 & M.data(:,1)<300); - - wind_speed(i) = mean(M.data(indices,3)); - p = polyfit(M.data(indices,1),M.data(indices,2),1); - slope(i) = p(1); - - clear indices M - -end - -fid = fopen([outdir 'ROS.csv'],'wt','n'); -fprintf(fid,'%s\n','km/h,m/min'); -fprintf(fid,'%s\n','U,ROS'); -for i=1:n_files - fprintf(fid,'%4.1f,%6.2f\n',3.6*wind_speed(i),60*slope(i)); -end -fclose(fid); - diff --git a/Utilities/Matlab/scripts/FM_Burner.m b/Utilities/Matlab/scripts/FM_Burner.m deleted file mode 100644 index 6dffa663e7f..00000000000 --- a/Utilities/Matlab/scripts/FM_Burner.m +++ /dev/null @@ -1,77 +0,0 @@ -% McGrattan -% 7-30-2018 -% FM_Burner.m -% -% Read and process FDS output files for FM_Burner cases - -close all -clear all - -outdir = '../../../out/FM_Burner/'; - -fuel_name = {'C2H4','C3H6','C3H8','CH4'}; -res_name = {'2cm','1cm','5mm'}; - -for i_fuel=1:4; - - for fds_resolution=1:3; - - DEV = importdata([outdir,'FM_15cm_Burner_',fuel_name{i_fuel},'_',res_name{fds_resolution},'_devc.csv'],',',2); - HRR = importdata([outdir,'FM_15cm_Burner_',fuel_name{i_fuel},'_',res_name{fds_resolution},'_hrr.csv'],',',2); - - Time_FDS = DEV.data(:,find(strcmp(DEV.colheaders,'Time'))); - XO2_FDS = DEV.data(:,find(strcmp(DEV.colheaders,'XO2'))); - Qdot_FDS = HRR.data(:,find(strcmp(HRR.colheaders,'HRR'))); - Qrad_FDS = HRR.data(:,find(strcmp(HRR.colheaders,'Q_RADI'))); - ntp = length(Time_FDS); - - fid = fopen([outdir,'FM_15cm_Burner_',fuel_name{i_fuel},'_',res_name{fds_resolution},'.csv'],'wt','n'); - fprintf(fid,'%s\n','XO2,eta,Chi_R'); - for ii=1:ntp - fprintf(fid,'%5.3f,%6.2f,%6.2f\n',XO2_FDS(ii),Qdot_FDS(ii)/max(Qdot_FDS),max(0,-Qrad_FDS(ii)/max(0.001,Qdot_FDS(ii)))); - end - fclose(fid); - - end -end - - -clear all - -outdir = '../../../out/FM_Burner/'; -O2_name = {'20p9','19p0','16p8','15p2'}; -res_name = {'2cm','1cm','5mm'}; - -for i_O2=1:4; - - for fds_resolution=1:3; - - HRR = importdata([outdir,'FM_15cm_Burner_C2H4_',O2_name{i_O2},'_',res_name{fds_resolution},'_hrr.csv'],',',2); - - Time_FDS = HRR.data(:,find(strcmp(HRR.colheaders,'Time'))); - Qdot_FDS = HRR.data(:,find(strcmp(HRR.colheaders,'HRR'))); - Qrad_FDS = HRR.data(:,find(strcmp(HRR.colheaders,'Q_RADI'))); - ntp = length(Time_FDS); - - chi_r = max(0,-Qrad_FDS./max(0.001,Qdot_FDS)); - - fid = fopen([outdir,'FM_15cm_Burner_C2H4_',O2_name{i_O2},'_',res_name{fds_resolution},'_chir.csv'],'wt','n'); - fprintf(fid,'%s\n','Time,Chi_r'); - for ii=2:ntp - fprintf(fid,'%5.3f,%6.3f\n',Time_FDS(ii),chi_r(ii)); - end - fclose(fid); - - end -end - -% THIS DATA NOW STORED IN MACFP REPO - -% expdir = '../../../exp/Submodules/macfp-db/Extinction/FM_Burner/Experimental_Data/Radiation_global/'; - -% CHIR = importdata([expdir,'Radiant_fraction.csv'],',',1); -% rfid = fopen([expdir,'Radiant_fraction2.csv'],'wt','n'); -% fprintf(rfid,'%s\n','Time,20p9 percent,19p0 percent,17p0 percent,15p0 percent'); -% fprintf(rfid,'%5.3f,%6.3f,%6.3f,%6.3f,%6.3f\n', 0.,CHIR.data(1:4,2)); -% fprintf(rfid,'%5.3f,%6.3f,%6.3f,%6.3f,%6.3f\n',1000.,CHIR.data(1:4,2)); -% fclose(rfid); diff --git a/Utilities/Matlab/scripts/FM_Vertical_Wall_Flames.m b/Utilities/Matlab/scripts/FM_Vertical_Wall_Flames.m deleted file mode 100644 index 46317d2726c..00000000000 --- a/Utilities/Matlab/scripts/FM_Vertical_Wall_Flames.m +++ /dev/null @@ -1,77 +0,0 @@ -% McGrattan -% 3-15-2017 -% FM_Vertical_Wall_Flames.m -% -% Reads the _devc.csv file and writes output in a form appropriate for dataplot.m - -outdir = '../../../out/FM_Vertical_Wall_Flames/'; - -nts = 32; - -M = importdata([outdir,'propylene_devc.csv'],',',2); - -% Heat flux data - -H = cell(2,4); -H(1,:) = {'m' 'kW/m2' 'kW/m2' 'kW/m2'}; -H(2,:) = {'z' 'HF-14' 'HF-18' 'HF-20'}; - -fid = fopen([outdir,'propylene_hf.csv'],'wt','n'); -fprintf(fid,'%s,%s,%s,%s\n',H{1,:}); -fprintf(fid,'%s,%s,%s,%s\n',H{2,:}); -for i=1:40 - z = 0.05*i-0.025; - fprintf(fid,'%5.3f,%6.2f,%6.2f,%6.2f\n',z,M.data([8 10 11],1+i)); -end -fclose(fid); - -clear fid H - -% Temperature data - -H = cell(2,6); -H(1,:) = {'mm' 'K' 'K' 'K' 'K' 'K'}; -H(2,:) = {'x' 'T-10' 'T-12' 'T-14' 'T-18' 'T-20'}; - -fid = fopen([outdir,'propylene_tc.csv'],'wt','n'); -fid2 = fopen([outdir,'propylene_tmp.csv'],'wt','n'); -fprintf(fid,'%s,%s,%s,%s,%s,%s\n',H{1,:}); -fprintf(fid,'%s,%s,%s,%s,%s,%s\n',H{2,:}); -fprintf(fid2,'%s,%s,%s,%s,%s,%s\n',H{1,:}); -fprintf(fid2,'%s,%s,%s,%s,%s,%s\n',H{2,:}); -for i=1:50 - x = 3*i-1.5; - fprintf(fid, '%5.3f,%6.2f,%6.2f,%6.2f,%6.2f,%6.2f\n',x,M.data([5 6 7 9 10],41+i)+273.15); - fprintf(fid2,'%5.3f,%6.2f,%6.2f,%6.2f,%6.2f,%6.2f\n',x,M.data([5 6 7 9 10],345+i)+273.15); -end -fclose(fid); -fclose(fid2); - -clear fid fid2 H - -% Soot data - -H = cell(2,6); -H(1,:) = {'g/m2/s' 'mm' 'mm' 'mm' 'mm' 'mm'}; -H(2,:) = {'mdot' '365 mm' '527 mm' '771 mm' '1022 mm' '1317 mm'}; - -threshold = 0.0025; -fid = fopen([outdir,'propylene_soot.csv'],'wt','n'); -fprintf(fid,'%s,%s,%s,%s,%s,%s\n',H{1,:}); -fprintf(fid,'%s,%s,%s,%s,%s,%s\n',H{2,:}); -for i=1:nts - for j=1:5 - for k=1:49 - if (M.data(i+1,92+50*(j-1)+k-1)>=threshold) && (M.data(i+1,92+50*(j-1)+k)t_start{j}(i) & time 6 - error('myApp:argChk','Unexpected number of arguments') -end - -% Allocate space for arrays -hu = zeros(length(u),4); -hv = zeros(length(u),4); - -% Define arrow geometry and plot arrows -for i = 1:length(u) - hu(i,1) = x(i)+u(i)-alpha*(u(i)+beta*(v(i)+eps)); - hu(i,2) = x(i)+u(i); - hu(i,3) = x(i)+u(i)-alpha*(u(i)-beta*(v(i)+eps)); - hu(i,4) = x(i)+u(i)-alpha*(u(i)+beta*(v(i)+eps)); - hv(i,1) = y(i)+v(i)-alpha*(v(i)-beta*(u(i)+eps)); - hv(i,2) = y(i)+v(i); - hv(i,3) = y(i)+v(i)-alpha*(v(i)+beta*(u(i)+eps)); - hv(i,4) = y(i)+v(i)-alpha*(v(i)-beta*(u(i)+eps)); - fill(hu(i,:),hv(i,:),[0.3 0.7 1]); -end - -%-------------------------------------------------------------------------% -%-------------------------------------------------------------------------% \ No newline at end of file diff --git a/Utilities/Matlab/scripts/ashrae_7.m b/Utilities/Matlab/scripts/ashrae_7.m deleted file mode 100644 index ea24563994a..00000000000 --- a/Utilities/Matlab/scripts/ashrae_7.m +++ /dev/null @@ -1,56 +0,0 @@ -%Roger Wang -%7-20-11 -%ashrae_7.m - -close all -clear all - -infile{1} = '../../Verification/HVAC/ashrae_7_exp.csv'; -infile{2} = '../../Verification/HVAC/ashrae7_fixed_flow_devc.csv'; -infile{3} = '../../Verification/HVAC/ashrae7_quadratic_devc.csv'; -infile{4} = '../../Verification/HVAC/ashrae7_table_devc.csv'; - -label{1} = 'Experiment'; -label{2} = 'Fixed Flow & '; -label{3} = 'Quadratic & '; -label{4} = 'Table & '; - -duct{1} = '1'; -duct{2} = '2'; -duct{3} = '3'; -duct{4} = '4'; -duct{5} = '5'; -duct{6} = '56'; -duct{7} = '6'; -duct{8} = '7'; - -M = csvread(infile{1},6,1); - -for n = 2:4 - if ~exist(infile{n}) - display(['Error: File ',infile{n},' does not exist. Skipping case.']) - return - end - m = csvread(infile{n},2,1); - pressure(n,1:8) = m(length(m(:,1)),1:8); -end - -filename = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/ashrae_7.tex'; -fid = fopen(filename, 'wt'); - -fprintf(fid,'%s\n','\begin{center}'); -fprintf(fid,'%s\n','\begin{tabular}{|c|c|c|c|c|c|c|c|c|} \hline'); -fprintf(fid, '%s', 'Duct Number & '); -fprintf(fid, '%s\n', '1 & 2 & 3 & 4 & 5 & 56 & 6 & 7 \\ \hline'); -fprintf(fid, '%s\n', 'Experiment &'); -fprintf(fid, '%6.3f & %6.3f & %6.3f & %6.3f & %6.3f & %6.3f & %6.3f & %6.3f %s\n', M,'\\'); -for i = 2:4 - fprintf(fid, '%s', label{i}); - fprintf(fid, '%6.3f & %6.3f & %6.3f & %6.3f & %6.3f & %6.3f & %6.3f & %6.3f %s\n', pressure(i,1:8),'\\'); -end -fprintf(fid,'%s\n','\hline'); -fprintf(fid,'%s\n','\end{tabular}'); -fprintf(fid,'%s\n','\end{center}'); - - - \ No newline at end of file diff --git a/Utilities/Matlab/scripts/atmospheric_boundary_layer.m b/Utilities/Matlab/scripts/atmospheric_boundary_layer.m deleted file mode 100644 index 274eedcd56f..00000000000 --- a/Utilities/Matlab/scripts/atmospheric_boundary_layer.m +++ /dev/null @@ -1,132 +0,0 @@ -% McGrattan -% 08-17-2017 -% atmospheric_boundary_layer.m -% -% Atmospheric Boundary Layer profiles, based on M-O theory as described in -% "Falcon Series Data Report", GRI-89/0138, June 1990. -% These plots are used as illustrations in the FDS User's Guide. - -clear all -close all - -plot_style - -basein ='../../Verification/Atmospheric_Effects/atmospheric_boundary_layer'; -baseout='../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/atmospheric_boundary_layer'; - -for i=1:4 - -datafile=[basein '_' num2str(i,'%1d\n')]; -outfile =[baseout '_' num2str(i,'%1d\n')]; - -M1 = importdata([datafile,'_devc.csv'],',',2); -M2 = importdata([datafile,'_line.csv'],',',2); - -u_r = M1.data(end,2); -T_r = M1.data(end,3) + 273.15; - -rho_0 = 1.2; -g = 9.81; -cp = 1005; -kappa = 0.41; -p_0 = 100000; -qdot = {50 -50 25 -25}; -z_0 = {0.25 0.25 0.125 0.125}; -T_low = {15 15 15 15}; -T_high = {25 25 25 25}; -u_high = {20 20 10 15}; -fvec = {0.01 0.01 0.002 0.005}; -s = {8.15 8.15 4.075 4.075}; - -theta_0 = T_r; -z_r = 10.; -p_r = p_0-rho_0*g*(z_r-z_0{i}); -theta_r = T_r*(p_0/p_r)^0.285; -u_star = kappa*u_r/log(z_r/z_0{i}); -L = -u_star^3*theta_0*rho_0*cp/(g*kappa*qdot{i}); -theta_star = u_star^2*theta_0/(g*kappa*L); - -z = [z_0{i} 10*z_0{i} 1 2 3 4 5 6 7 8 9 10 15 20 25 30 50 100]; - -f1=figure; -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -if L<0; -x = (1-16*z/L).^0.25; -psi_m = 2*log((1+x)/2) + log((1+x.^2)/2) - 2*atan(x) + pi/2; -psi_h = 2*log((1+x.^2)/2); -else -psi_m = -5*z/L; -psi_h = psi_m; -end - -u = (u_star/kappa)*(log(z/z_0{i}) - psi_m); -theta = theta_0 + (theta_star/kappa)*(log(z/z_0{i}) - psi_h); -T = theta.*(p_0./(p_0-rho_0*g*(z-z_0{i}))).^-0.285; - -T = T + (theta_0-T(12)); - -ERROR = abs(u(end)-M2.data(end,2)); -if ERROR>2. - display(['Matlab Warning: atmospheric_boundary_layer Case ',num2str(i),' velocity out of tolerance. ERROR = ',num2str(ERROR),' m/s']) -end - -plot(u,z,'ko'); hold on -plot(M2.data(:,2),M2.data(:,1),'k-'); hold off -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Title_Font_Size) -axis([0 u_high{i} 0 100]) -text(.05,.90,['Case ' num2str(i,'%1d\n')],'FontName',Font_Name,'FontSize',Label_Font_Size,'Interpreter','LaTeX','Units','normalized') - -text(.05,.80,['$F=' num2str(fvec{i},'%5.3f\n') '\; \hbox{Pa/m}$'],'FontName',Font_Name,'FontSize',Label_Font_Size,'Interpreter','LaTeX','Units','normalized') -text(.05,.70,['$s=' num2str(s{i},'%5.2f\n') '\; \hbox{m}$'],'FontName',Font_Name,'FontSize',Label_Font_Size,'Interpreter','LaTeX','Units','normalized') -text(.05,.60,['$\dot{q}_{\rm c}^{\prime \prime}=' num2str(qdot{i}/1000,'%5.3f\n') '\; \hbox{kW/m}^2$'],'FontName',Font_Name,'FontSize',Label_Font_Size,'Interpreter','LaTeX','Units','normalized') - -text(.05,.50,['$u(' num2str(z_r,'%2.0f\n') '\; \hbox{m})=' num2str(u_r,'%4.1f\n') '\; \hbox{m/s}$'],'FontName',Font_Name,'FontSize',Label_Font_Size,'Interpreter','LaTeX','Units','normalized') -text(.05,.40,['$L=' num2str(L,'%4.0f\n') '$ m'],'FontName',Font_Name,'FontSize',Label_Font_Size,'Interpreter','LaTeX','Units','normalized') -text(.05,.30,['$z_0=' num2str(z_0{i},'%5.3f\n') '$ m'],'FontName',Font_Name,'FontSize',Label_Font_Size,'Interpreter','LaTeX','Units','normalized') -xlabel('Velocity (m/s)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter) -ylabel('Height (m)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter) -legend({'M-O Theory','FDS'}, 'Location', 'SouthEast'); - -git_file = [datafile, '_git.txt']; -addverstr(gca,git_file,'linear') - -set(f1,'Visible',Figure_Visibility); -set(f1,'Units',Paper_Units); -set(f1,'PaperUnits',Paper_Units); -set(f1,'PaperSize',[Paper_Width Paper_Height]); -set(f1,'Position',[0 0 Paper_Width Paper_Height]); -print(f1,'-dpdf',[outfile '_vel']) - -f2=figure; -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -ERROR = abs(T(end)-273.15-M2.data(end,3)); -if ERROR>1.0 - display(['Matlab Warning: atmospheric_boundary_layer Case ',num2str(i),' temperature out of tolerance. ERROR = ',num2str(ERROR),' K']) -end - -plot(T-273.15,z,'ko'); hold on -plot(M2.data(:,3),M2.data(:,1),'k-'); hold off -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Title_Font_Size) -axis([T_low{i} T_high{i} 0 100]) -text(.05,.90,['Case ' num2str(i,'%1d\n')],'FontName',Font_Name,'FontSize',Label_Font_Size,'Interpreter','LaTeX','Units','normalized') -text(.05,.80,['$T(' num2str(z_r,'%2.0f\n') '\; \hbox{m})=' num2str(T_r-273,'%3.1f\n') '\;^\circ$C'],'FontName',Font_Name,'FontSize',Label_Font_Size,'Interpreter','LaTeX','Units','normalized') -xlabel('Temperature (°C)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter) -ylabel('Height (m)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter) -legend({'M-O Theory','FDS'}, 'Location', 'SouthWest'); - -addverstr(gca,git_file,'linear') - -set(f2,'Visible',Figure_Visibility); -set(f2,'Units',Paper_Units); -set(f2,'PaperUnits',Paper_Units); -set(f2,'PaperSize',[Paper_Width Paper_Height]); -set(f2,'Position',[0 0 Paper_Width Paper_Height]); -print(f2,'-dpdf',[outfile '_tmp']) - -end diff --git a/Utilities/Matlab/scripts/burke_schumann.m b/Utilities/Matlab/scripts/burke_schumann.m deleted file mode 100644 index 88004698ce1..00000000000 --- a/Utilities/Matlab/scripts/burke_schumann.m +++ /dev/null @@ -1,142 +0,0 @@ -%----------------------- -% C Weinschenk -% Verification of Mixture Fraction (Species,Temp,Pres) -% Fuel: Methane -% 9/2012 -%----------------------- - -clear all -close all - -addpath('../../Verification/Species/') - -%----------------------- -% Read in FDS Data File -%----------------------- - -if ~exist('burke_schumann_devc.csv') - display(['Error: File ../../Verification/Species/burke_schumann_devc.csv does not exist. Skipping case.']) - return -end -Burke_Schumann_Data=importdata('burke_schumann_devc.csv'); -burke(:,:)=Burke_Schumann_Data.data; % data - -for i=1:15 - temperature(:,i) = burke(:,11*i-9)+273.15; % temperature [K] - rho(:,i) = burke(:,11*i-8); % density [kg/m^3] - h(:,i) = burke(:,11*i-7); % specific enthalpy [kJ/kg] - hrrpuv(:,i)=burke(:,11*i-6); % heat release rate per unit volume [kW] - pressure(:,i) = burke(:,11*i-5)+101325; % abolute pressure [Pa] - mix_frac(:,i) = burke(:,11*i-4); % mixture fraction - o2(:,i) = burke(:,11*i-3); % mass fraction o2 - ch4(:,i) = burke(:,11*i-2); % mass fraction ch4 - h2o(:,i) = burke(:,11*i-1); % mass fraction h2o - co2(:,i) = burke(:,11*i); % mass fraction co2 - n2(:,i) = burke(:,11*i+1); % mass fraction n2 -end - -n2_o2_ratio = n2(1,1)/o2(1,1); % initial o2/n2 ratio - -for i=1:length(mix_frac) - ox(:,i) = o2(:,i) + n2_o2_ratio*o2(:,i); % O2 plus N2 that started with O2 - prod(:,i) = h2o(:,i) + co2(:,i) + (n2(:,i)-n2_o2_ratio*o2(:,i)); % CO2 + H2O + N2 in products -end - -%----------------------- -% Calculate Expected Species and Temperature Profiles -%----------------------- - -volume = 0.001; % volume of each "reactor" [m^3] -temp_0 = temperature(1,1); % initial temperature [K] -density = rho(1,5); % stoichiometric density [kg/m^3] -R = 8.3145; % gas constnat [J/mol K] -mass = rho(1,:) * volume; % mass [kg] - -%------------- -% vector key -% (1) = nitrogen -% (2) = methane -% (3) = oxygen -% (4) = carbon dioxide -% (5) = water vapor -%------------- - -y_MW = [28.0134; 16.042460; 31.9988; 44.0095; 18.015280]; % molecular weight [g/mol] -y_hf = [0.0; -74873; 0.0; 0.0; 0.0]; % heat of formation all zero except fuel [J/mol] -yf0 = [n2(1,:); ch4(1,:); o2(1,:); co2(1,:); h2o(1,:)]; % intial mass fractions @ stoichiometric -yff = [n2(end,:); ch4(end,:); o2(end,:); co2(end,:); h2o(end,:)]; % final mass fractions -for i=1:length(yf0) - N0(:,i) = (1000*volume*density*yf0(:,i))./(y_MW); % initial moles @ stoichiometric - Nf(:,i) = (1000*volume*density*yff(:,i))./(y_MW); % final moles - mean_mw_f(:,i) = sum(y_MW.*(Nf(:,i)./sum(Nf(:,i)))); % mole average molecular weight - Rw(i) = (R./mean_mw_f(i))*1000; % ideal gas constant [J/kg/K] -end - -hc = -y_hf(2)/y_MW(2)*1000; % heat of combustion [J/kg] -cp = 1000; % specific heat [J/kg/K] set constant for all species -cv = cp - Rw; -%----------------------- -% Calculate State Relationships -%----------------------- -z_st = yf0(2,5); -f = mix_frac(1,:); - -for i =1:length(f) - if f(i) > z_st && f(i) <= 1 - Yf(i) = (f(i)-z_st)/(1-z_st); - Yo2(i) = 0; - Yp(i) = (1-f(i))/(1-z_st); - T_calc(i) = f(i)*(-(z_st/(1-z_st))*(hc/cv(i)))+temp_0+(z_st)/((1-z_st)*cv(i))*hc; - elseif f(i) >= 0 && f(i) < z_st - Yf(i) = 0; - Yo2(i) = 1 - f(i)/z_st; - Yp(i) = f(i)/z_st; - T_calc(i) = f(i)*((hc)/(cv(i)))+temp_0; - else - Yf(i) = 0; - Yo2(i) = 0; - Yp(i) = 1; - T_calc(i) = yf0(2,5)*(hc/cv(i))+temp_0; - end -end - -T_calc_norm = (T_calc-temp_0)./(T_calc(5)-temp_0); % normalized expected temperature -FDS_temp_norm = (temperature(end,:)-temp_0)./(T_calc(5)-temp_0); % normalized FDS temperature - -%------------------------------------------------ -% Write FDS and Expected Data to CSV Files -%------------------------------------------------ - -for i=1:length(mix_frac) - burke_expected(i,1) = mix_frac(1,i); - burke_expected(i,2) = T_calc_norm(i); - burke_expected(i,3) = Yf(i); - burke_expected(i,4) = Yo2(i); - burke_expected(i,5) = Yp(i); -end - -header1 = {'Mixture_Fraction','Temperature','Fuel','Ox','Prod'}; -filename1 = '../../Verification/Species/burke_schumann_expected.csv'; -fid = fopen(filename1,'wt'); -fprintf(fid,'%s, %s, %s, %s, %s\n',header1{:}); -for j=1:length(mix_frac) - fprintf(fid,'%f, %f, %f, %f, %f\n',burke_expected(j,:)); -end -fclose(fid); - -for i=1:length(mix_frac) - burke_FDS(i,1) = mix_frac(1,i); - burke_FDS(i,2) = FDS_temp_norm(i); - burke_FDS(i,3) = ch4(end,i); - burke_FDS(i,4) = ox(end,i); - burke_FDS(i,5) = prod(end,i); -end - -header1 = {'Mixture_Fraction','FDS_Temperature','FDS_Fuel','FDS_Ox','FDS_Prod'}; -filename1 = '../../Verification/Species/burke_schumann_FDS.csv'; -fid = fopen(filename1,'wt'); -fprintf(fid,'%s, %s, %s, %s, %s\n',header1{:}); -for j=1:length(mix_frac) - fprintf(fid,'%f, %f, %f, %f, %f\n',burke_FDS(j,:)); -end -fclose(fid); \ No newline at end of file diff --git a/Utilities/Matlab/scripts/cat_propane_depo.m b/Utilities/Matlab/scripts/cat_propane_depo.m deleted file mode 100644 index b92ea40befd..00000000000 --- a/Utilities/Matlab/scripts/cat_propane_depo.m +++ /dev/null @@ -1,103 +0,0 @@ -% Overholt -% 6-13-2012 -% cat_propane_depo.m -% -% Concatenates columns from Propane flame deposition FDS cases (/Verification/Aerosols) - -% Condensed phase aerosol - -clear all - -outdir = '../../Verification/Aerosols/'; - -skip_case = 0; -if ~exist([outdir,'propane_flame_deposition_devc.csv']) - display(['Error: File ',[outdir,'propane_flame_deposition_devc.csv'],' does not exist. Skipping case.']) - skip_case = 1; -end -if ~exist([outdir,'propane_flame_deposition_none_devc.csv']) - display(['Error: File ',[outdir,'propane_flame_deposition_none_devc.csv'],' does not exist. Skipping case.']) - skip_case = 1; -end -if ~exist([outdir,'propane_flame_deposition_gravitational_devc.csv']) - display(['Error: File ',[outdir,'propane_flame_deposition_gravitational_devc.csv'],' does not exist. Skipping case.']) - skip_case = 1; -end -if ~exist([outdir,'propane_flame_deposition_thermophoretic_devc.csv']) - display(['Error: File ',[outdir,'propane_flame_deposition_thermophoretic_devc.csv'],' does not exist. Skipping case.']) - skip_case = 1; -end -if ~exist([outdir,'propane_flame_deposition_turbulent_devc.csv']) - display(['Error: File ',[outdir,'propane_flame_deposition_turbulent_devc.csv'],' does not exist. Skipping case.']) - skip_case = 1; -end -if skip_case - return -end - -M1 = importdata([outdir,'propane_flame_deposition_devc.csv'],',',2); -M2 = importdata([outdir,'propane_flame_deposition_none_devc.csv'],',',2); -M3 = importdata([outdir,'propane_flame_deposition_gravitational_devc.csv'],',',2); -M4 = importdata([outdir,'propane_flame_deposition_thermophoretic_devc.csv'],',',2); -M5 = importdata([outdir,'propane_flame_deposition_turbulent_devc.csv'],',',2); - -H1 = cell(2,6); -H1(1,:) = {'s' 'kg' 'kg' 'kg' 'kg' 'kg'}; -H1(2,:) = {'Time' 'depo_all' 'depo_none' 'depo_gravitational' 'depo_thermophoretic' 'depo_turbulent'}; - -D1 = [M1.data(:,:), M2.data(:,2), M3.data(:,2), M4.data(:,2), M5.data(:,2)]; - -fid = fopen([outdir,'propane_flame_deposition_cat_wall.csv'],'wt','n'); - -fprintf(fid,'%s, %s, %s, %s, %s, %s\n',H1{1,:}); -fprintf(fid,'%s, %s, %s, %s, %s, %s\n',H1{2,:}); -for i=1:numel(M1.data(:,1)) - fprintf(fid,'%f, %f, %f, %f, %f, %f\n',D1(i,:)); -end -fclose(fid); - -% Gas phase aerosol - -N1 = importdata([outdir,'propane_flame_deposition_mass.csv'],',',2); -N2 = importdata([outdir,'propane_flame_deposition_none_mass.csv'],',',2); -N3 = importdata([outdir,'propane_flame_deposition_gravitational_mass.csv'],',',2); -N4 = importdata([outdir,'propane_flame_deposition_thermophoretic_mass.csv'],',',2); -N5 = importdata([outdir,'propane_flame_deposition_turbulent_mass.csv'],',',2); - -H2 = cell(2,6); -H2(1,:) = {'s' 'kg' 'kg' 'kg' 'kg' 'kg'}; -H2(2,:) = {'Time' 'depo_all' 'depo_none' 'depo_gravitational' 'depo_thermophoretic' 'depo_turbulent'}; - -D2 = [N1.data(:,1), N1.data(:,8), N2.data(:,8), N3.data(:,8), N4.data(:,8), N5.data(:,8)]; - -fid = fopen([outdir,'propane_flame_deposition_cat_gas.csv'],'wt','n'); - -fprintf(fid,'%s, %s, %s, %s, %s, %s\n',H2{1,:}); -fprintf(fid,'%s, %s, %s, %s, %s, %s\n',H2{2,:}); -for i=1:numel(N1.data(:,1)) - fprintf(fid,'%f, %f, %f, %f, %f, %f\n',D2(i,:)); -end -fclose(fid); - -% Total aerosol (sum of gas plus wall) - -S1 = interp1(M1.data(:,1), M1.data(:,2), N1.data(:,1)) + N1.data(:,8); -S2 = interp1(M2.data(:,1), M2.data(:,2), N2.data(:,1)) + N2.data(:,8); -S3 = interp1(M3.data(:,1), M3.data(:,2), N3.data(:,1)) + N3.data(:,8); -S4 = interp1(M4.data(:,1), M4.data(:,2), N4.data(:,1)) + N4.data(:,8); -S5 = interp1(M5.data(:,1), M5.data(:,2), N5.data(:,1)) + N5.data(:,8); - -H3 = cell(2,6); -H3(1,:) = {'s' 'kg' 'kg' 'kg' 'kg' 'kg'}; -H3(2,:) = {'Time' 'depo_all' 'depo_none' 'depo_gravitational' 'depo_thermophoretic' 'depo_turbulent'}; - -D3 = [N1.data(:,1), S1, S2, S3, S4, S5]; - -fid = fopen([outdir,'propane_flame_deposition_cat_total.csv'],'wt','n'); - -fprintf(fid,'%s, %s, %s, %s, %s, %s\n',H3{1,:}); -fprintf(fid,'%s, %s, %s, %s, %s, %s\n',H3{2,:}); -for i=1:numel(S1(:,1)) - fprintf(fid,'%f, %f, %f, %f, %f, %f\n',D3(i,:)); -end -fclose(fid); diff --git a/Utilities/Matlab/scripts/extinction.m b/Utilities/Matlab/scripts/extinction.m deleted file mode 100644 index d26fac8cd5e..00000000000 --- a/Utilities/Matlab/scripts/extinction.m +++ /dev/null @@ -1,315 +0,0 @@ -%----------------------- -% C Weinschenk -% Verification of Extinction Model -% Fuel: Methane -% 6/2012 -%----------------------- - -clear all -close all - -addpath('../../Verification/Extinction/') - -%----------------------- -% Initialize species -%----------------------- - -%------------- -% vector key -% (1) = nitrogen -% (2) = methane -% (3) = oxygen -% (4) = carbon dioxide -% (5) = water vapor -%------------- -T_crit = 1780; % critical flame temperature for methane, Beyler T(OI) [K] -Y_O2_0 = 0.156; % Beyler OI converted to a mass fraction -mass = 0.1; % mass [kg] -volume = 0.001; % volume [m^3] -R = 8.3145; % gas constant [J/mol K] - -mult = 1.; -seed = 0.0029:0.005744:0.0546; % array of fuel mass fractions -seed = seed/mult; -for ii = 1:10 - for jj = 1:10 - fuel_seed(jj+10*(ii-1)) = seed(ii); - end -end - -seed2 = 300:175:2035; % array of temperatures (K) -for ii = 1:10 - for jj = 1:10 - temp_seed(jj+10*(ii-1)) = seed2(jj); - end -end - -num_samp = 100; % number of input sets -ignite=zeros(num_samp,2); -extinct_o2=zeros(num_samp,2); -fds_ext_o2=zeros(num_samp,2); -extinct_fuel=zeros(num_samp,2); - -nu = [0; -1; -2; 1; 2]; % stoichiometric coefficients -y_MW = [28.0134; 16.042460; 31.9988; 44.0095; 18.01528]; % [g/mol] -y_hf = [0.0; -74873; 0.0; -393522; -241826]; % [J/mol] -pres_0 = 1.013253421185575e+05; % initial presure [Pa] - -o2_mult = 4.*mult; - -for i=1:num_samp - phi_fuel(i) = fuel_seed(i); % initial mass fraction of fuel - phi(i,:) = [(1-(o2_mult+1)*fuel_seed(i)); fuel_seed(i); o2_mult*fuel_seed(i); 0.0; 0.0]; % initial mass fractions of all species - T0(i) = temp_seed(i); % initial temperature [K] -end - -%----------------------- -% Determine max change in species -%----------------------- -for jj = 1:num_samp - nu_mw_sum = 0; - phi_sum = 0; - - for i=1:length(nu) - if nu(i) < 0 - nu_mw_sum = nu_mw_sum + abs(nu(i))*y_MW(i); - phi_sum = phi_sum + phi(jj,i); - end - end - - for i=1:length(nu) - if nu(i) < 0 - phi_st(i) = abs(nu(i))*y_MW(i)/nu_mw_sum; - phi_r(i) = phi(jj,i)/phi_sum; - end - end - - RR = phi_r./phi_st; - ILR = 2; - for i=3:length(nu) - if nu(i) < 0 - if RR(i) < RR(ILR) - ILR = i; - end - end - end - - for i=1:length(nu) - d_phi(jj,i) = nu(i)*y_MW(i)/(abs(nu(ILR))*y_MW(ILR))*phi(jj,ILR); - end - phi_new(jj,:) = phi(jj,:) + d_phi(jj,:); - - %----------------------- - % Determine Extinction - %----------------------- - %--------- - %NOTE: coefficients were found from NIST Webbook - %--------- - %reference temperature coeffs - coeff_ref(:,1) = [28.98641;1.853978;-9.647459;16.63537;0.000117;-8.671914;0.0]; - coeff_ref(:,2) = [-0.703029;108.4773;-42.52157;5.862788;0.678565;-76.84376;-74.87310]; - coeff_ref(:,3) = [31.32234;-20.23531;57.86644;-36.50624;-0.007374;-8.903471;0.0]; - coeff_ref(:,4) = [24.99735;55.18696;-33.69137;7.948387;-0.136638;-403.6075;-393.5224]; - coeff_ref(:,5) = [30.09200;6.832514;6.793435;-2.534480;0.082139;-250.8810;-241.8264]; - - %initial temperature coeffs - %nitrogen cp coeffs [J/mol K] - if T0(jj) <=500 - coeff0(:,1) = [28.98641;1.853978;-9.647459;16.63537;0.000117;-8.671914;0.0]; - elseif 500 < T0(jj) <= 2000 - coeff0(:,1) = [19.50583;19.88705;-8.598535;1.369784;0.527601;-4.935202;0.0]; - else - coeff0(:,1) = [35.51872;1.128728;-0.196103;0.014662;-4.553760;-18.97091;0.0]; - end - %methane cp coeffs [J/mol K] - if T0(jj) <= 1300 - coeff0(:,2) = [-0.703029;108.4773;-42.52157;5.862788;0.678565;-76.84376;-74.87310]; - else - coeff0(:,2) = [85.81217;11.26467;-2.114146;0.138190;-26.42221;-153.5327;-74.87310]; - end - %oxygen cp coeffs [J/mol K] - if T0(jj) <=700 - coeff0(:,3) = [31.32234;-20.23531;57.86644;-36.50624;-0.007374;-8.903471;0.0]; - elseif 700 < T0(jj) <= 2000 - coeff0(:,3) = [30.03235;8.772972;-3.988133;0.788313;-0.741599;-11.32468;0.0]; - else - coeff0(:,3) = [20.91111;10.72071;-2.020498;0.146449;9.245722;5.337651;0.0]; - end - %carbon dooxide cp coeffs [J/mol K] - if T0(jj) <= 1200 - coeff0(:,4) = [24.99735;55.18696;-33.69137;7.948387;-0.136638;-403.6075;-393.5224]; - else - coeff0(:,4) = [58.16639;2.720074;-0.492289;0.038844;-6.447293;-425.9186;-393.5224]; - end - %water vapor cp coeffs [J/mol K] - if T0(jj) <= 1700 - coeff0(:,5) = [30.09200;6.832514;6.793435;-2.534480;0.082139;-250.8810;-241.8264]; - else - coeff0(:,5) = [41.96246;8.622053;-1.499780;0.098199;-11.15764;-272.1797;-241.8264]; - end - - %critical temperature coeffs - %nitrogen cp coeffs [J/mol K] - if T_crit <=500 - coeff(:,1) = [28.98641;1.853978;-9.647459;16.63537;0.000117;-8.671914;0.0]; - elseif 500 < T_crit <= 2000 - coeff(:,1) = [19.50583;19.88705;-8.598535;1.369784;0.527601;-4.935202;0.0]; - else - coeff(:,1) = [35.51872;1.128728;-0.196103;0.014662;-4.553760;-18.97091;0.0]; - end - %methane cp coeffs [J/mol K] - if T_crit <= 1300 - coeff(:,2) = [-0.703029;108.4773;-42.52157;5.862788;0.678565;-76.84376;-74.87310]; - else - coeff(:,2) = [85.81217;11.26467;-2.114146;0.138190;-26.42221;-153.5327;-74.87310]; - end - %oxygen cp coeffs [J/mol K] - if T_crit <=700 - coeff(:,3) = [31.32234;-20.23531;57.86644;-36.50624;-0.007374;-8.903471;0.0]; - elseif 700 < T_crit <= 2000 - coeff(:,3) = [30.03235;8.772972;-3.988133;0.788313;-0.741599;-11.32468;0.0]; - else - coeff(:,3) = [20.91111;10.72071;-2.020498;0.146449;9.245722;5.337651;0.0]; - end - %carbon dooxide cp coeffs [J/mol K] - if T_crit <= 1200 - coeff(:,4) = [24.99735;55.18696;-33.69137;7.948387;-0.136638;-403.6075;-393.5224]; - else - coeff(:,4) = [58.16639;2.720074;-0.492289;0.038844;-6.447293;-425.9186;-393.5224]; - end - %water vapor cp coeffs [J/mol K] - if T_crit <= 1700 - coeff(:,5) = [30.09200;6.832514;6.793435;-2.534480;0.082139;-250.8810;-241.8264]; - else - coeff(:,5) = [41.96246;8.622053;-1.499780;0.098199;-11.15764;-272.1797;-241.8264]; - end - t=T_crit/1000; - t0=T0(jj)/1000; - for i=1:5 - del_h_init(i) = 1000*(coeff0(1,i)*t0 + (1/2)*coeff0(2,i)*t0^2 + (1/3)*coeff0(3,i)*t0^3 + (1/4)*coeff0(4,i)*t0^4 - coeff0(5,i)/t0 + coeff0(6,i) - coeff0(7,i)); - del_h(i) = 1000*(coeff(1,i)*t + (1/2)*coeff(2,i)*t^2 + (1/3)*coeff(3,i)*t^3 + (1/4)*coeff(4,i)*t^4 - coeff(5,i)/t + coeff(6,i) - coeff(7,i)); - end - - Q(jj) = 0; - h = 0; - h0 = 0; - for i=1:length(y_hf) - Q(jj) = Q(jj) - y_hf(i)*d_phi(jj,i)/y_MW(i); - h0 = h0 +phi(jj,i).*del_h_init(i)/y_MW(i); - h = h + phi(jj,i).*del_h(i)/y_MW(i); - end - - if h0 + Q(jj) > h - ignite(jj,:) = [T0(jj);phi(jj,3)]; - else - extinct_o2(jj,:) = [T0(jj);phi(jj,3)]; - end -end - -%----------------------- -% Import FDS results -%----------------------- -epsilon = 1e-10; - -fds_file{1} = 'extinction_1_devc.csv'; -fds_file{2} = 'extinction_2_devc.csv'; - -X_ignite=zeros(num_samp,2); -X_fds_ignite=zeros(num_samp,2); -X_extinct_o2=zeros(num_samp,2); -X_fds_ext_o2=zeros(num_samp,2); - -for ifile=2:-1:1 - -if ~exist(fds_file{ifile}) - display('Error: File ',fds_file{ifile},' does not exist. Skipping case.') - return -end - -extinct=importdata(fds_file{ifile}); -extinct_1(:,:)=extinct.data; % data - -for i=1:100 - hrr_ext(:,i) = extinct_1(:,4*i-2); - temp_ext(:,i) = extinct_1(:,4*i-1)+273.15; - o2_ext(:,i) = extinct_1(:,4*i); - fu_ext(:,i) = extinct_1(:,4*i+1); -end - -for i=1:100 - if sum(hrr_ext(:,i)) > epsilon - fds_ignite(i,:) = [temp_ext(1,i);o2_ext(1,i)]; - fds_ext_o2(i,:) = [0 0]; - else - fds_ext_o2(i,:) = [temp_ext(1,i);o2_ext(1,i)]; - fds_ignite(i,:) = [0 0]; - end -end - -clear hrr_ext temp_ext o2_ext fu_ext - -% Simple Extinction Model - -if ifile==2 - simple_o2 = [Y_O2_0 0]; - simple_temp = [293.15 T_crit]; -else - simple_o2 = [Y_O2_0 0.0939 0]; - simple_temp = [293.15 873 873]; -end - -% Make the plot - -figure -plot_style -set(gca,'Units',Plot_Units) -set(gca,'Position',[Scat_Plot_X Scat_Plot_Y Scat_Plot_Width Scat_Plot_Height]) - -tmpm = 273; -X_simple_o2 = (simple_o2/32)./(simple_o2/32 + (1-simple_o2)/28); -X_ignite(:,2) = (ignite(:,2)/32)./(ignite(:,2)/32 + (1-ignite(:,2))/28); -X_fds_ignite(:,2) = (fds_ignite(:,2)/32)./(fds_ignite(:,2)/32 + (1-fds_ignite(:,2))/28); -X_extinct_o2(:,2) = (extinct_o2(:,2)/32)./(extinct_o2(:,2)/32 + (1-extinct_o2(:,2))/28); -X_fds_ext_o2(:,2) = (fds_ext_o2(:,2)/32)./(fds_ext_o2(:,2)/32 + (1-fds_ext_o2(:,2))/28); - -if ifile==1 % Modify expected behavior - for jj=1:num_samp - if extinct_o2(jj,1)-tmpm>600 && X_extinct_o2(jj,2)>0 ; - X_ignite(jj,2)=X_extinct_o2(jj,2); - X_extinct_o2(jj,2)=0; - ignite(jj,1)=extinct_o2(jj,1); - extinct_o2(jj,1)=0; - end - end -end - -h=plot(simple_temp-tmpm,X_simple_o2,'k',... - ignite(:,1)-tmpm,X_ignite(:,2),'rs',... - fds_ignite(:,1)-tmpm,X_fds_ignite(:,2),'r+',... - extinct_o2(:,1)-tmpm,X_extinct_o2(:,2),'bo',... - fds_ext_o2(:,1)-tmpm,X_fds_ext_o2(:,2),'b*',... - 'LineWidth',0.5,'MarkerSize',4); -set(h([1]),'LineWidth',1) -set(h([2 4]),'MarkerSize',7) -axis([0. 1700 0 0.21]) -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Scat_Label_Font_Size) -xlabel('Temperature (°C)','Interpreter',Font_Interpreter,'FontSize',Scat_Label_Font_Size,'FontName',Font_Name) -ylabel('Oxygen Volume Fraction','Interpreter',Font_Interpreter,'FontSize',Scat_Label_Font_Size,'FontName',Font_Name) -lh=legend('Simple Model','Expected Burning','FDS Burning','Expected Extinction','FDS Extinction','Location','NorthEast'); -set(lh,'FontSize',Key_Font_Size) - -% add Git if file is available - -git_file = 'extinction_1_git.txt'; -addverstr(gca,git_file,'linear') - -% print to pdf -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Scat_Paper_Width Scat_Paper_Height]); -set(gcf,'Position',[0 0 Scat_Paper_Width Scat_Paper_Height]); -print(gcf,'-dpdf',['../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/' 'extinction_' num2str(ifile,'%i')]); - -end diff --git a/Utilities/Matlab/scripts/extinction_1_sketch.m b/Utilities/Matlab/scripts/extinction_1_sketch.m deleted file mode 100644 index f6e26b3aeee..00000000000 --- a/Utilities/Matlab/scripts/extinction_1_sketch.m +++ /dev/null @@ -1,40 +0,0 @@ -% McGrattan -% 4-2-19 -% extinction_1_sketch.m -% -% Makes figure for 'EXTINCTION 1' model for Tech Guide - -close all -clear all - -plot_style -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -T1 = 0:600; -T2 = 600:1500; -X_O2_1 = 0.135*(1-(T1-20)/1427.); -X_O2_2 = 0.135*(1-(T2-20)/1427.); -XLegendStr{1}='constant volume'; -XLegendStr{2}='quadratic'; -XLegendStr{3}='user fan curve'; -K(1)=plot(T1,X_O2_1,'k-','LineWidth',1); hold on -K(2)=plot(T2,X_O2_2,'k--','LineWidth',1); -K(3)=plot([600 600],[0 .08013],'k-','LineWidth',1); -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Title_Font_Size) -axis([0 1500 0 0.2]) -xlabel('Temperature (°C)','Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) -ylabel('Oxygen Volume Fraction','Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) -text(150,0.06,'No Burn','Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) -text(800,0.03,'Burn','Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) -text(700,0.15,'Burn','Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) -% print to pdf -plot_dir = '../../Manuals/FDS_Technical_Reference_Guide/FIGURES/'; -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf',[plot_dir,'extinction_1_sketch']) diff --git a/Utilities/Matlab/scripts/fan_curve.m b/Utilities/Matlab/scripts/fan_curve.m deleted file mode 100644 index 9c199354542..00000000000 --- a/Utilities/Matlab/scripts/fan_curve.m +++ /dev/null @@ -1,50 +0,0 @@ -% McDermott and Floyd -% 10-3-12 -% fan_curve.m -% -% Makes figure for HVAC Fan Parameters section of the FDS Users Guide - -close all -clear all - -plot_style -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -vdot_max = 10; -dp_max = 500; - -dp = -1000:1000; - -vdot = vdot_max*sign(dp_max-dp).*sqrt(abs(dp-dp_max)/dp_max); -vdot1 = 10; -XLegendStr{1}='constant volume'; -XLegendStr{2}='quadratic'; -XLegendStr{3}='user fan curve'; -K(1)=plot(vdot1*ones(1,length(dp)),dp,'r-','LineWidth',2); hold on -K(2)=plot(vdot,dp,'k-','LineWidth',2); -i=0; -for dp=-1000:200:1000 - i=i+1; - rampx(i) = vdot_max*sign(dp_max-dp).*sqrt(abs(dp-dp_max)/dp_max); - rampy(i) = dp; -end -K(3)=plot(rampx,rampy,'b-','LineWidth',2); -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Title_Font_Size) -set(gca,'XGrid','on') -set(gca,'YGrid','on') -axis([-10 20 -1000 1000]) -xlabel('Volume Flow Rate (m³/s)','Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) -ylabel('Static Pressure (Pa)','Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) -lh=legend(K,XLegendStr,'Location','Southwest'); -set(lh,'FontSize',Key_Font_Size) -% print to pdf -plot_dir = '../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/'; -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf',[plot_dir,'fan_curve']) diff --git a/Utilities/Matlab/scripts/favre_test.m b/Utilities/Matlab/scripts/favre_test.m deleted file mode 100644 index c0ca663b966..00000000000 --- a/Utilities/Matlab/scripts/favre_test.m +++ /dev/null @@ -1,192 +0,0 @@ -% McDermott -% 5-17-2021 -% favre_test.m -% -% compare TEMPORAL_STATISTIC='FAVRE AVERAGE' with brute force Favre average - -close all -clear all - -% Output files - -datadir = '../../Verification/Species/'; -plotdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/'; - -% gather Favre averages from line file - -L = importdata([datadir,'favre_test_line.csv'],',',2); -M = importdata([datadir,'favre_test_devc.csv'],',',2); -t_stats_start = M.data(end,1)/2; -t = M.data(find(M.data(:,1)>t_stats_start),1); -T = t(end)-t(1); - -%%%%%%%%%%%%%%%%%% -% cell data -%%%%%%%%%%%%%%%%%% - -YL1 = L.data(1,find(strcmp(L.colheaders,'YTILDE_O2'))); -YL2 = L.data(2,find(strcmp(L.colheaders,'YTILDE_O2'))); -YL3 = L.data(3,find(strcmp(L.colheaders,'YTILDE_O2'))); - -YRMSL1 = L.data(1,find(strcmp(L.colheaders,'YO2_RMS'))); -YRMSL2 = L.data(2,find(strcmp(L.colheaders,'YO2_RMS'))); -YRMSL3 = L.data(3,find(strcmp(L.colheaders,'YO2_RMS'))); - -RHO1 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHO_1'))); -RHO2 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHO_2'))); -RHO3 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHO_3'))); -RHOYO2_1 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHOYO2_1'))); -RHOYO2_2 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHOYO2_2'))); -RHOYO2_3 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHOYO2_3'))); - -% brute force integration for means - -NUM1 = 0; -NUM2 = 0; -NUM3 = 0; -DENOM1 = 0; -DENOM2 = 0; -DENOM3 = 0; -for i=2:length(t) - dt = t(i)-t(i-1); - NUM1 = NUM1 + RHOYO2_1(i)*dt; - NUM2 = NUM2 + RHOYO2_2(i)*dt; - NUM3 = NUM3 + RHOYO2_3(i)*dt; - DENOM1 = DENOM1 + RHO1(i)*dt; - DENOM2 = DENOM2 + RHO2(i)*dt; - DENOM3 = DENOM3 + RHO3(i)*dt; -end -YTILDE1 = NUM1/DENOM1; -YTILDE2 = NUM2/DENOM2; -YTILDE3 = NUM3/DENOM3; - -% compute error and report if necessary - -e1 = abs(YL1-YTILDE1); -e2 = abs(YL2-YTILDE2); -e3 = abs(YL3-YTILDE3); - -tol = 1e-4; -if e1>tol; disp(['Matlab Warning: e1 = ',num2str(e1),' in Species/favre_test mean cell data']); end -if e2>tol; disp(['Matlab Warning: e2 = ',num2str(e2),' in Species/favre_test mean cell data']); end -if e3>tol; disp(['Matlab Warning: e3 = ',num2str(e3),' in Species/favre_test mean cell data']); end - -% brute force integration for rms - -NUM1 = 0; -NUM2 = 0; -NUM3 = 0; -for i=2:length(t) - dt = t(i)-t(i-1); - NUM1 = NUM1 + (RHOYO2_1(i)/RHO1(i) - YTILDE1)^2 *dt; - NUM2 = NUM2 + (RHOYO2_2(i)/RHO2(i) - YTILDE2)^2 *dt; - NUM3 = NUM3 + (RHOYO2_3(i)/RHO3(i) - YTILDE3)^2 *dt; -end -YRMS1 = sqrt(NUM1/T); -YRMS2 = sqrt(NUM2/T); -YRMS3 = sqrt(NUM3/T); - -% compute error and report if necessary - -e1 = abs(YRMSL1-YRMS1); -e2 = abs(YRMSL2-YRMS2); -e3 = abs(YRMSL3-YRMS3); - -tol = 1e-2; -if e1>tol; disp(['Matlab Warning: e1 = ',num2str(e1),' in Species/favre_test rms cell data']); end -if e2>tol; disp(['Matlab Warning: e2 = ',num2str(e2),' in Species/favre_test rms cell data']); end -if e3>tol; disp(['Matlab Warning: e3 = ',num2str(e3),' in Species/favre_test rms cell data']); end - -%%%%%%%%%%%%%%%%%%%%% -% interpolated data -%%%%%%%%%%%%%%%%%%%%% - -YL1 = L.data(1,find(strcmp(L.colheaders,'YTILDE_O2_INT'))); -YL2 = L.data(2,find(strcmp(L.colheaders,'YTILDE_O2_INT'))); -YL3 = L.data(3,find(strcmp(L.colheaders,'YTILDE_O2_INT'))); - -YRMSL1 = L.data(1,find(strcmp(L.colheaders,'YO2_RMS_INT'))); -YRMSL2 = L.data(2,find(strcmp(L.colheaders,'YO2_RMS_INT'))); -YRMSL3 = L.data(3,find(strcmp(L.colheaders,'YO2_RMS_INT'))); - -RHO1 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHO_1_INT'))); -RHO2 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHO_2_INT'))); -RHO3 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHO_3_INT'))); -RHOYO2_1 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHOYO2_1_INT'))); -RHOYO2_2 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHOYO2_2_INT'))); -RHOYO2_3 = M.data(find(M.data(:,1)>t_stats_start),find(strcmp(M.colheaders,'RHOYO2_3_INT'))); - -% brute force integration - -NUM1 = 0; -NUM2 = 0; -NUM3 = 0; -DENOM1 = 0; -DENOM2 = 0; -DENOM3 = 0; -for i=2:length(t) - dt = t(i)-t(i-1); - NUM1 = NUM1 + RHOYO2_1(i)*dt; - NUM2 = NUM2 + RHOYO2_2(i)*dt; - NUM3 = NUM3 + RHOYO2_3(i)*dt; - DENOM1 = DENOM1 + RHO1(i)*dt; - DENOM2 = DENOM2 + RHO2(i)*dt; - DENOM3 = DENOM3 + RHO3(i)*dt; -end -YTILDE1 = NUM1/DENOM1; -YTILDE2 = NUM2/DENOM2; -YTILDE3 = NUM3/DENOM3; - -% compute error and report if necessary - -e1 = abs(YL1-YTILDE1); -e2 = abs(YL2-YTILDE2); -e3 = abs(YL3-YTILDE3); - -tol = 1e-4; -if e1>tol; disp(['Matlab Warning: e1 = ',num2str(e1),' in Species/favre_test mean interpolated data']); end -if e2>tol; disp(['Matlab Warning: e2 = ',num2str(e2),' in Species/favre_test mean interpolated data']); end -if e3>tol; disp(['Matlab Warning: e3 = ',num2str(e3),' in Species/favre_test mean interpolated data']); end - -% brute force integration for rms - -NUM1 = 0; -NUM2 = 0; -NUM3 = 0; -for i=2:length(t) - dt = t(i)-t(i-1); - NUM1 = NUM1 + (RHOYO2_1(i)/RHO1(i) - YTILDE1)^2 *dt; - NUM2 = NUM2 + (RHOYO2_2(i)/RHO2(i) - YTILDE2)^2 *dt; - NUM3 = NUM3 + (RHOYO2_3(i)/RHO3(i) - YTILDE3)^2 *dt; -end -YRMS1 = sqrt(NUM1/T); -YRMS2 = sqrt(NUM2/T); -YRMS3 = sqrt(NUM3/T); - -% compute error and report if necessary - -e1 = abs(YRMSL1-YRMS1); -e2 = abs(YRMSL2-YRMS2); -e3 = abs(YRMSL3-YRMS3); - -tol = 1e-2; -if e1>tol; disp(['Matlab Warning: e1 = ',num2str(e1),' in Species/favre_test rms interpolated data']); end -if e2>tol; disp(['Matlab Warning: e2 = ',num2str(e2),' in Species/favre_test rms interpolated data']); end -if e3>tol; disp(['Matlab Warning: e3 = ',num2str(e3),' in Species/favre_test rms interpolated data']); end - - - - - - - - - - - - - - - - - diff --git a/Utilities/Matlab/scripts/flame_height.m b/Utilities/Matlab/scripts/flame_height.m deleted file mode 100644 index 302b376c440..00000000000 --- a/Utilities/Matlab/scripts/flame_height.m +++ /dev/null @@ -1,108 +0,0 @@ -% McDermott -% 2-4-11 -% flame_height.m -% -% integrates HRRPUL(z) from *_line.csv file to determine L_f/D (normalized flame height) - -check_hrr % confirm heat release rate - -outdir = '../../../out/Heskestad_Flame_Height/'; -expdir = '../../../exp/Heskestad_Flame_Height/'; - -filename = {'Qs=p1_RI=05_devc.csv', 'Qs=p1_RI=10_devc.csv', 'Qs=p1_RI=20_devc.csv'; ... - 'Qs=p2_RI=05_devc.csv', 'Qs=p2_RI=10_devc.csv', 'Qs=p2_RI=20_devc.csv'; ... - 'Qs=p5_RI=05_devc.csv', 'Qs=p5_RI=10_devc.csv', 'Qs=p5_RI=20_devc.csv'; ... - 'Qs=1_RI=05_devc.csv', 'Qs=1_RI=10_devc.csv', 'Qs=1_RI=20_devc.csv'; ... - 'Qs=2_RI=05_devc.csv', 'Qs=2_RI=10_devc.csv', 'Qs=2_RI=20_devc.csv'; ... - 'Qs=5_RI=05_devc.csv', 'Qs=5_RI=10_devc.csv', 'Qs=5_RI=20_devc.csv'; ... - 'Qs=10_RI=05_devc.csv', 'Qs=10_RI=10_devc.csv', 'Qs=10_RI=20_devc.csv'; ... - 'Qs=20_RI=05_devc.csv', 'Qs=20_RI=10_devc.csv', 'Qs=20_RI=20_devc.csv'; ... - 'Qs=50_RI=05_devc.csv', 'Qs=50_RI=10_devc.csv', 'Qs=50_RI=20_devc.csv'; ... - 'Qs=100_RI=05_devc.csv', 'Qs=100_RI=10_devc.csv', 'Qs=100_RI=20_devc.csv'; ... - 'Qs=200_RI=05_devc.csv', 'Qs=200_RI=10_devc.csv', 'Qs=200_RI=20_devc.csv'; ... - 'Qs=500_RI=05_devc.csv', 'Qs=500_RI=10_devc.csv', 'Qs=500_RI=20_devc.csv'; ... - 'Qs=1000_RI=05_devc.csv', 'Qs=1000_RI=10_devc.csv', 'Qs=1000_RI=20_devc.csv'; ... - 'Qs=2000_RI=05_devc.csv', 'Qs=2000_RI=10_devc.csv', 'Qs=2000_RI=20_devc.csv'; ... - 'Qs=5000_RI=05_devc.csv', 'Qs=5000_RI=10_devc.csv', 'Qs=5000_RI=20_devc.csv'; ... - 'Qs=10000_RI=05_devc.csv', 'Qs=10000_RI=10_devc.csv', 'Qs=10000_RI=20_devc.csv'}; - -rho_inf = 1.2; -cp = 1; -T_inf = 293; -g = 9.81; -D = 1.13; -f=0.99; -%Q* = .1 .2 .5 1 2 5 10 20 50 100 200 500 1000 2000 5000 10000 -Qdot=[151 303 756 1513 3025 7564 15127 30255 75636 151273 302545 756363 1512725 3025450 7563625 15127250]; - -for i=1:16 % hrr loop - for j=1:3 % resolution loop - M = csvread([outdir,filename{i,j}],2,0); - L(j) = M(end,4); % 99th percentile - Qstar = Qdot(i)/(rho_inf*cp*T_inf*sqrt(g)*D^(5/2)); - end - W(i,1:4) = [Qstar L(1)/D L(2)/D L(3)/D]; -end - -fclose('all'); - -% Write a file with FDS-predicted flame heights - -header1 = {'Q*','L/D (RI=5)','L/D (RI=10)','L/D (RI=20)'}; -filename1 = [outdir,'FDS_Flame_Height.csv']; -fid = fopen(filename1,'wt'); -fprintf(fid,'%s, %s, %s, %s\n',header1{:}); -for i=1:16 - fprintf(fid,'%f, %f, %f, %f\n',W(i,:)); -end -fclose(fid); - -% Generate FDS results for Tamanini cases - -filename{1} = [outdir,'FDS_Tamanini_RI=05.csv']; -filename{2} = [outdir,'FDS_Tamanini_RI=10.csv']; -filename{3} = [outdir,'FDS_Tamanini_RI=20.csv']; - -fds_line_file = {'Qs=1500_RI=05_line.csv', 'Qs=p6_RI=05_line.csv', 'Qs=p3_RI=05_line.csv'; ... - 'Qs=1500_RI=10_line.csv', 'Qs=p6_RI=10_line.csv', 'Qs=p3_RI=10_line.csv'; ... - 'Qs=1500_RI=20_line.csv', 'Qs=p6_RI=20_line.csv', 'Qs=p3_RI=20_line.csv'}; - -Qstar = [1500 .6 .3]; -header = {'z/L jet','Q jet','z/L 62','Q 62','z/L 31','Q 31'}; - -for j=1:3 % resolution loop - - clear z hrr - - fid = fopen(filename{j},'wt'); - - fprintf(fid,'%s, %s, %s, %s, %s, %s\n',header{:}); - A = []; - - for k=1:3 % hrr loop - - M = importdata([outdir,fds_line_file{j,k}],',',2); - z = M.data(:,1); - dz = z(2)-z(1); - hrrpul = M.data(:,2); - Qdot_line = sum(hrrpul)*dz; - f = 0.99; - - % determine flame height - for n=1:length(z) - hrr(n) = sum(hrrpul(1:n))*dz/Qdot_line; % cummulative heat release - end - kk = find(hrr>f,1); - L(k) = z(kk-1)+dz*(f-hrr(kk-1))/(hrr(kk)-hrr(kk-1)); - - A=[A,(z+dz/2)/L(k),hrr']; - - end % hrr loop - - for i=1:length(z) - fprintf(fid,'%f, %f, %f, %f, %f, %f\n',A(i,:)); - end - fclose(fid); - -end % resolution loop - diff --git a/Utilities/Matlab/scripts/flame_species.m b/Utilities/Matlab/scripts/flame_species.m deleted file mode 100644 index 6802efb2c38..00000000000 --- a/Utilities/Matlab/scripts/flame_species.m +++ /dev/null @@ -1,95 +0,0 @@ -%------------------------------------------------ -% C Weinschenk -% 10-2011 -% Combine outputs from Methane_flame_lumped and -% Methane_flame_primitive into 1 file -%------------------------------------------------ - -%----------------------- -% Write directory -%----------------------- - -outdir = '../../Verification/Species/'; - -%---------------------- -% Import files -%---------------------- - -if ~exist([outdir,'methane_flame_primitive_devc.csv']) - display(['Error: File ',[outdir,'methane_flame_primitive_devc.csv'],' does not exist. Skipping case.']) - return -end - -if ~exist([outdir,'methane_flame_lumped_devc.csv']) - display(['Error: File ',[outdir,'methane_flame_lumped_devc.csv'],' does not exist. Skipping case.']) - return -end - -if ~exist([outdir,'methane_flame_lumped_fuel_devc.csv']) - display(['Error: File ',[outdir,'methane_flame_lumped_fuel_devc.csv'],' does not exist. Skipping case.']) - return -end - -if ~exist([outdir,'methane_flame_lumped_ox_devc.csv']) - display(['Error: File ',[outdir,'methane_flame_lumped_ox_devc.csv'],' does not exist. Skipping case.']) - return -end - -if ~exist([outdir,'methane_flame_primitive_2_devc.csv']) - display(['Error: File ',[outdir,'methane_flame_primitive_2_devc.csv'],' does not exist. Skipping case.']) - return -end - - -primitive_struct=importdata([outdir,'methane_flame_primitive_devc.csv']); -primitive_data=primitive_struct.data; -primitive_text=primitive_struct.textdata; - -lumped_struct=importdata([outdir,'methane_flame_lumped_devc.csv']); -lumped_data=lumped_struct.data; -lumped_text=lumped_struct.textdata; - -header1=cat(2,primitive_text(1),lumped_text(1,2:4)); -header2=cat(2,primitive_text(2,:),lumped_text(2,2:4)); -data=cat(2,primitive_data,lumped_data(:,2:4)); - -primitive_struct_2=importdata([outdir,'methane_flame_primitive_2_devc.csv']); -primitive_data_2=primitive_struct_2.data; -primitive_text_2=primitive_struct_2.textdata; - -lumped_struct_f=importdata([outdir,'methane_flame_lumped_fuel_devc.csv']); -lumped_data_f=lumped_struct_f.data; -lumped_text_f=lumped_struct_f.textdata; - -lumped_struct_ox=importdata([outdir,'methane_flame_lumped_ox_devc.csv']); -lumped_data_ox=lumped_struct_ox.data; -lumped_text_ox=lumped_struct_ox.textdata; - -header1b=cat(2,primitive_text_2(1),lumped_text_f(1,2:3),lumped_text_ox(1,2:3)); -header2b=cat(2,primitive_text_2(2,:),lumped_text_f(2,2:3),lumped_text_ox(2,2:3)); -datab=cat(2,primitive_data_2,lumped_data_f(:,2:3),lumped_data_ox(:,2:3)); - -%----------------------- -% Write new files -%----------------------- - -fid = fopen([outdir,'methane_flame_lumpedprimitive.csv'],'wt','n'); - -fprintf(fid,'%s,%s,%s,%s,%s,%s,%s\n','s','kg','kg','kg','kg','kg','kg'); -fprintf(fid,'%s,%s,%s,%s,%s,%s,%s\n',header2{1,:}); -for i=1:length(primitive_data) - fprintf(fid,'%f,%f,%f,%f,%f,%f,%f\n',data(i,:)); -end -fclose(fid); - -fid = fopen([outdir,'methane_flame_multilumped.csv'],'wt','n'); - -fprintf(fid,'%s,%s,%s,%s,%s,%s,%s\n','s','kg','kg','kg','kg','kg','kg'); -fprintf(fid,'%s,%s,%s,%s,%s,%s,%s\n',header2b{1,:}); -for i=1:length(primitive_data_2) - fprintf(fid,'%f,%f,%f,%f,%f,%f,%f\n',datab(i,:)); -end -fclose(fid); - - - diff --git a/Utilities/Matlab/scripts/fluid_part.m b/Utilities/Matlab/scripts/fluid_part.m deleted file mode 100644 index 565f0649854..00000000000 --- a/Utilities/Matlab/scripts/fluid_part.m +++ /dev/null @@ -1,238 +0,0 @@ -% McDermott -% 10-12-11 -% fluid_part.m - -close all -clear all - -% set the plot style parameters - -ddir='../../Verification/Sprinklers_and_Sprays/'; - -skip_case = 0; - -if ~exist([ddir,'fluid_part_mom_x_devc.csv']) - display(['Error: File ' [ddir,'fluid_part_mom_x_devc.csv'] ' does not exist. Skipping case.']) - skip_case = 1; -end -if ~exist([ddir,'fluid_part_mom_y_devc.csv']) - display(['Error: File ' [ddir,'fluid_part_mom_y_devc.csv'] ' does not exist. Skipping case.']) - skip_case = 1; -end -if ~exist([ddir,'fluid_part_mom_z_devc.csv']) - display(['Error: File ' [ddir,'fluid_part_mom_z_devc.csv'] ' does not exist. Skipping case.']) - skip_case = 1; -end - -if ~exist([ddir,'fluid_part_mom_x_1.prt5']) - display(['Error: File ' [ddir,'fluid_part_mom_x_1.prt5'] ' does not exist. Skipping case.']) - skip_case = 1; -end -if ~exist([ddir,'fluid_part_mom_y_1.prt5']) - display(['Error: File ' [ddir,'fluid_part_mom_y_1.prt5'] ' does not exist. Skipping case.']) - skip_case = 1; -end -if ~exist([ddir,'fluid_part_mom_z_1.prt5']) - display(['Error: File ' [ddir,'fluid_part_mom_z_1.prt5'] ' does not exist. Skipping case.']) - skip_case = 1; -end - -if skip_case - return -end - -M = importdata([ddir,'fluid_part_mom_x_devc.csv'],',',2); -tx = M.data(:,1); -U = M.data(:,2); -MX = M.data(:,3); - -M = importdata([ddir,'fluid_part_mom_y_devc.csv'],',',2); -ty = M.data(:,1); -V = M.data(:,2); -MY = M.data(:,3); - -M = importdata([ddir,'fluid_part_mom_z_devc.csv'],',',2); -tz = M.data(:,1); -W = M.data(:,2); -MZ = M.data(:,3); - -range=1:10:min([length(tx),length(ty),length(tz)]); - -plot_style -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -H(1)=plot(tx(range),MX(range).*U(range),'bo'); hold on -H(2)=plot(ty(range),MY(range).*V(range),'bv'); -H(3)=plot(tz(range),MZ(range).*W(range),'b+'); - -n = 1000; % number of particles -mpv = 10.; % kg/m^3, mass_per_volume (from FDS input file) -v_xb = 1^3; % volume of XB region on init line in FDS input file -rho_p = 1000; % density of water, kg/m^3 -d_p = 1000e-6; % diameter, m -v_p = 4/3*pi*(d_p/2)^3; % volume of a single droplet, m^3 -m_p = rho_p*v_p; % mass of single droplet, kg -pwt = mpv*v_xb/(n*m_p); % particle weight factor - -[STIME_X, XP_X, YP_X, ZP_X, QP_X] = read_prt5([ddir,'fluid_part_mom_x_1.prt5'],'real*4'); -[STIME_Y, XP_Y, YP_Y, ZP_Y, QP_Y] = read_prt5([ddir,'fluid_part_mom_y_1.prt5'],'real*4'); -[STIME_Z, XP_Z, YP_Z, ZP_Z, QP_Z] = read_prt5([ddir,'fluid_part_mom_z_1.prt5'],'real*4'); - -P_X = zeros(1,numel(STIME_X)); -for i=1:numel(STIME_X) - for j=1:n - P_X(i) = P_X(i) + pwt*m_p*QP_X(i,j,1,1); % momentum of particle at time STIME(i) - end -end - -P_Y = zeros(1,numel(STIME_Y)); -for i=1:numel(STIME_Y) - for j=1:n - P_Y(i) = P_Y(i) + pwt*m_p*QP_Y(i,j,1,1); - end -end - -P_Z = zeros(1,numel(STIME_Z)); -for i=1:numel(STIME_Z) - for j=1:n - P_Z(i) = P_Z(i) + pwt*m_p*QP_Z(i,j,1,1); - end -end - -range=1:10:min([length(STIME_X),length(STIME_Y),length(STIME_Z)]); - -H(4)=plot(STIME_X(range),P_X(range),'ro'); -H(5)=plot(STIME_Y(range),P_Y(range),'rv'); -H(6)=plot(STIME_Z(range),P_Z(range),'r+'); - -P_total_X = P_X + (MX.*U)'; % total momentum -P_total_Y = P_Y + (MY.*V)'; -P_total_Z = P_Z + (MZ.*W)'; - -H(7)=plot(STIME_X(range),P_total_X(range),'go'); -H(8)=plot(STIME_Y(range),P_total_Y(range),'gv'); -H(9)=plot(STIME_Z(range),P_total_Z(range),'g+'); - -% analytical solution - -rho = 1.1992661; % fluid density -Cd = 1; % drag coefficient -A_p = pi*(d_p/2)^2; % particle area - -u_p = QP_Z(1,1,1,1); % initial velocity -U_p = U(1); - -M_p = MX(1)/(n*pwt); -alpha = M_p/m_p; - - -for i=1:(numel(tx)-1) - - u_soln(i) = u_p; - U_soln(i) = U_p; - t_soln(i) = tx(i); - - dt = tx(i+1)-tx(i); - - u0 = u_p; - U0 = U_p; - - beta = 0.5*rho*Cd*A_p*(1/m_p + 1/M_p)*abs(u0-U0); - - u_p = u0/(1+beta*dt) + (u0+alpha*U0)/(1+alpha)*(beta*dt)/(1+beta*dt); - - U_p = U0 + n*pwt*m_p/MX(1)*(u0-u_p); - -end - -H(10)=plot(t_soln,MX(1)*U_soln,'b-'); -H(11)=plot(t_soln,n*pwt*m_p*u_soln,'r-'); - -axis([min(tx) max(tx) 0 150]) -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) -xlabel('Time (s)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) -ylabel('Momentum (kg m/s)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) - -legend_handle = legend(H(1:11),'FDS fluid U','FDS fluid V','FDS fluid W', ... - 'FDS particle U','FDS particle V','FDS particle W', ... - 'FDS total U','FDS total V','FDS total W', ... - 'Analytical fluid','Analytical particle','Location','EastOutside'); -set(legend_handle,'FontSize',Key_Font_Size) -set(legend_handle,'Units',Paper_Units) -pos = get(legend_handle,'position'); -set(legend_handle,'position',[Paper_Width pos(2:4)]) - -% add Git revision if file is available -Git_Filename = [ddir,'fluid_part_mom_x_git.txt']; -addverstr(gca,Git_Filename,'linear') - -PDF_Paper_Width = 1.5*Paper_Width; - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[PDF_Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 PDF_Paper_Width Paper_Height]); - -print -dpdf ../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/fluid_part_momentum - -% plot velocities - -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -H(1)=plot(tx(range),U(range),'bo'); hold on -H(2)=plot(ty(range),V(range),'bv'); -H(3)=plot(tz(range),W(range),'b+'); - -U_p = P_X/(n*pwt*m_p); -V_p = P_Y/(n*pwt*m_p); -W_p = P_Z/(n*pwt*m_p); - -H(4)=plot(tx(range),U_p(range),'ro'); -H(5)=plot(ty(range),V_p(range),'rv'); -H(6)=plot(tz(range),W_p(range),'r+'); - -U_eq = P_total_X/(MX(1)+n*pwt*m_p); -V_eq = P_total_Y/(MY(1)+n*pwt*m_p); -W_eq = P_total_Z/(MZ(1)+n*pwt*m_p); - -H(7)=plot(tx,U_eq,'g--'); -H(7)=plot(ty,V_eq,'g--'); -H(7)=plot(tz,W_eq,'g--'); - -axis([min(tx) max(tx) 0 10]) -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) -xlabel('Time (s)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) -ylabel('Velocity (m/s)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) - -legend_handle = legend(H(1:7),'FDS fluid U','FDS fluid V','FDS fluid W',... - 'FDS particle U','FDS particle V','FDS particle W',... - 'Equilibrium velocity','Location','EastOutside'); -set(legend_handle,'FontSize',Key_Font_Size) -set(legend_handle,'Units',Paper_Units) -pos = get(legend_handle,'position'); -set(legend_handle,'position',[Paper_Width pos(2:4)]) - -% add Git revision if file is available -Git_Filename = [ddir,'fluid_part_mom_x_git.txt']; -addverstr(gca,Git_Filename,'linear') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[PDF_Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 PDF_Paper_Width Paper_Height]); - -print -dpdf ../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/fluid_part_velocity - - - - - - diff --git a/Utilities/Matlab/scripts/fm_datacenter_scatter.m b/Utilities/Matlab/scripts/fm_datacenter_scatter.m deleted file mode 100644 index 893bd721941..00000000000 --- a/Utilities/Matlab/scripts/fm_datacenter_scatter.m +++ /dev/null @@ -1,155 +0,0 @@ -% $Id$ -% $Revision$ - -% Generate fds summary data for scatterplots - -outdir = '../../../out/FM_FPRF_Datacenter/'; -expdir = '../../../exp/FM_FPRF_Datacenter/'; - -[exp_data] = csvread([expdir,'/fm_exp.csv'],1); - -% Low flow test -[fds_data] = csvread([outdir,'FM_Datacenter_Veltest_Low_devc.csv'],13); -n_fds_data=size(fds_data,1); -%compute average pressures -for i=2:7 - fds_avg(i-1) = mean(fds_data(1:n_fds_data,i)); -end - -fds_header={'Time','Low SF-CA','Low HA-CP','High SF-CA','High HA-CP'}; - -fds_out(1)=100; -fds_out(2)=fds_avg(1)-fds_avg(2); -fds_out(3)=fds_avg(5)-fds_avg(6); - -% High flow test -[fds_data] = csvread([outdir,'FM_Datacenter_Veltest_High_devc.csv'],13); - -%compute average pressures -for i=2:7 - fds_avg(i-1) = mean(fds_data(1:n_fds_data,i)); -end - -fds_out(4)=fds_avg(1)-fds_avg(2); -fds_out(5)=fds_avg(5)-fds_avg(6); - -fid=fopen([outdir,'FM_Datacenter_fds_data.csv'],'w+'); - -fprintf(fid,'%s, %s, %s, %s, %s \n',fds_header{1:5}); -fprintf(fid,'%f, %f, %f, %f, %f, \n',fds_out(1:5)); - -fclose(fid); - -%get soot values - -[fds_data] = csvread([outdir,'FM_Datacenter_Low_C3H6_SF_devc.csv'],15); - -fds_out(6) = mean(fds_data(:,28))*1000000; -fds_out(7) = mean(fds_data(:,46))*1000000; -fds_out(8) = mean(fds_data(:,65))*1000000; - -[fds_data] = csvread([outdir,'FM_Datacenter_High_C3H6_SF_devc.csv'],15); - -fds_out(9) = mean(fds_data(:,28))*1000000; -fds_out(10) = mean(fds_data(:,46))*1000000; -fds_out(11) = mean(fds_data(:,65))*1000000; - -[fds_data] = csvread([outdir,'FM_Datacenter_Low_C3H6_HA_devc.csv'],15); - -fds_out(12) = mean(fds_data(:,28))*1000000; -fds_out(13) = mean(fds_data(:,46))*1000000; -fds_out(14) = mean(fds_data(:,65))*1000000; - -[fds_data] = csvread([outdir,'FM_Datacenter_High_C3H6_HA_devc.csv'],15); - -fds_out(15) = mean(fds_data(:,28))*1000000; -fds_out(16) = mean(fds_data(:,46))*1000000; -fds_out(17) = mean(fds_data(:,65))*1000000; - -[fds_data] = csvread([outdir,'FM_Datacenter_Low_Cable_SF_devc.csv'],13); - -fds_out(18) = mean(fds_data(:,28))*1000000; -fds_out(19) = mean(fds_data(:,46))*1000000; -fds_out(20) = mean(fds_data(:,65))*1000000; - -[fds_data] = csvread([outdir,'FM_Datacenter_High_Cable_SF_devc.csv'],13); - -fds_out(21) = mean(fds_data(:,28))*1000000; -fds_out(22) = mean(fds_data(:,46))*1000000; -fds_out(23) = mean(fds_data(:,65))*1000000; - -x=[0.01 0.122 0.2 0.3 0.5 1 5 10 50 100 500 1000]; -logx=min(max(-2.7,log(x+0.00001)),1); -errx=0.01*(3.8184*logx.^2-7.7783*logx+14.346); -toterr=(errx.^2+0.1^2+0.1^2+0.05^2).^0.5; -xerrp = x + 2*toterr.*x; -xerrm = max(0.00001,x - 2*toterr.*x); - -plot_style -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Scat_Plot_X Scat_Plot_Y Scat_Plot_Width Scat_Plot_Height]) - -hx=loglog(x,x,'k-',x,xerrp,'k--',x,xerrm,'k--'); -hold on; -h1=loglog(exp_data(6:8),fds_out(6:8),'ro'); -h2=loglog(exp_data(9:11),fds_out(9:11),'r+'); -h3=loglog(exp_data(12:14),fds_out(12:14),'bo'); -h4=loglog(exp_data(15:17),fds_out(15:17),'b+'); -h5=loglog(exp_data(18:20),fds_out(18:20),'go'); -h6=loglog(exp_data(21:23),fds_out(21:23),'g+'); - -xlim([0.01 300]); -ylim([0.01 300]); - -lh=legend([h1 h2 h3 h4 h5 h6],... - 'C3H6 Low SF','C3H6 High SF','C3H6 Low HA','C3H6 High HA','Cable Low SF','Cable High SF',... - 'Location','southeast'); -set(lh,'FontSize',Key_Font_Size) - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Scat_Label_Font_Size) -xtitle = ['Measured Soot Concentration (mg/m³)']; -ytitle = ['Predicted Soot Concentration (mg/m³)']; -xlabel(xtitle,'Interpreter',Font_Interpreter,'FontSize',Scat_Label_Font_Size) -ylabel(ytitle,'Interpreter',Font_Interpreter,'FontSize',Scat_Label_Font_Size) - -git_file = [outdir,'FM_Datacenter_Low_C3H6_SF_git.txt']; -addverstr(gca,git_file,'loglog') - -% print to pdf -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Scat_Paper_Width Scat_Paper_Height]); -set(gcf,'Position',[0 0 Scat_Paper_Width Scat_Paper_Height]); -plotname = ['../../Manuals/FDS_Validation_Guide/SCRIPT_FIGURES/FM_FPRF_Datacenter/FM_Datacenter_Soot']; -print(gcf,'-dpdf',plotname); -hold off - -filename = '../../Manuals/FDS_Validation_Guide/SCRIPT_FIGURES/FM_FPRF_Datacenter/pressure.tex'; -fid = fopen(filename,'wt'); - -pres_dump(1)=fds_out(2); -pres_dump(2)=exp_data(2); -pres_dump(3)=exp_data(2)*.19; -pres_dump(4)=fds_out(3); -pres_dump(5)=exp_data(3); -pres_dump(6)=exp_data(3)*.19; -pres_dump(7)=fds_out(4); -pres_dump(8)=exp_data(4); -pres_dump(9)=exp_data(4)*.1; -pres_dump(10)=fds_out(5); -pres_dump(11)=exp_data(5); -pres_dump(12)=exp_data(5)*.1; - - -fprintf(fid,'%s\n','\begin{center}'); -fprintf(fid,'%s\n','\begin{tabular}{|c|c|c|c|c|} \hline'); -fprintf(fid,'%s\n','Fan Speed & FDS SF to CA & Exp SF to CA & FDS HA to CP & Exp HA to CP \\'); -fprintf(fid,'%s\n',' & (Pa) & (Pa) & (Pa) & (Pa) \\ \hline\hline'); -fprintf(fid,'78 ACH & %5.1f & %5.1f $\\pm$ %5.1f & %5.1f & %5.1f $\\pm$ %5.1f %s\n',pres_dump(1:6),'\\'); -fprintf(fid,'265 ACH & %5.1f & %5.1f $\\pm$ %5.1f & %5.1f & %5.1f $\\pm$ %5.1f %s\n',pres_dump(7:12),'\\'); -fprintf(fid,'%s\n','\hline'); -fprintf(fid,'%s\n','\end{tabular}'); -fprintf(fid,'%s\n','\end{center}'); diff --git a/Utilities/Matlab/scripts/hot_layer_collapse.m b/Utilities/Matlab/scripts/hot_layer_collapse.m deleted file mode 100644 index 01b653a61d9..00000000000 --- a/Utilities/Matlab/scripts/hot_layer_collapse.m +++ /dev/null @@ -1,277 +0,0 @@ -% McDermott -% 10-7-14 -% hot_layer_collapse.m -% -% H. Baum. "Collapse of a Hot Layer in a Micro-Gravity Environment", Sep 2, 2014 (personal notes) - -close all -clear all - -datadir='../../Verification/Flowfields/'; -plotdir='../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/'; - -if ~exist([datadir,'hot_layer_360_devc.csv']) - display(['Error: File ',[datadir,'hot_layer_360_devc.csv'],' does not exist. Skipping case.']) - return -end - -plot_style - -error_tolerance = 0.01; - -L = 2; % height of domain 2*d where d is the layer depth at t=0 -N = 360; % number of cells in vertical direction -T_0 = 293.15; % cold wall temperature (K) -T_h = 1172.6; % hot layer initial temperature (K) -k_0 = 1; % W/m/K -rho_0 = 1; % kg/m^3 -Cp = 1000; % J/kg/K -d = 1; % m -v0 = k_0/(rho_0*Cp*d); % m/s - -dz = L/N; - -t = [.2,.4,.6,.8,1,2,4,6,8,10]; -tau = t*1e-3; -marker_style = {'ko','mo','ro','go','bo'}; -exact_soln_style = {'k-','m-','r-','g-','b-'}; -legend_entries = {'\tau = 2 \times 10^{-4}','\tau = 4 \times 10^{-4}','\tau = 6 \times 10^{-4}','\tau = 8 \times 10^{-4}','\tau = 10 \times 10^{-4}'}; - -% analytical solution - -f = @(lambda_in,tau_in,a_in) -2*sqrt(tau_in/pi)*exp(-(a_in-lambda_in).^2/(4*tau_in)) + ... - (a_in+lambda_in).*erfc((a_in+lambda_in)/(2*sqrt(tau_in))); -F = @(lambda_in,tau_in,a_in) f(lambda_in,tau_in,a_in) - f(0,tau_in,a_in); -Y = @(lambda_in,tau_in,T_h_in,T_0_in) lambda_in + (T_h_in-T_0_in)/T_0_in*( -F(lambda_in,tau_in,0) + ... - 0.5*( F(lambda_in,tau_in,T_0_in/T_h_in) + F(lambda_in,tau_in,-T_0_in/T_h_in) ) ); -U = @(lambda_in,tau_in,T_h_in,T_0_in) -erfc(lambda_in/(2*sqrt(tau_in))) + ... - 0.5*( erfc( (lambda_in - T_0_in/T_h_in)/(2*sqrt(tau_in)) ) + erfc( (lambda_in + T_0_in/T_h_in)/(2*sqrt(tau_in)) ) ); -Theta = @(lambda_in,tau_in,T_h_in,T_0_in) 1. + ( (T_h_in - T_0_in)/T_0_in )*U(lambda_in,tau_in,T_h_in,T_0_in); -G = @(lambda_in,tau_in,a_in) 1/sqrt(pi*tau_in)*( -exp(-(a_in+lambda_in).^2/(4*tau_in)) + exp(-a_in^2/(4*tau_in)) ); -V = @(lambda_in,tau_in,T_h_in,T_0_in) (T_h_in-T_0_in)/T_0_in*( -G(lambda_in,tau_in,0) + ... - 0.5*(G(lambda_in,tau_in,T_0_in/T_h_in) + G(lambda_in,tau_in,-T_0_in/T_h_in)) ); - -lambda = linspace(0,10*T_0/T_h,1000); - -% % test -% plot(Theta(lambda,tau(1),T_h,T_0),lambda/(T_0/T_h)) -% return - -% get FDS data - -M = importdata([datadir,'hot_layer_360_devc.csv'],',',2); - -for j=1:length(tau) - J(j) = find(M.data(:,1)>=t(j),1); -end - -T_range = 2:41; -W_range = 42:81; -dz_40 = L/40; % devices are based on N=40 resolution -dz_360 = L/360; % but N=360 is used for verification (3^3*40) - -z_T = dz_40/2:dz_40:L-dz_40/2; % exact T location is the same as for the N=40 case -z_W = dz_40/2+dz_360/2:dz_40:L-dz_40/2+dz_360/2; % capture exact staggered z location of W component of velocity - -f1=figure; -a1=gca; -set(f1,'Visible',Figure_Visibility); -set(a1,'Units',Plot_Units) -set(a1,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -for j=1:5 - T = (M.data(J(j),T_range)+273.15)/T_0; - H(j)=plot(T,z_T,marker_style{j}); hold on - plot(Theta(lambda,tau(j),T_h,T_0),Y(lambda,tau(j),T_h,T_0),exact_soln_style{j}) -end - -xlabel('{\it T/T_0}','fontsize',Label_Font_Size,'FontName',Font_Name) -ylabel('{\it y/d}','fontsize',Label_Font_Size,'FontName',Font_Name) -axis([1 4 0 1.2]) -lh=legend(H,legend_entries,'location','southwest'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size) - -Git_Filename = [datadir,'hot_layer_360_git.txt']; -addverstr(a1,Git_Filename,'linear') - -set(a1,'FontName',Font_Name) -set(a1,'FontSize',Label_Font_Size) -set(f1,'Units',Paper_Units); -set(f1,'PaperUnits',Paper_Units); -set(f1,'PaperSize',[Paper_Width Paper_Height]); -set(f1,'Position',[0 0 Paper_Width Paper_Height]); -print(f1,'-dpdf',[plotdir,'hot_layer_temp_1']) - -% compute temperature error at tau(5) - -% map nondimensional position -for i=1:length(z_T) - I(i) = find(Y(lambda,tau(5),T_h,T_0)>=z_T(i),1); -end -% % test -% figure -% plot(T,z_T,'ko'); hold on -% plot(Theta(lambda(I),tau(5),T_h,T_0),Y(lambda(I),tau(5),T_h,T_0),'k+') -% return - -Error = norm(T-Theta(lambda(I),tau(5),T_h,T_0))/max(T)/length(T); -if Error>error_tolerance - display(['Matlab Warning: hot_layer_360.fds Temp_1 Error = ',num2str(Error)]) -end - -f2=figure; -a2=gca; -set(f2,'Visible',Figure_Visibility); -set(a2,'Units',Plot_Units) -set(a2,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -for j=1:5 - W = M.data(J(j),W_range)/v0; - H2(j)=plot(W,z_W,marker_style{j}); hold on - plot(V(lambda,tau(j),T_h,T_0),Y(lambda,tau(j),T_h,T_0),exact_soln_style{j}) -end - -xlabel('{\it v/v_0}','fontsize',Label_Font_Size,'FontName',Font_Name) -ylabel('{\it y/d}','fontsize',Label_Font_Size,'FontName',Font_Name) -axis([-200 0 0 1.2]) -lh=legend(H2,legend_entries,'location','southwest'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size) - -% add version string if file is available - -Git_Filename = [datadir,'hot_layer_360_git.txt']; -addverstr(a2,Git_Filename,'linear') - -set(a2,'FontName',Font_Name) -set(a2,'FontSize',Label_Font_Size) -set(f2,'Visible',Figure_Visibility); -set(f2,'Units',Paper_Units); -set(f2,'PaperUnits',Paper_Units); -set(f2,'PaperSize',[Paper_Width Paper_Height]); -set(f2,'Position',[0 0 Paper_Width Paper_Height]); -print(f2,'-dpdf',[plotdir,'hot_layer_vel_1']) - -% compute velocity error at tau(5) - -% map nondimensional position -for i=1:length(z_W) - I(i) = find(Y(lambda,tau(5),T_h,T_0)>=z_W(i),1); -end -% % test -% figure -% plot(W,z_W,'ko'); hold on -% plot(V(lambda(I),tau(5),T_h,T_0),Y(lambda(I),tau(5),T_h,T_0),'k+') -% return - -Error = norm(W-V(lambda(I),tau(5),T_h,T_0))/max(abs(W))/length(W); -if Error>error_tolerance - display(['Matlab Warning: hot_layer_360.fds Vel_1 Error = ',num2str(Error)]) -end - -% second set of Howard's plots - -f3=figure(3); -a3=gca; -set(f3,'Visible',Figure_Visibility); -set(a3,'Units',Plot_Units) -set(a3,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -legend_entries_2 = {'\tau = 2 \times 10^{-3}','\tau = 4 \times 10^{-3}','\tau = 6 \times 10^{-3}','\tau = 8 \times 10^{-3}','\tau = 10 \times 10^{-3}'}; - -for j=6:10 - jj=j-5; - - T = (M.data(J(j),T_range)+273.15)/T_0; - H3(jj)=plot(T,z_T,marker_style{jj}); hold on - plot(Theta(lambda,tau(j),T_h,T_0),Y(lambda,tau(j),T_h,T_0),exact_soln_style{jj}) - -end - -xlabel('{\it T/T_0}','fontsize',Label_Font_Size,'FontName',Font_Name) -ylabel('{\it y/d}','fontsize',Label_Font_Size,'FontName',Font_Name) -axis([1 4 0 1.2]) -lh=legend(H3,legend_entries_2,'location','northeast'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size) - -% add version string if file is available - -Git_Filename = [datadir,'hot_layer_360_git.txt']; -addverstr(a3,Git_Filename,'linear') - -set(a3,'FontName',Font_Name) -set(a3,'FontSize',Label_Font_Size) -set(f3,'Visible',Figure_Visibility); -set(f3,'Units',Paper_Units); -set(f3,'PaperUnits',Paper_Units); -set(f3,'PaperSize',[Paper_Width Paper_Height]); -set(f3,'Position',[0 0 Paper_Width Paper_Height]); -print(f3,'-dpdf',[plotdir,'hot_layer_temp_2']) - -% compute temperature error at tau(10) - -% map nondimensional position -for i=1:length(z_T) - I(i) = find(Y(lambda,tau(10),T_h,T_0)>=z_T(i),1); -end -% % test -% figure -% plot(T,z_T,'ko'); hold on -% plot(Theta(lambda(I),tau(10),T_h,T_0),Y(lambda(I),tau(10),T_h,T_0),'k+') -% return - -Error = norm(T-Theta(lambda(I),tau(10),T_h,T_0))/max(T)/length(T); -if Error>error_tolerance - display(['Matlab Warning: hot_layer_360.fds Temp_2 Error = ',num2str(Error)]) -end - -f4=figure(4); -a4=gca; -set(f4,'Visible',Figure_Visibility); -set(a4,'Units',Plot_Units) -set(a4,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -for j=6:10 - jj=j-5; - - W = M.data(J(j),W_range)/v0; - H4(jj)=plot(W,z_W,marker_style{jj}); hold on - plot(V(lambda,tau(j),T_h,T_0),Y(lambda,tau(j),T_h,T_0),exact_soln_style{jj}) - -end - -xlabel('{\it v/v_0}','fontsize',Label_Font_Size,'FontName',Font_Name) -ylabel('{\it y/d}','fontsize',Label_Font_Size,'FontName',Font_Name) -axis([-60 0 0 1.6]) -lh=legend(H4,legend_entries_2,'location','northwest'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size) - -% add version string if file is available - -Git_Filename = [datadir,'hot_layer_360_git.txt']; -addverstr(a4,Git_Filename,'linear') - -set(a4,'FontName',Font_Name) -set(a4,'FontSize',Label_Font_Size) -set(f4,'Visible',Figure_Visibility); -set(f4,'Units',Paper_Units); -set(f4,'PaperUnits',Paper_Units); -set(f4,'PaperSize',[Paper_Width Paper_Height]); -set(f4,'Position',[0 0 Paper_Width Paper_Height]); -print(f4,'-dpdf',[plotdir,'hot_layer_vel_2']) - -% compute velocity error at tau(10) - -% map nondimensional position -for i=1:length(z_W) - I(i) = find(Y(lambda,tau(10),T_h,T_0)>=z_W(i),1); -end -% % test -% figure -% plot(W,z_W,'ko'); hold on -% plot(V(lambda(I),tau(10),T_h,T_0),Y(lambda(I),tau(10),T_h,T_0),'k+') -% return - -Error = norm(W-V(lambda(I),tau(10),T_h,T_0))/max(abs(W))/length(W); -if Error>error_tolerance - display(['Matlab Warning: hot_layer_360.fds Vel_2 Error = ',num2str(Error)]) -end diff --git a/Utilities/Matlab/scripts/ht3d_slab.m b/Utilities/Matlab/scripts/ht3d_slab.m deleted file mode 100644 index ed0c44b18a6..00000000000 --- a/Utilities/Matlab/scripts/ht3d_slab.m +++ /dev/null @@ -1,57 +0,0 @@ -% McDermott -% 8-9-2016 -% ht3d_slab.m -% -% Analytical solution to heat transfer in a semi-infinite slab with convection. -% See D. Drysdale, "An Introduction to Fire Dynamcis", 2nd Ed., Wiley, p. 43. -% -% This case uses basically the same parameters as the "convective_cooling" -% solid phase verification case. - -close all -clear all - -t_end = 1800; -a = .001; -h = 1; -k = 1; -T0 = 1000; -Tinf = 0; - -T = @(x,t) T0 + (Tinf-T0) * ( erfc(x./sqrt(a*t)/2) - exp((x*h)/k + a*t/(k/h)^2).*erfc(x./sqrt(a*t)/2 + sqrt(a*t)/(k/h)) ); -Ts = @(t) T0 + (Tinf-T0) * ( 1 - exp(a*t/(k/h)^2).*erfc(sqrt(a*t)/(k/h)) ); - -t_range = linspace(0,t_end,50); - -plot(t_range,Ts(t_range),'bo'); hold on - -% read FDS results -ddir = '/Volumes/rmcdermo/GitHub/fds-smv_rmcdermo/Verification/Heat_Transfer/'; - -M = importdata([ddir,'ht3d_slab_devc.csv'],',',2); -jTime = find(strcmp(M.colheaders,'Time')); -jTS = find(strcmp(M.colheaders,'"TS"')); -t_fds = M.data(:,jTime); -Ts_fds = M.data(:,jTS); - -plot(t_fds,Ts_fds,'b-') - -% % write out analytical ramp at x = 0.5 m - -% A = [t_range',T(.5,t_range)']; -% fid = fopen('Tsoln.txt','wt'); -% for i=1:length(t_range) -% fprintf(fid,'%s %f %s %f %s\n','&RAMP ID=''T_ramp'', T=',A(i,1),', F=',A(i,2),' /'); -% end -% fclose(fid); - -% % write out analytical solution for dataplot - -% A = [t_range',Ts(t_range)']; -% fid = fopen([ddir,'ht3d_slab_soln.csv'],'wt'); -% fprintf(fid,'%s,%s\n','Time','Ts'); -% fprintf(fid,'%s,%s\n','(s)','(C)'); -% for i=1:length(t_range) -% fprintf(fid,'%f,%f\n',A(i,:)); -% end -% fclose(fid); diff --git a/Utilities/Matlab/scripts/ht3d_sphere.m b/Utilities/Matlab/scripts/ht3d_sphere.m deleted file mode 100644 index a0caf4d0e37..00000000000 --- a/Utilities/Matlab/scripts/ht3d_sphere.m +++ /dev/null @@ -1,180 +0,0 @@ -% Salah Benkorichi & Randy McDermott -% 17-7-2017 -% ht3d_sphere.m -% -% The solution is from Carslaw and Jaeger, Sec. 9.8, p. 243, Eq. (6) -% -% The notation adopted here follows C. Lautenberger, IAFSS, 2014. - -close all -clear all - -plot_style - -% analytical solution - -k = 1.0; % W/m/k -rho = 1000; % kg/m3 -cp = 1000; % J/kg/K -g0 = 2e5; % W/m3 -alpha = k/(rho*cp); % m2/s - -a1 = 0.1; % m (this should match the last cell face in ht3d_sphere_96.fds) -a2 = 0.1; % m (this should match the last cell face in ht3d_sphere_48.fds) -a3 = 0.1; % m (this should match the last cell face in ht3d_sphere_24.fds) - -n1 = 41; -n2 = 21; -n3 = 11; -r1 = linspace(0.0,0.1,n1); % this should match line DEVC in ht3d_sphere_96.fds -r2 = linspace(0.0,0.1,n2); % this should match line DEVC in ht3d_sphere_48.fds -r3 = linspace(0.0,0.1,n3); % this should match line DEVC in ht3d_sphere_24.fds - -t = [10 20 60 120 180]; % seconds - -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -for m=1:length(t) - - for ii=1:length(r1) - - sum_term = 0; - for n=1:n1 - sum_term = sum_term + (-1)^n/n^3 * sin(n*pi*r1(ii)/a1) * exp(-alpha*t(m)*(n*pi/a1)^2); - end - - DT1(ii) = 20 + g0/(6*k) * (a1^2 - r1(ii)^2) + 2*g0*a1^3/(k*pi^3*r1(ii)) * sum_term; - - end - - % Exact = plot(r1,DT1,'k-x'); hold on - - for jj=1:length(r2) - - sum_term = 0; - for n=1: n2 - sum_term = sum_term + (-1)^n/n^3 * sin(n*pi*r2(jj)/a2) * exp(-alpha*t(m)*(n*pi/a2)^2); - end - - DT2(jj) = 20 + g0/(6*k) * (a2^2 - r2(jj)^2) + 2*g0*a2^3/(k*pi^3*r2(jj)) * sum_term; - - end - - Exact = plot(r2,DT2,'k-x'); hold on - - for kk=1:length(r3) - - sum_term = 0; - for n=1:n3 - sum_term = sum_term + (-1)^n/n^3 * sin(n*pi*r3(kk)/a3) * exp(-alpha*t(m)*(n*pi/a3)^2); - end - - DT3(kk) = 20 + g0/(6*k) * (a3^2 - r3(kk)^2) + 2*g0*a3^3/(k*pi^3*r3(kk)) * sum_term; - - end - - % Exact = plot(r3,DT3,'k-x'); hold on - -end - -%% gather FDS results - -ddir = '../../Verification/Heat_Transfer/'; -fnt = {'ht3d_sphere_48'}; -fileName = {'ht3d_sphere_24','ht3d_sphere_48','ht3d_sphere_96'}; -nc_array = [25,50,100]; -dx_array = 0.25./nc_array; - -M = importdata([ddir,fnt{1},'_prof_1.csv'],',',3); -T_fds1 = M.data(2,64:end); -T_fds2 = M.data(3,64:end); -T_fds3 = M.data(7,64:end); -T_fds4 = M.data(13,64:end); -T_fds5 = M.data(end,64:end); -t10 = plot(r2,T_fds1,'--ob'); -t20 = plot(r2,T_fds2,'--og'); -t60 = plot(r2,T_fds3,'--or'); -t120 = plot(r2,T_fds4,'--oc'); -t180 = plot(r2,T_fds5,'--om'); - -ERROR = abs(M.data(end,64)-DT2(2))/(DT2(2)-20); -if ERROR > 0.01 - display(['Matlab Warning: ht3d_sphere cases out of tolerance. ERROR = ',num2str(ERROR)]) -end - -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Title_Font_Size) - -axis([0 0.105 20 60]) -xlabel('Radial Distance (m)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter,'Fontname',Font_Name) -ylabel('Temperature (°C)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter,'Fontname',Font_Name) -lh=legend([Exact, t10, t20, t60, t120, t180], {'Analytical', 'FDS {\itt}=10 s', 'FDS {\itt}=20 s', 'FDS {\itt}=60 s', 'FDS {\itt}=120 s', 'FDS {\itt}=180 s'},'location','west'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size) - -% add version string if file is available - -Git_Filename = [ddir,'ht3d_sphere_48_git.txt']; -addverstr(gca,Git_Filename,'linear') - -% print to pdf -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf','../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/ht3d_sphere_profile') - -% estimating L1 & L2 norm errors - -Linfe = []; % initialize L1 norm error vector -L2e = []; % initialize L2 norm error vector -dxx = []; % init dxx vector -DT = {DT3(end),DT2(end),DT1(end)} ; -r = {r3(end),r2(end),r1(end)}; - -for i=1:length(fileName) - M1 = importdata([ddir,fileName{i},'_prof_1.csv'],',',3); - T_fds = M1.data(end,end); % FDS devices data - T_fds1=T_fds(end); - Linfe = [Linfe,1/(length(T_fds1))*max(abs(DT{i}-T_fds1))]; % populates Linf norm error vector, element-by-element - L2e = [L2e,sqrt(1/(length(T_fds1))*sum((DT{i}-T_fds1).^2))]; % populates L2 error norm vector, element-by-element - dxx = [dxx,dx_array(i)]; % populates dxx vector, element-by-element -end - -% Set the figure - -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -hh(1)=loglog(dxx,Linfe,'msq-'); hold on -hh(2)=loglog(dxx,1e2*dxx,'k--'); -hh(3)=loglog(dxx,1e4*dxx.^2,'k-'); - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Title_Font_Size) - -xlabel('{\it \Deltax} (m)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter,'Fontname',Font_Name) -ylabel('{\it L}_{\infty} error (°C)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter,'Fontname',Font_Name) -lh=legend(hh,'FDS','{\it O(\Deltax)}','{\it O(\Deltax²)}','location','northwest'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size) - -% add version string if file is available - -Git_Filename = [ddir,'ht3d_sphere_48_git.txt']; -addverstr(gca,Git_Filename,'loglog') - -% print to pdf - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf','../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/ht3d_sphere_convergence1') - diff --git a/Utilities/Matlab/scripts/hvac_mass_transport.m b/Utilities/Matlab/scripts/hvac_mass_transport.m deleted file mode 100644 index e465e008251..00000000000 --- a/Utilities/Matlab/scripts/hvac_mass_transport.m +++ /dev/null @@ -1,139 +0,0 @@ -% B M Ralph -% 12-8-2016 -% hvac_mass_transport.m -% -% Convergence study for HVAC transient mass transport (mass fraction at -% downstream duct node). - -close all -clear all - -plot_style - -% Gather FDS results -dataDir = [pwd, '/../../Verification/HVAC/']; -fileName = {'HVAC_mass_transport_conv_0020','HVAC_mass_transport_conv_0040',... - 'HVAC_mass_transport_conv_0080','HVAC_mass_transport_conv_0160',... - 'HVAC_mass_transport_conv_0320'}; -PlotStyle = {'b-','g-','r-','m-','c-'}; -nc_array = {20,40,80,160,320}; -dx_array = {1/20,1/40,1/80,1/160,1/320}; - -% Exit if data doesn't exist -for i=1:length(fileName) - %display([dataDir,fileName{i},'.fds']) - if ~exist([dataDir,fileName{i},'.fds'],'file') - display(['Error: File ' fileName{i} ' does not exist. Skipping case.']) - return - end -end - -% Input parameters -t0 = 0; -t_end = 2; -u = 1; -L = 1; - -% Analytical solution (using Anonymous Function) -Y = @(t) t .*(t <= 1) + 1 .*(t > 1); - -% Create mass fraction plot and plot analytical solution -nt = 1000; -dt = t_end/nt; -tc = t0 : dt : t_end; -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) -plot(tc,Y(tc), 'k--'); -hold on - -L1e = []; % initialize L1 norm error vector -L2e = []; % initialize L2 norm error vector -dxx = []; % init dxx vector - -% Loop over cases, plotting FDS results (hold on) and computing L2 error vector -for i=1:length(fileName) - M = importdata([dataDir,fileName{i},'_devc.csv'],',',2); - Y_fds = M.data(1:end,2); % FDS species data - t_fds = M.data(1:end,1); % FDS time - plot(t_fds,Y_fds,PlotStyle{i}) - L1e = [L1e,1/nc_array{i}*sum(abs(Y(t_fds)-Y_fds))]; % populates L1 norm error vector, element-by-element - L2e = [L2e,sqrt(1/nc_array{i}*sum((Y(t_fds)-Y_fds).^2))]; % populates L2 error norm vector, element-by-element - dxx = [dxx,dx_array{i}]; % populates dxx vector, element-by-element -end - -% Mass fraction plot settings -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -xlabel('Time (s)') -ylabel('Mass fraction (kg/kg)') -lh=legend({'Exact solution','FDS N\_CELLS = 20','FDS N\_CELLS = 40','FDS N\_CELLS = 80',... - 'FDS N\_CELLS = 160','FDS N\_CELLS = 320'},'FontSize',Key_Font_Size,'location','southeast'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size) - -Git_Filename = [dataDir,'HVAC_mass_transport_conv_0320_git.txt']; -addverstr(gca,Git_Filename,'linear') - -% print to pdf -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf','../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/HVAC_mass_transport_convergence_1') - -% Plot L1 norm error convergence -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) -hh(1)=loglog(dxx,L1e,'ksq-'); -hold on -hh(2)=loglog(dxx,dxx/10,'k--'); - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Title_Font_Size) - -xlabel('{\it \Delta x} (m)') -ylabel('L1 error (kg/kg)') -lh=legend(hh,'FDS','{\it O(\Delta x)}','location','southeast'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size) - -Git_Filename = [dataDir,'HVAC_mass_transport_conv_0320_git.txt']; -addverstr(gca,Git_Filename,'loglog') - -% print to pdf -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf','../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/HVAC_mass_transport_convergence_2') - -% Plot L2 error convergence -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) -hh(1)=loglog(dxx,L2e,'ksq-'); -hold on -hh(2)=loglog(dxx,dxx/10,'k--'); - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Title_Font_Size) - -xlabel('{\it \Deltax} (m)') -ylabel('L2 error (kg/kg)') -lh=legend(hh,'FDS','{\it O(\Delta x)}','location','southeast'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size) - -Git_Filename = [dataDir,'HVAC_mass_transport_conv_0320_git.txt']; -addverstr(gca,Git_Filename,'loglog') - -% print to pdf -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf','../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/HVAC_mass_transport_convergence_3') - diff --git a/Utilities/Matlab/scripts/impinging_jet.m b/Utilities/Matlab/scripts/impinging_jet.m deleted file mode 100644 index c74973b3166..00000000000 --- a/Utilities/Matlab/scripts/impinging_jet.m +++ /dev/null @@ -1,160 +0,0 @@ -% McDermott -% 12-8-2023 -% impinging_jet.m - -close all -clear all - -figure -plot_style -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -outdir = '../../../out/Convection/'; -pltdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/'; -chid = 'impinging_jet'; - -% plot the correlation - -D_h = 0.2; % hydraulic diameter of the jet [m] -H = 1; % distance from jet to wall [m] -mu = 1.822E-05; % dynamic viscosity, [kg/m/s] -k = 2.566E-02; % thermal conductivity [W/m/K] -Pr = 0.71; % Prandtl number -T_j = 100; % tempetature of jet exit [C] -T_w = 20; % constant plate temperature [C] -rho_a = 1.200; % ambient density [kg/m3] -rho_j = rho_a * (T_w+273)/(T_j+273); % jet fluid density [kg/m3] -nu = mu/rho_j; % kinematic viscosity [m2/s] -U_j = [10,40]; % jet exit velocity [m/s] -A_r = 0.01; % D_h^2/(4 r^2), where r defines the outer extent of the averaging region - -% Plot correlation versus Re_j for a given geometry - -% Martin corrleation -G = 2*sqrt(A_r)*( (1-2.2*sqrt(A_r))/(1+0.2*(H/D_h-6)*sqrt(A_r)) ); - -RE = linspace(2e3,5e5); -NU = G*2*sqrt(RE).*sqrt(1+0.005*RE.^0.55).* Pr^0.42; - -K(1)=plot(RE,NU,'k-','linewidth',2); hold on - -res_str = {'coarse','medium','fine'}; -Re_str = {'1e5','4e5'}; - -% relative error tolerance -E_tol = 0.1; - -E_FDS = zeros(3,2); - -for j=1:length(res_str) - for i=1:length(Re_str) - - Re_j = D_h*U_j(i)/nu; % jet Reynolds number - - Nu = G*2*sqrt(Re_j)*sqrt(1+0.005*Re_j^0.55) * Pr^0.42; - - h_cor = Nu * k/D_h; - - % FDS results - - M = importdata([outdir,'impinging_jet_Re_',Re_str{i},'_',res_str{j},'_devc.csv'],',',2); - HF = mean(M.data(floor(end/2):end,find(strcmp(M.colheaders,'HF')))); - - qconv = HF * 1000; % W/m2 - h_fds = qconv/(T_j-T_w); - Nu_fds = h_fds*D_h/k; - - E_FDS(i,j) = abs(Nu - Nu_fds)/abs(Nu); - - if E_FDS(i,j) > E_tol - disp(['Matlab Warning: impinging jet error = ',num2str(E_FDS(i,j)),' at Re_j=',Re_str{i},', Res=',res_str{j}]) - end - - if i==1 - if j==1 - K(2)=plot(Re_j,Nu_fds,'bsq','linewidth',2); Key={'FDS coarse'}; - elseif j==2 - K(3)=plot(Re_j,Nu_fds,'rsq','linewidth',2); Key={'FDS coarse','FDS medium'}; - elseif j==3 - K(4)=plot(Re_j,Nu_fds,'gsq','linewidth',2); Key={'FDS coarse','FDS medium','FDS fine'}; - end - elseif i==2 - if j==1 - plot(Re_j,Nu_fds,'bsq','linewidth',2) - elseif j==2 - plot(Re_j,Nu_fds,'rsq','linewidth',2) - elseif j==3 - plot(Re_j,Nu_fds,'gsq','linewidth',2) - end - end - - end -end - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -xlabel('Re','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) -ylabel('Nu','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) -lh=legend(K,['Martin',Key],'location','northwest'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size); - -Git_Filename = [outdir,'impinging_jet_Re_1e5_coarse_git.txt']; -addverstr(gca,Git_Filename,'linear') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf',[pltdir,'impinging_jet_correlation']); - - -% plot the profile of heat transfer coefficient - -style = {'k-.','k--','k-'}; -clear K lh; - -for i=1:length(Re_str) - figure - set(gca,'Units',Plot_Units) - set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - - for j=1:length(res_str) - - M = importdata([outdir,'impinging_jet_Re_',Re_str{i},'_',res_str{j},'_line.csv'],',',2); - x = M.data(:,1); - q_x = M.data(:,find(strcmp(M.colheaders,'QCONV'))) * 1000; - Nu_x = q_x/(T_j-T_w)*D_h/k; - - K(j)=plot(x,Nu_x,style{j}); hold on - end - xlabel('{\itx} (m)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) - ylabel('Nu_{Dh}({\itx})','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) - - axis([-.5 .5 0 1000]) - - set(gca,'FontName',Font_Name) - set(gca,'FontSize',Label_Font_Size) - - lh=legend(K,'D_h/\delta{\itx}=7','D_h/\delta{\itx}=14','D_h/\delta{\itx}=28','location','northwest'); - set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size); - - Git_Filename = [outdir,'impinging_jet_Re_1e5_coarse_git.txt']; - addverstr(gca,Git_Filename,'linear') - - set(gcf,'Visible',Figure_Visibility); - set(gcf,'Units',Paper_Units); - set(gcf,'PaperUnits',Paper_Units); - set(gcf,'PaperSize',[Paper_Width Paper_Height]); - set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - print(gcf,'-dpdf',[pltdir,'impinging_jet_local_Re_',Re_str{i}]); - - hold off -end - - - - - diff --git a/Utilities/Matlab/scripts/layer_height.m b/Utilities/Matlab/scripts/layer_height.m deleted file mode 100644 index 07a24115840..00000000000 --- a/Utilities/Matlab/scripts/layer_height.m +++ /dev/null @@ -1,155 +0,0 @@ -% McDermott -% 9-23-13 -% layer_height.m -% -% replaces old layer_height.f (by Kevin McGrattan) used to post-process HGL cases - -close all -clear all - -% this is horrendous, but the ls command was giving file permission problems with Samba -list_dir = dir('../../Validation/*'); -k = 0; -for i=1:length(list_dir) - Output_Directory = (['../../../out/',list_dir(i).name]); - if exist(Output_Directory) - list_files = dir([Output_Directory,'/*HGL.input']); - if size(list_files)>0 - for j=1:length(list_files) - if ~strcmp(list_files(j).name(1),'.') % ignore hidden files - k=k+1; - output_dir{k} = ['../../../out/',list_dir(i).name,'/']; - input_file{k} = list_files(j).name; - end - end - end - end -end - -%return % uncomment to just list the files for testing purposes - -ntd=20000; -ncd=500; - -for i=1:length(input_file) % input_file loop - - clear M - tmp=zeros(ntd,ncd); - - fid = fopen([output_dir{i},input_file{i}],'r'); - - % read number of trees - ntrees = str2num(fgetl(fid)); - - % read number of TCs in the tree - ntc = str2num(fgetl(fid)); - for n=1:ntc - tline = fgetl(fid); - cell_array = textscan(tline,'%s','delimiter',' ','MultipleDelimsAsOne',1); - S = cell_array{:}; - ztc(n)=str2num(S{1}); - for nn=1:ntrees - icol(n,nn)=str2num(S{nn+1}); - end - end - - % read weight of each tree - tline = fgetl(fid); - cell_array = textscan(tline,'%s','delimiter',' ','MultipleDelimsAsOne',1); - S = cell_array{:}; - for nn=1:ntrees - wgt(nn)=str2num(S{nn}); - end - - % read data file name - infile = fgetl(fid); - - % read number of columns in data file - nc = str2num(fgetl(fid)); - - % read row number where data starts - nr = str2num(fgetl(fid)); - - % read ceiling height - z_h = str2num(fgetl(fid)); - - % read starting time - t_start = str2num(fgetl(fid)); - - % read name of output file - outfile = fgetl(fid); - fclose(fid); - - % read data from file - M = importdata([output_dir{i},infile],',',nr-1); - t = M.data(:,1); - d = M.data(:,2:nc); - - z_0 = 0; - for n=1:ntc-1 - z(n) = (ztc(n)+ztc(n+1))/2; - end - z(ntc) = z_h; - - fout = fopen([output_dir{i},outfile],'w'); - - fprintf(fout,'%s, %s, %s, %s\n','Time','Height','T_lower','T_upper'); - - for i=1:length(t) % time loop - if t(i)zint(i) - if z_0>=zint(i) - i1 = i1 + tmp(i,n)*(z(n)-z_0); - end - if z_0zint(i) - if z(n-1)>=zint(i) - i1 = i1 + tmp(i,n)*(z(n)-z(n-1)); - end - if z(n-1)0 - annotation('textarrow',[0.45,0.45+0.1*cosd(theta_s)],[0.23,0.23+0.1*sind(theta_s)],... - 'String','slope','Interpreter',Font_Interpreter,'FontSize',Scat_Label_Font_Size) - end - - % add Git revision - Git_Filename = [out_dir,CHID,'_git.txt']; - addverstr(gca,Git_Filename,'linear') - - % save figure - print(gcf,Image_File_Type,... - [plot_dir,'level_set_ellipse_',num2str(slope,'%02d'),'deg']) - -end - -max_err = max(error_table{:,2:end}(:)); -if max_err>.2 - display(['Matlab Warning: LS_ellipse is out of tolerance. Max error = ',num2str(max_err)]) -end - -% plot error_table to be used for verification -clf -hold on -box on -% standardize figure -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Scat_Label_Font_Size) -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -for i=2:width(error_table) - plot(error_table{:,1},error_table{:,i},'.-','color',colors(i-1),... - 'displayname',error_table.Properties.VariableNames{i}) -end -xlabel('compass angle (°)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) -ylabel('relative error (-)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) -lh=legend(); - -% add Git revision -Git_Filename = [out_dir,CHID,'_git.txt']; -addverstr(gca,Git_Filename,'linear') - -% save figure -print(gcf,Image_File_Type,[plot_dir,'level_set_ellipse_error']) - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% fire spread functions -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -% calculate wind adjustment vector -function [phi_w_x,phi_w_y]=wind_adj(U,theta_w) - U=U*60; %convert to m/min - sigma=50; % svr (cm^-1), FDS default - beta=0.01; % packing ratio (-), FDS default - % Rothermel optimum packing ratio - beta_op=0.20395*(sigma^-0.8189); - beta_ratio=beta./beta_op; - % Rothermel wind coefficient - C=7.47*exp(-0.8711*sigma.^0.55); - B=0.15988*sigma.^0.54; - E=0.715*exp(-0.01094*sigma); - phi_w_x=C.*(3.281*U).^B.*(beta_ratio).^-E*sind(theta_w); - phi_w_y=C.*(3.281*U).^B.*(beta_ratio).^-E*cosd(theta_w); -end - -% calculate slope adjustment vector -function [phi_s_x,phi_s_y] = slope_adj(dzdx,dzdy) - beta=0.01; % packing ratio (-), FDS default - % Rothermel optimum packing ratio - dzds = sqrt(dzdx^2+dzdy^2); - phi_s_x = 5.275*beta^-0.3*dzdx*dzds; - phi_s_y = 5.275*beta^-0.3*dzdy*dzds; -end - -% calculate virtual wind vector for slope -function [u_virtual,v_virtual]= virtual_wind(phi_s_x,phi_s_y) - sigma = 50; % svr (cm^-1), FDS default - beta = 0.01; % packing ratio (-), FDS default - % Rothermel optimum packing ratio - beta_op = 0.20395*(sigma^-0.8189); - beta_ratio = beta./beta_op; - % Rothermel wind coefficient - C = 7.47*exp(-0.8711*sigma.^0.55); - B = 0.15988*sigma.^0.54; - E = 0.715*exp(-0.01094*sigma); - phi_s=sqrt(phi_s_x^2+phi_s_y^2); - if (phi_s>0) - uv_tmp = 0.3048/phi_s*(phi_s/C*beta_ratio^E)^(1/B); - else - uv_tmp = 0; - end - % divide by 60 to maintain units of m/s elsewhere - u_virtual = uv_tmp*phi_s_x/60; - v_virtual = uv_tmp*phi_s_y/60; -end diff --git a/Utilities/Matlab/scripts/mass_balance.m b/Utilities/Matlab/scripts/mass_balance.m deleted file mode 100644 index 02586b8c406..00000000000 --- a/Utilities/Matlab/scripts/mass_balance.m +++ /dev/null @@ -1,71 +0,0 @@ -% McDermott -% 05 Dec 2017 -% mass_balance.m - -close all -clear all - -plot_mass_balance('mass_flux_wall_yindex','Primitive Species Mass Balance'); -plot_mass_balance('mass_flux_wall_zindex','Lumped Species Mass Balance'); - - -function [] = plot_mass_balance(chid,title_text) - -plot_style -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -ddir = '../../Verification/Species/'; -M = importdata([ddir,chid,'_mass.csv'],',',2); - -t = M.data(:,1); -m = M.data(:,find(strcmp(M.colheaders,'WATER VAPOR'))); -dmdt = zeros(length(t),1); -for i=2:length(t) - dmdt(i) = (m(i)-m(i-1))/(t(i)-t(i-1)); -end - -F = importdata([ddir,chid,'_devc.csv'],',',2); - -mdot_in = F.data(:,find(strcmp(F.colheaders,'H2O in'))); -mdot_out = F.data(:,find(strcmp(F.colheaders,'H2O out'))); - -bal = dmdt - mdot_in - mdot_out; - -plot(t,zeros(1,length(t)),'k-'); hold on -H(1)=plot(t,mdot_in); -H(2)=plot(t,-mdot_out); -H(3)=plot(t,bal); - -ylabel('mass flow (kg/s)', 'FontSize',Label_Font_Size) -xlabel('time (s)', 'FontSize',Label_Font_Size) - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -lh=legend(H,'Inlet H2O','Outlet H2O','dm/dt+out-in'); -set(lh,'FontSize',Key_Font_Size) - -text(100,18e-3,title_text,'FontSize',Title_Font_Size,'FontName',Font_Name,'Interpreter',Font_Interpreter) - -% check balance and report error - -mass_error = abs(mean(bal(find(t>1000)))); -if mass_error > 1e-5 - disp(['Matlab Warning: mass error = ',num2str(mass_error),' in ',chid]) -end - -% add version string if file is available - -Git_Filename = [ddir,chid,'_git.txt']; -addverstr(gca,Git_Filename,'linear') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf',['../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/',chid,'_mass_balance']) - -end diff --git a/Utilities/Matlab/scripts/mesh_transformation.m b/Utilities/Matlab/scripts/mesh_transformation.m deleted file mode 100644 index 5fc3ee52062..00000000000 --- a/Utilities/Matlab/scripts/mesh_transformation.m +++ /dev/null @@ -1,136 +0,0 @@ -% McDermott and McGrattan -% 10-4-12 -% mesh_transformation.m -% -% Postprocessing script to extract transformation mapping from SMV. - -close all -clear all - -% Read SMV file and store transformations - -datadir = '../../Verification/Miscellaneous/'; - -if ~exist([datadir,'mesh_transformation.smv']) - display(['Error: File ', [datadir,'mesh_transformation.smv'],' does not exist. Skipping case.']) - return -end - -fid = fopen([datadir,'mesh_transformation.smv'],'r'); - -I = 50; -J = 50; -LX = 1.5; -LY = 1.5; -dx = LX/I; -dy = LY/J; - -while 1 - tline = fgetl(fid); - if ~ischar(tline), break, end - if strcmp(tline,'TRNX') - %disp(tline) - for i=1:3 - skip=fgetl(fid); - end - for i=1:I+1 - tline=fgetl(fid); - C=textscan(tline,'%f'); - %disp(C{1}) - cx(i) = C{1}(1)*dx; - x(i) = C{1}(2); - end - end - if strcmp(tline,'TRNY') - %disp(tline) - for j=1:3 - skip=fgetl(fid); - end - for j=1:J+1 - tline=fgetl(fid); - C=textscan(tline,'%f'); - %disp(C{1}) - cy(j) = C{1}(1)*dy; - y(j) = C{1}(2); - end - end -end -fclose(fid); - -% Make the plots - -% From the mesh_transformation.fds input file: -CC = [0.3 1.2]; -PC = [0.5 1.0]; - -plotdir = '../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/'; -plot_style -Title_Font_Size=20; - -XMinorTick = 0.1:0.1:1.4; - -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Scat_Plot_X Scat_Plot_Y Scat_Plot_Width Scat_Plot_Height]) - -plot(cx,x,'k-','LineWidth',2); hold on -for i=1:length(XMinorTick) - % piece-wise linear function - if XMinorTick(i) 80. - display(['Matlab Warning: Timing for openmp_test64 out of tolerance.',num2str(time64(4))]) -end -if time128(4) > 80. - display(['Matlab Warning: Timing for openmp_test128 out of tolerance.',num2str(time128(4))]) -end - diff --git a/Utilities/Matlab/scripts/part_drag_profile.m b/Utilities/Matlab/scripts/part_drag_profile.m deleted file mode 100644 index 59d4e48454b..00000000000 --- a/Utilities/Matlab/scripts/part_drag_profile.m +++ /dev/null @@ -1,101 +0,0 @@ -% McDermott -% 8-27-24 -% part_drag_profile.m - -close all -clear all - -plot_style - -figure -set(gcf,'Visible',Figure_Visibility); -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -% prescribed velocity profile - -% mpv = 4.; % kg/m^3, mass_per_volume (from FDS input file) -% v_xb = 10^3; % volume of XB region on init line in FDS input file -% nppc = 10; % number of particles per cell -% n = 5*5*20*nppc; % number of particles -% rho_p = 400; % density of grass, kg/m^3 -r_p = 0.001; % radius, m -l_p = 0.02; % length, m -v_p = pi*(r_p)^2*l_p; % volume of a single particle, m^3 -shape_factor = 0.25; % assumes random orientation of cylinders -a_p = shape_factor*l_p*(2*pi*r_p); % projected area, m^2 -% m_p = rho_p*v_p; % mass of single particle, kg -% pwt = mpv*v_xb/(n*m_p) % particle weight factor - -z = linspace(0,10,20); -u_z = z; -c_d = 2.8; % from FDS input file (specified) -rho_g = 1.195; % from FDS out file -f_x = c_d * a_p * 0.5*rho_g*(u_z.^2); % drag experienced by a single particle - -H(1)=plot(z,-f_x,'k-'); hold on - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -ddir='../../Verification/WUI/'; -chid={'part_drag_prof_ux','part_drag_prof_uy','part_drag_prof_uz',... - 'part_drag_prof_vx','part_drag_prof_vy','part_drag_prof_vz',... - 'part_drag_prof_wx','part_drag_prof_wy','part_drag_prof_wz'}; -j={1,2,3,1,2,3,1,2,3}; % coordinate direction (x=1, y=2, z=3) - -for i=1:length(chid) % chid_for - - skip_case = 0; - if ~exist([ddir,chid{i},'_1.prt5']) - display(['Error: File ' [ddir,chid{i},'_1.prt5'] ' does not exist. Skipping case.']) - skip_case = 1; - end - - if skip_case - return - end - - [STIME, XP, YP, ZP, QP] = read_prt5([ddir,chid{i},'_1.prt5'],'real*4'); - - switch j{i} - case 1 - H(2)=plot(XP(end,:),QP(end,:,1,1)./QP(end,:,1,2),'b.'); - v = abs( c_d * a_p * 0.5*rho_g*(XP(end,:).^2) - QP(end,:,1,1)./QP(end,:,1,2) ); - case 2 - H(2)=plot(YP(end,:),QP(end,:,1,1)./QP(end,:,1,2),'b.'); - v = abs( c_d * a_p * 0.5*rho_g*(YP(end,:).^2) - QP(end,:,1,1)./QP(end,:,1,2) ); - case 3 - H(2)=plot(ZP(end,:),QP(end,:,1,1)./QP(end,:,1,2),'b.'); - v = abs( c_d * a_p * 0.5*rho_g*(ZP(end,:).^2) - QP(end,:,1,1)./QP(end,:,1,2) ); - end - - err = norm(v)/length(v); - if err>1e-4 - display(['Error: Case ' [ddir,chid{i}] ' error = ' num2str(err)]) - end - -end % chid_for - -xlabel('Position (m)','FontSize',Label_Font_Size) -ylabel('Drag Force (N)','FontSize',Label_Font_Size) -lh=legend(H,'exact','FDS part'); -set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size) - -Git_Filename = [ddir,chid{1},'_git.txt']; -addverstr(gca,Git_Filename,'linear') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf','../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/part_drag_profile'); - - - - - - - - - diff --git a/Utilities/Matlab/scripts/particle_size_distribution.m b/Utilities/Matlab/scripts/particle_size_distribution.m deleted file mode 100644 index 4360847d8fb..00000000000 --- a/Utilities/Matlab/scripts/particle_size_distribution.m +++ /dev/null @@ -1,89 +0,0 @@ -% McDermott -% 23 Oct 2017 -% particle_size_distribution.m -% -% This script generates the Rosin-Rammler / log-normal particle size distribution -% plot in the FDS Tech Guide (presently Fig. 8.1). - -close all -clear all - -plot_style -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -D_v50 = 1; - -gamma = 2.4; -sigma = 1.15/gamma; - -N = 100; -D = linspace(0,3,N); -dD = D(2)-D(1); - -for i=1:N - - if i==1 - F1(i) = 0; - else - DP = 0.5*(D(i-1)+D(i)); - F1(i) = F1(i-1) + exp(-log(DP/D_v50)^2/(2*sigma^2)) * dD / (sqrt(2*pi)*sigma*DP); - end - - F2(i) = 1 - exp(-0.693*(D(i)/D_v50)^gamma); - - if D(i)> read_prt5('terminal_velocity.prt5','real*8') -% -% precision = 'real*4' if EB_PART_FILE=.FALSE. on the DUMP line -% precision = 'real*8' if EB_PART_FILE=.TRUE. on the DUMP line -% -% To read part files generated by FDS+Evac use -% -% >> read_prt5('evac_casename.prt5','real*4','evac') - -function [STIME, XP, YP, ZP, QP, varargout] = read_prt5(filename,precision,varargin) - -nout = max(nargout,1); - -evac = false; -if size(varargin)>0 - if strcmp(varargin{1},'evac') | strcmp(varargin{1},'EVAC') | strcmp(varargin{1},'Evac') - evac = true; - end -end - -fid = fopen(filename); - -% The DUMMY lines are 4 byte placeholders that apparently fortran puts at the -% beginning and end of all lines. I only knew of this thanks to Glenn. - -DUMMY = fread(fid,1,'integer*4'); -ONE_INTEGER = fread(fid,1,'integer*4'); -DUMMY = fread(fid,1,'integer*4'); - -DUMMY = fread(fid,1,'integer*4'); -INT_VERSION = fread(fid,1,'integer*4'); -DUMMY = fread(fid,1,'integer*4'); - -DUMMY = fread(fid,1,'integer*4'); -N_PART = fread(fid,1,'integer*4'); -DUMMY = fread(fid,1,'integer*4'); - -for NPC=1:N_PART - - DUMMY = fread(fid,1,'integer*4'); - PC = fread(fid,2,'integer*4'); N_QUANTITIES(NPC) = PC(1); - DUMMY = fread(fid,1,'integer*4'); - - for NQ=1:N_QUANTITIES(NPC) - DUMMY = fread(fid,1,'integer*4'); - SMOKEVIEW_LABEL{NQ} = fgets(fid,30); - DUMMY = fread(fid,1,'integer*4'); - - DUMMY = fread(fid,1,'integer*4'); - UNITS{NQ} = fgets(fid,30); - DUMMY = fread(fid,1,'integer*4'); - end - -end - -n = 0; -while ~feof(fid) - n = n + 1; - - DUMMY = fread(fid,1,'integer*4'); - stime_tmp = fread(fid,1,precision); - DUMMY = fread(fid,1,'integer*4'); - - if size(stime_tmp,1)==0 - break - else - STIME(n) = stime_tmp; - end - - for NPC=1:N_PART - - DUMMY = fread(fid,1,'integer*4'); - NPLIM = fread(fid,1,'integer*4'); - DUMMY = fread(fid,1,'integer*4'); - - DUMMY = fread(fid,1,'integer*4'); - xp = fread(fid,NPLIM,precision); - yp = fread(fid,NPLIM,precision); - zp = fread(fid,NPLIM,precision); - if evac - ap1 = fread(fid,NPLIM,precision); - ap2 = fread(fid,NPLIM,precision); - ap3 = fread(fid,NPLIM,precision); - ap4 = fread(fid,NPLIM,precision); - end - DUMMY = fread(fid,1,'integer*4'); - - for NP=1:NPLIM - XP(n,NP,NPC) = xp(NP); - YP(n,NP,NPC) = yp(NP); - ZP(n,NP,NPC) = zp(NP); - if evac & nout==6 - AP(n,NP,NPC,1) = ap1(NP); - AP(n,NP,NPC,2) = ap2(NP); - AP(n,NP,NPC,3) = ap3(NP); - AP(n,NP,NPC,4) = ap4(NP); - end - end - %clear xp yp zp - - DUMMY = fread(fid,1,'integer*4'); - TA = fread(fid,NPLIM,'integer*4'); - DUMMY = fread(fid,1,'integer*4'); - - if N_QUANTITIES(NPC)>0 - DUMMY = fread(fid,1,'integer*4'); - for NQ=1:N_QUANTITIES(NPC) - qp = fread(fid,NPLIM,precision); - for NP=1:NPLIM - QP(n,NP,NPC,NQ) = qp(NP); - end - %clear qp - end - DUMMY = fread(fid,1,'integer*4'); - end - - end - -end -fclose(fid); - -if evac & nout==6 - varargout{1} = AP; -end - -%display('Part file read successfully!') - -% Examples for plotting position and quantities - -%plot(STIME,ZP(:,1,1)) % XP(time step range, particle #, part class #) -%size(STIME) -%size(QP(:, 1, 1, 1)) -%plot(STIME,QP(:,1,1,1)) % QP(time step range, particle #, part class #, quantity #) -%min(QP(:,1,1,1)) diff --git a/Utilities/Matlab/scripts/rms_cov_corr.m b/Utilities/Matlab/scripts/rms_cov_corr.m deleted file mode 100644 index 893b35172a1..00000000000 --- a/Utilities/Matlab/scripts/rms_cov_corr.m +++ /dev/null @@ -1,161 +0,0 @@ -% Floyd -% 5-23-2014 -% rms_cov_corr.m - -close all -clear all - -plot_style - -datadir='../../Verification/Controls/'; - -% load experimental data and FDS prediction - -filename = [datadir,'rms_cov_corr_devc.csv']; - -if ~exist(filename) % skip_case_if - - display(['Error: File ' filename ' does not exist. Skipping case.']) - -else - - fds_data = csvread([datadir,'rms_cov_corr_devc.csv'],2); - - startrow=500/0.02+1; - endrow=size(fds_data,1); - - umean=mean(fds_data(startrow:endrow,2)); - wmean=mean(fds_data(startrow:endrow,3)); - - udiff=fds_data(startrow:endrow,2)-umean; - wdiff=fds_data(startrow:endrow,3)-wmean; - - udiff2=udiff; - wdiff2=wdiff; - uwcova=udiff; - for i=1:endrow-startrow+1 - udiff2(i)=udiff(i)*udiff(i); - wdiff2(i)=wdiff(i)*wdiff(i); - uwcova(i)=udiff(i)*wdiff(i); - drawnow; - end - - urms=sqrt(mean(udiff2)); - wrms=sqrt(mean(wdiff2)); - uwcov=mean(uwcova); - uwcorr=uwcov/urms/wrms; - - urms_fds=fds_data(endrow,4); - uwcov_fds=fds_data(endrow,5); - uwcorr_fds=fds_data(endrow,6); - - xcalc(1)=0; - xcalc(2)=1000; - ycalc(1)=urms; - ycalc(2)=urms; - - maxval=ceil(2*urms*100)/100; - - figure - set(gca,'Units',Plot_Units) - set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - - h=plot(xcalc,ycalc,'r-',fds_data(:,1),fds_data(:,4),'k-'); - - set(gca,'FontName',Font_Name) - set(gca,'FontSize',Label_Font_Size) - xlabel('Time (s)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size,'FontName',Font_Name) - ylabel('{\it u} rms (m/s)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size,'FontName',Font_Name) - legend('Analytic','FDS','Location','East') - - % add Git revision if file is available - git_file = '../../Verification/Controls/rms_cov_corr_git.txt'; - addverstr(gca,git_file,'linear') - - % print to pdf - set(gcf,'Visible',Figure_Visibility); - set(gcf,'Units',Paper_Units); - set(gcf,'PaperUnits',Paper_Units); - set(gcf,'PaperSize',[Paper_Width Paper_Height]); - set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - plotname = ['../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/rms_cov_corr_rms']; - print(gcf,'-dpdf',plotname); - - clear h - - ycalc(1)=uwcov; - ycalc(2)=uwcov; - - maxval=ceil(2*uwcov*100)/100; - - figure - set(gca,'Units',Plot_Units) - set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - - h=plot(xcalc,ycalc,'r-',fds_data(:,1),fds_data(:,5),'k-'); - - set(gca,'FontName',Font_Name) - set(gca,'FontSize',Label_Font_Size) - xlabel('Time (s)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size,'FontName',Font_Name) - ylabel('{\it uw} covariance (m²/s²)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size,'FontName',Font_Name) - legend('Analytic','FDS','Location','East') - - % add Git revision if file is available - git_file = '../../Verification/Controls/rms_cov_corr_git.txt'; - addverstr(gca,git_file,'linear') - - % print to pdf - set(gcf,'Visible',Figure_Visibility); - set(gcf,'Units',Paper_Units); - set(gcf,'PaperUnits',Paper_Units); - set(gcf,'PaperSize',[Paper_Width Paper_Height]); - set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - plotname = ['../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/rms_cov_corr_cov']; - print(gcf,'-dpdf',plotname); - - clear h - - ycalc(1)=uwcorr; - ycalc(2)=uwcorr; - - maxval=ceil(2*uwcorr*100)/100; - - figure - set(gca,'Units',Plot_Units) - set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - - h=plot(xcalc,ycalc,'r-',fds_data(:,1),fds_data(:,6),'k-'); - - set(gca,'FontName',Font_Name) - set(gca,'FontSize',Label_Font_Size) - xlabel('Time (s)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size,'FontName',Font_Name) - ylabel('{\it uw} cross correlation','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size,'FontName',Font_Name) - legend('Analytic','FDS','Location','NorthEast') - - % add Git revision if file is available - git_file = '../../Verification/Controls/rms_cov_corr_git.txt'; - addverstr(gca,git_file,'linear') - - % print to pdf - set(gcf,'Visible',Figure_Visibility); - set(gcf,'Units',Paper_Units); - set(gcf,'PaperUnits',Paper_Units); - set(gcf,'PaperSize',[Paper_Width Paper_Height]); - set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - plotname = ['../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/rms_cov_corr_corr']; - print(gcf,'-dpdf',plotname); - - clear h - - % check errors - if abs((urms-urms_fds)/urms) > 0.001 - display(['Matlab Warning: urms in rms_cov_corr is out of tolerance.']) - end - if abs((uwcov-uwcov_fds)/urms) > 0.001 - display(['Matlab Warning: uwcov in rms_cov_corr is out of tolerance.']) - end - if abs((uwcorr-uwcorr_fds)/urms) > 0.001 - display(['Matlab Warning: uwcorr in rms_cov_corr is out of tolerance.']) - end - -end % skip_case_if diff --git a/Utilities/Matlab/scripts/scaling_tests.m b/Utilities/Matlab/scripts/scaling_tests.m deleted file mode 100644 index e6fdb38f56b..00000000000 --- a/Utilities/Matlab/scripts/scaling_tests.m +++ /dev/null @@ -1,158 +0,0 @@ -% McGrattan -% 10-21-2015 -% scaling_tests.m -% -% Read _cpu.csv files for the MPI weak and strong scaling test cases - -clear all -close all - -plot_style - -outdir = '../../../out/MPI_Scaling_Tests/'; - -M(1) = importdata([outdir,'strong_scaling_test_001_cpu.csv'],',',1); -M(2) = importdata([outdir,'strong_scaling_test_008_cpu.csv'],',',1); -M(3) = importdata([outdir,'strong_scaling_test_032_cpu.csv'],',',1); -M(4) = importdata([outdir,'strong_scaling_test_064_cpu.csv'],',',1); -M(5) = importdata([outdir,'strong_scaling_test_096_cpu.csv'],',',1); -M(6) = importdata([outdir,'strong_scaling_test_192_cpu.csv'],',',1); -M(7) = importdata([outdir,'strong_scaling_test_288_cpu.csv'],',',1); -M(8) = importdata([outdir,'strong_scaling_test_432_cpu.csv'],',',1); - -r = [1 8 32 64 96 192 288 432]; -r2 = [.1 8 32 64 96 192 432 1000]; - -[n_rows,n_cols] = size(M(1).data); - -for j=1:n_cols - for i=1:8 - t(i,j) = M(i).data(1,j)/M(1).data(1,n_cols); - t2(i) = 1./r2(i); - end -end - -if t(8,n_cols)>4/r(8) || t(8,n_cols)<1/r(8) - display(['Error: strong scaling test out of tolerance']) -end - -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -H1(1) = loglog(r2,2*t2,'k:'); hold on -H1(2) = loglog(r2,t2,'k:'); hold on -H1(3) = loglog(r2,t2/2,'k:'); hold on -H1(4) = loglog(r2,t2/4,'k:'); hold on -H1(5) = loglog(r2,t2/8,'k:'); hold on -H1(6) = loglog(r2,t2/16,'k:'); hold on -H1(7) = loglog(r2,t2/32,'k:'); hold on -H1(8) = loglog(r2,t2/64,'k:'); hold on -H1(9) = loglog(r2,t2/128,'k:'); hold on -H1(10) = loglog(r2,t2/256,'k:'); hold on - -H(1) = loglog(r,t(:,n_cols),'k-o'); -H(2) = loglog(r,t(:,3),'r-o'); -H(3) = loglog(r,t(:,4),'b-o'); -H(4) = loglog(r,t(:,5),'m-o'); -H(5) = loglog(r,t(:,6),'c-o'); -H(6) = loglog(r,t(:,12),'g-o'); -H(7) = loglog(r,t(:,10),'y-o'); -H(8) = loglog(r,t(:,2),'k-s'); - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) -xlabel('MPI Processes','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) -ylabel('Relative Wall Clock Time','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) -Min_Ind = 1.0; -Max_Ind = 1000; -Min_Dep = 0.00001; -Max_Dep = 1.; -axis([Min_Ind Max_Ind Min_Dep Max_Dep]) -set(gca,'XTickLabel',num2str(get(gca,'XTick')')) -yticks([0.000001 0.00001 0.0001 0.001 0.01 0.1 1]); -Title_Position(1) = 0.40; -Title_Position(2) = 0.95; -X_Title_Position = 10^(log10(Min_Ind)+Title_Position(1)*(log10(Max_Ind)-log10(Min_Ind))); -Y_Title_Position = 10^(log10(Min_Dep)+Title_Position(2)*(log10(Max_Dep)-log10(Min_Dep))); -text(X_Title_Position,Y_Title_Position,'Strong Scaling Test','FontSize',Title_Font_Size,'FontName',Font_Name,'Interpreter',Font_Interpreter) -legend_handle = legend(H,'Total','DIVG','MASS','VELO','PRES','COMM','RADI','MAIN','Location','NorthEast'); -set(legend_handle,'Interpreter',Font_Interpreter); -set(legend_handle,'Fontsize',8); - -git_file = [outdir,'strong_scaling_test_288_git.txt']; -addverstr(gca,git_file,'loglog') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf',['../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/strong_scaling_test']) - -close all -clear all -plot_style - -outdir = '../../../out/MPI_Scaling_Tests/'; - -M(1) = importdata([outdir,'weak_scaling_test_001_cpu.csv'],',',1); -M(2) = importdata([outdir,'weak_scaling_test_002_cpu.csv'],',',1); -M(3) = importdata([outdir,'weak_scaling_test_004_cpu.csv'],',',1); -M(4) = importdata([outdir,'weak_scaling_test_008_cpu.csv'],',',1); -M(5) = importdata([outdir,'weak_scaling_test_016_cpu.csv'],',',1); -M(6) = importdata([outdir,'weak_scaling_test_032_cpu.csv'],',',1); -M(7) = importdata([outdir,'weak_scaling_test_064_cpu.csv'],',',1); -M(8) = importdata([outdir,'weak_scaling_test_128_cpu.csv'],',',1); -M(9) = importdata([outdir,'weak_scaling_test_192_cpu.csv'],',',1); -M(10) = importdata([outdir,'weak_scaling_test_288_cpu.csv'],',',1); -M(11) = importdata([outdir,'weak_scaling_test_432_cpu.csv'],',',1); - -r = [1 2 4 8 16 32 64 128 192 288 432]; - -[n_rows,n_cols] = size(M(1).data); - -for i=1:11 - t(i) = M(1).data(1,n_cols)/M(i).data(1,n_cols); - t2(i) = 1.; -end - -if t(11)>1. || t(11)<0.4 - display(['Error: weak scaling test out of tolerance']) -end - -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -H(1) = semilogx(r,t,'ko'); hold on -H(2) = semilogx(r,t2,'k--'); - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) -xlabel('MPI Processes','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) -ylabel('Efficiency','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size) -Min_Ind = 1.0; -Max_Ind = 1000; -Min_Dep = 0.0; -Max_Dep = 1.2; -axis([Min_Ind Max_Ind Min_Dep Max_Dep]) -set(gca,'XTickLabel',num2str(get(gca,'XTick')')) -set(gca,'YTickLabel',num2str(get(gca,'YTick')')) -Title_Position(1) = 0.60; -Title_Position(2) = 0.90; -X_Title_Position = 10^(log10(Min_Ind)+Title_Position(1)*(log10(Max_Ind)-log10(Min_Ind))); -Y_Title_Position = Min_Dep+Title_Position(2)*(Max_Dep-Min_Dep); -text(X_Title_Position,Y_Title_Position,'Weak Scaling Test','FontSize',Title_Font_Size,'FontName',Font_Name,'Interpreter',Font_Interpreter) -legend(H,'FDS','Ideal','Location','Southwest') - -git_file = [outdir,'weak_scaling_test_288_git.txt']; -addverstr(gca,git_file,'semilogx') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf',['../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/weak_scaling_test']) - diff --git a/Utilities/Matlab/scripts/shunn_cc_mms_error.m b/Utilities/Matlab/scripts/shunn_cc_mms_error.m deleted file mode 100644 index 805d7a8a75e..00000000000 --- a/Utilities/Matlab/scripts/shunn_cc_mms_error.m +++ /dev/null @@ -1,226 +0,0 @@ -%!/usr/bin/matlab -%Vanella from McDermott shunn_mms_error.m: -%03-09-2018 - -close all -clear all - -% Shunn et al. Problem 3 parameters: -r0 = 5.; -r1 = 1.; -uf = 0.5; -vf = 0.5; -k = 2.; -w = 2.; -mu = 0.001; -D = 0.001; - -% Analytical solutions: -vd2d_mms_z = @(x,y,t) ... -( 1. + sin(pi*k*(x-uf*t))*sin(pi*k*(y-vf*t))*cos(pi*w*t) )/ ... -( (1+r0/r1) + (1-r0/r1)*sin(pi*k*(x-uf*t))*sin(pi*k*(y-vf*t))*cos(pi*w*t)); - -vd2d_mms_rho = @(x,y,t) ... - 1./( vd2d_mms_z(x,y,t)/r1 + (1-vd2d_mms_z(x,y,t))/r0 ); - -vd2d_mms_u = @(x,y,t) ... - uf + (r1-r0)/vd2d_mms_rho(x,y,t)*(-w/(4.*k))*... - cos(pi*k*(x-uf*t))*sin(pi*k*(y-vf*t))*sin(pi*w*t); - -vd2d_mms_v = @(x,y,t) ... - vf + (r1-r0)/vd2d_mms_rho(x,y,t)*(-w/(4.*k))*... - sin(pi*k*(x-uf*t))*cos(pi*k*(y-vf*t))*sin(pi*w*t); - -vd2d_mms_H = @(x,y,t) ... - 0.5*(vd2d_mms_u(x,y,t)-uf)*(vd2d_mms_v(x,y,t)-vf); - -vd2d_mms_p = @(x,y,t) ... - vd2d_mms_rho(x,y,t)*(vd2d_mms_H(x,y,t) - ... - 0.5*(vd2d_mms_u(x,y,t)^2 + vd2d_mms_v(x,y,t)^2)); - -L = 2; -nx = [32,64,128,256,320]; -dx = L./nx; - -% % visualize field in time -% n=1; -% x=linspace(-L/2,L/2,nx(n)+1); -% xc = x(1:nx(n)) + .5*dx(n); -% yc = xc; -% for t=linspace(0,1,100) -% for j=1:nx(n) -% for i=1:nx(n) -% %pres(i,j) = vd2d_mms_p(xc(i),yc(j),t); -% hfld(i,j) = vd2d_mms_H(xc(i),yc(j),t); -% end -% end -% surf(xc,yc,hfld) -% axis([-1 1 -1 1 0 1]) -% pause(0.001) -% end -% return - -datadir = '../../Verification/Complex_Geometry/'; - -file_s=1; -file_f=2; - -file_str = ['exp_chm';'exp_gdv']; - -skip_case = 0; -for ifile=file_s:file_f - - file(ifile).name = { ['shunn3_32_cc_' file_str(ifile,:) '_mms.csv'], ... - ['shunn3_64_cc_' file_str(ifile,:) '_mms.csv'], ... - ['shunn3_128_cc_' file_str(ifile,:) '_mms.csv'],... - ['shunn3_256_cc_' file_str(ifile,:) '_mms.csv'],... - ['shunn3_320_cc_' file_str(ifile,:) '_mms.csv']}; - for n=1:length(file(ifile).name) - if ~exist([datadir,file(ifile).name{n}]) - display(['Error: File ' [datadir,file(ifile).name{n}] ... - ' does not exist. Skipping case.']) - skip_case = 1; - end - end -end -if skip_case - return -end - -for ifile=file_s:file_f - - e_r = zeros(length(file(ifile).name),1); - e_z = zeros(length(file(ifile).name),1); - e_u = zeros(length(file(ifile).name),1); - e_H = zeros(length(file(ifile).name),1); - - - for n=1:length(file(ifile).name) - - %disp(filename(n)) - - M = importdata([datadir,file(ifile).name{n}],',',2); % FDS results. - T = str2num(M.textdata{2,1}); % exact time value - - x=linspace(-L/2,L/2,nx(n)+1); - xc = x(1:nx(n)) + .5*dx(n); - yc = xc; - - % inialize error arrays - rho_error = zeros(nx(n),nx(n)); - e_r_vec = zeros(nx(n)*nx(n),1); - - z_error = zeros(nx(n),nx(n)); - e_z_vec = zeros(nx(n)*nx(n),1); - - u_error = zeros(nx(n),nx(n)); - e_u_vec = zeros(nx(n)*nx(n),1); - - H_error = zeros(nx(n),nx(n)); - e_H_vec = zeros(nx(n)*nx(n),1); - - p = 0; - for j=1:nx(n) - for i=1:nx(n) - p = p+1; - - rho = M.data(p,1); - rho_mms = vd2d_mms_rho(xc(i),yc(j),T); - rho_error(i,j) = rho - rho_mms; - e_r_vec(p) = rho_error(i,j); - - z = M.data(p,2); - z_mms = vd2d_mms_z(xc(i),yc(j),T); - z_error(i,j) = z - z_mms; - e_z_vec(p) = z_error(i,j); - - u = M.data(p,3); - u_mms = vd2d_mms_u(x(i+1),yc(j),T); - u_error(i,j) = u - u_mms; - e_u_vec(p) = u_error(i,j); - - H = M.data(p,5); - H_mms = vd2d_mms_H(xc(i),yc(j),T); - H_error(i,j) = H - H_mms; - e_H_vec(p) = H_error(i,j); - end - end - - N = nx(n)*nx(n); - - e_r(n) = norm(e_r_vec(1:N),2)/nx(n); - e_z(n) = norm(e_z_vec(1:N),2)/nx(n); - e_u(n) = norm(e_u_vec(1:N),2)/nx(n); - e_H(n) = norm(e_H_vec(1:N),2)/nx(n); - end - - plot_style - figure - set(gca,'Units',Plot_Units) - set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - - hh(1)=loglog(dx,e_r,'ko-'); - hold on - hh(2)=loglog(dx,e_z,'ks-'); - hh(3)=loglog(dx,e_u,'k>-'); - hh(4)=loglog(dx,e_H,'k+-'); - hh(5)=loglog(dx,dx,'k--'); - hh(6)=loglog(dx,dx.^2,'k-'); - if (ifile==1) - axis([10^-3 10^-1 10^-6 10^-1]) - else - axis([10^-3 10^-1 10^-6 10^0]) - end - set(gca,'FontName',Font_Name) - set(gca,'FontSize',Title_Font_Size) - - xlabel('{\it \Deltax} (m)','FontSize',Title_Font_Size,'Interpreter',... - Font_Interpreter,'Fontname',Font_Name) - ylabel('{\it L_2} Error','FontSize',Title_Font_Size,'Interpreter', ... - Font_Interpreter,'Fontname',Font_Name) - lh=legend(hh,'FDS {\it \rho}','FDS {\it Z}','FDS {\it u}',... - 'FDS {\it H}','{\it O(\Deltax)}','{\it O(\Deltax^2)}',... - 'location','northwest'); - set(lh,'FontSize',Title_Font_Size,'Interpreter',Font_Interpreter,... - 'Fontname',Font_Name) - - % add Git version if file is available - Git_Filename = [datadir,'shunn3_256_cc_exp_chm_git.txt']; - addverstr(gca,Git_Filename,'loglog') - - % print to pdf - set(gcf,'Visible',Figure_Visibility); - set(gcf,'Units',Paper_Units); - set(gcf,'PaperUnits',Paper_Units); - set(gcf,'PaperSize',[Paper_Width Paper_Height]); - set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - - strng=['../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/' ... - 'shunn_cc_' file_str(ifile,:) '_mms_convergence']; - print(gcf,'-dpdf',strng) - - if (ifile==1) % Central flux limiter cases: - % check errors - if e_r(end) > 3e-4 - display(['Matlab Warning: Density in shunn3 ' ... - file_str(ifile,:) ' is out of tolerance. e_r = ',... - num2str(e_r(end))]) - end - if e_z(end) > 1e-4 - display(['Matlab Warning: Mixture fraction in shunn3 ' ... - file_str(ifile,:) ' is out of tolerance. e_z = ', ... - num2str(e_z(end))]) - end - if e_u(end) > 3e-5 - display(['Matlab Warning: Velocity in shunn3 ' ... - file_str(ifile,:) ' is out of tolerance. e_u = ', ... - num2str(e_u(end))]) - end - if e_H(end) > 2e-3 - display(['Matlab Warning: Pressure in shunn3 ' ... - file_str(ifile,:) ' is out of tolerance. e_H = ', ... - num2str(e_H(end))]) - end - end - %disp([file_str(ifile,:) ', Err u=' num2str(e_u(end))]) -end diff --git a/Utilities/Matlab/scripts/shunn_mms_error.m b/Utilities/Matlab/scripts/shunn_mms_error.m deleted file mode 100644 index dbd97935d49..00000000000 --- a/Utilities/Matlab/scripts/shunn_mms_error.m +++ /dev/null @@ -1,189 +0,0 @@ -%!/usr/bin/matlab -%McDermott -%09-04-2013 - -close all -clear all - -% Shunn et al. Problem 3 parameters -r0 = 5.; -r1 = 1.; -uf = 0.5; -vf = 0.5; -k = 2.; -w = 2.; -mu = 0.001; -D = 0.001; - -% analytical solutions -vd2d_mms_z = @(x,y,t) ... - ( 1. + sin(pi*k*(x-uf*t))*sin(pi*k*(y-vf*t))*cos(pi*w*t) )/ ... - ( (1+r0/r1) + (1-r0/r1)*sin(pi*k*(x-uf*t))*sin(pi*k*(y-vf*t))*cos(pi*w*t) ); - -vd2d_mms_rho = @(x,y,t) ... - 1./( vd2d_mms_z(x,y,t)/r1 + (1-vd2d_mms_z(x,y,t))/r0 ); - -vd2d_mms_u = @(x,y,t) ... - uf + (r1-r0)/vd2d_mms_rho(x,y,t)*(-w/(4.*k))*cos(pi*k*(x-uf*t))*sin(pi*k*(y-vf*t))*sin(pi*w*t); - -vd2d_mms_v = @(x,y,t) ... - vf + (r1-r0)/vd2d_mms_rho(x,y,t)*(-w/(4.*k))*sin(pi*k*(x-uf*t))*cos(pi*k*(y-vf*t))*sin(pi*w*t); - -vd2d_mms_H = @(x,y,t) ... - 0.5*(vd2d_mms_u(x,y,t)-uf)*(vd2d_mms_v(x,y,t)-vf); - -vd2d_mms_p = @(x,y,t) ... - vd2d_mms_rho(x,y,t)*(vd2d_mms_H(x,y,t) - 0.5*(vd2d_mms_u(x,y,t)^2 + vd2d_mms_v(x,y,t)^2)); - -L = 2; -nx = [32,64,128,256,512]; -dx = L./nx; - -% % visualize field in time -% n=1; -% x=linspace(-L/2,L/2,nx(n)+1); -% xc = x(1:nx(n)) + .5*dx(n); -% yc = xc; -% for t=linspace(0,1,100) -% for j=1:nx(n) -% for i=1:nx(n) -% %pres(i,j) = vd2d_mms_p(xc(i),yc(j),t); -% hfld(i,j) = vd2d_mms_H(xc(i),yc(j),t); -% end -% end -% surf(xc,yc,hfld) -% axis([-1 1 -1 1 0 1]) -% pause(0.001) -% end -% return - -datadir = '../../Verification/Scalar_Analytical_Solution/'; -%datadir = '/Volumes/firebot/FDS-SMVgitclean/Verification/Scalar_Analytical_Solution/'; % check firebot run -filename = {'shunn3_32_mms.csv','shunn3_64_mms.csv','shunn3_128_mms.csv','shunn3_256_mms.csv','shunn3_512_mms.csv'}; - -skip_case = 0; - -for n=1:length(filename) - if ~exist([datadir,filename{n}]) - display(['Error: File ' [datadir,filename{n}] ' does not exist. Skipping case.']) - skip_case = 1; - end -end - -if skip_case - return -end - -e_r = zeros(length(filename),1); -e_z = zeros(length(filename),1); -e_u = zeros(length(filename),1); -e_H = zeros(length(filename),1); - - -for n=1:length(filename) - - %disp(filename(n)) - - M = importdata([datadir,filename{n}],',',2); % collect FDS results - T = str2num(M.textdata{2,1}); % exact time value - - x=linspace(-L/2,L/2,nx(n)+1); - xc = x(1:nx(n)) + .5*dx(n); - yc = xc; - - % inialize error arrays - rho_error = zeros(nx(n),nx(n)); - e_r_vec = zeros(nx(n)*nx(n),1); - - z_error = zeros(nx(n),nx(n)); - e_z_vec = zeros(nx(n)*nx(n),1); - - u_error = zeros(nx(n),nx(n)); - e_u_vec = zeros(nx(n)*nx(n),1); - - H_error = zeros(nx(n),nx(n)); - e_H_vec = zeros(nx(n)*nx(n),1); - - p = 0; - for j=1:nx(n) - for i=1:nx(n) - p = p+1; - - rho = M.data(p,1); - rho_mms = vd2d_mms_rho(xc(i),yc(j),T); - rho_error(i,j) = rho - rho_mms; - e_r_vec(p) = rho_error(i,j); - - z = M.data(p,2); - z_mms = vd2d_mms_z(xc(i),yc(j),T); - z_error(i,j) = z - z_mms; - e_z_vec(p) = z_error(i,j); - - u = M.data(p,3); - u_mms = vd2d_mms_u(x(i+1),yc(j),T); - u_error(i,j) = u - u_mms; - e_u_vec(p) = u_error(i,j); - - H = M.data(p,5); - H_mms = vd2d_mms_H(xc(i),yc(j),T); - H_error(i,j) = H - H_mms; - e_H_vec(p) = H_error(i,j); - end - end - - N = nx(n)*nx(n); - - e_r(n) = norm(e_r_vec(1:N),2)/nx(n); - e_z(n) = norm(e_z_vec(1:N),2)/nx(n); - e_u(n) = norm(e_u_vec(1:N),2)/nx(n); - e_H(n) = norm(e_H_vec(1:N),2)/nx(n); -end - -plot_style -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -hh(1)=loglog(dx,e_r,'ko-'); -hold on -hh(2)=loglog(dx,e_z,'ks-'); -hh(3)=loglog(dx,e_u,'k>-'); -hh(4)=loglog(dx,e_H,'k+-'); -hh(5)=loglog(dx,dx,'k--'); -hh(6)=loglog(dx,dx.^2,'k-'); -axis([5*10^-4 10^-1 10^-6 10^-1]) - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Title_Font_Size) - -xlabel('{\it \Deltax} (m)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter,'Fontname',Font_Name) -ylabel('{\it L_2} Error','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter,'Fontname',Font_Name) -lh=legend(hh,'FDS {\it \rho}','FDS {\it Z}','FDS {\it u}','FDS {\it H}','{\it O(\Deltax)}','{\it O(\Deltax^2)}','location','northwest'); -set(lh,'FontSize',Title_Font_Size,'Interpreter',Font_Interpreter,'Fontname',Font_Name) - -% add Git version if file is available - -Git_Filename = [datadir,'shunn3_256_git.txt']; -addverstr(gca,Git_Filename,'loglog') - -% print to pdf -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf','../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/shunn_mms_convergence') - -% check errors -if e_r(end) > 2e-4 - display(['Matlab Warning: Density in shunn3 is out of tolerance. e_r = ',num2str(e_r(end))]) -end -if e_z(end) > 1e-4 - display(['Matlab Warning: Mixture fraction in shunn3 is out of tolerance. e_z = ',num2str(e_z(end))]) -end -if e_u(end) > 3e-5 - display(['Matlab Warning: Velocity in shunn3 is out of tolerance. e_u = ',num2str(e_u(end))]) -end -if e_H(end) > 2e-3 - display(['Matlab Warning: Pressure in shunn3 is out of tolerance. e_H = ',num2str(e_H(end))]) -end diff --git a/Utilities/Matlab/scripts/sippola_aerosol_deposition.m b/Utilities/Matlab/scripts/sippola_aerosol_deposition.m deleted file mode 100644 index 357a3409a93..00000000000 --- a/Utilities/Matlab/scripts/sippola_aerosol_deposition.m +++ /dev/null @@ -1,94 +0,0 @@ -% Overholt -% 10-30-2012 -% aerosol_depo.m -% -% Calculations for Aerosol Deposition FDS Validation cases -% located in (/Validation/Sippola_Aerosol_Deposition) - -clear all - -outdir = '../../../out/Sippola_Aerosol_Deposition/'; - -filename = {'Sippola_Test_01_devc.csv', 'Sippola_Test_02_devc.csv' ... - 'Sippola_Test_03_devc.csv', 'Sippola_Test_04_devc.csv' ... - 'Sippola_Test_05_devc.csv', 'Sippola_Test_06_devc.csv' ... - 'Sippola_Test_07_devc.csv', 'Sippola_Test_08_devc.csv' ... - 'Sippola_Test_09_devc.csv', 'Sippola_Test_10_devc.csv' ... - 'Sippola_Test_11_devc.csv', 'Sippola_Test_12_devc.csv' ... - 'Sippola_Test_13_devc.csv', 'Sippola_Test_14_devc.csv' ... - 'Sippola_Test_15_devc.csv', 'Sippola_Test_16_devc.csv' ... - 'Sippola_Test_17_devc.csv', 'Sippola_Test_18_devc.csv' ... - 'Sippola_Test_19_devc.csv', 'Sippola_Test_20_devc.csv' ... - 'Sippola_Test_21_devc.csv', 'Sippola_Test_22_devc.csv' ... - 'Sippola_Test_23_devc.csv', 'Sippola_Test_24_devc.csv' ... - 'Sippola_Test_25_devc.csv', 'Sippola_Test_26_devc.csv' ... - 'Sippola_Test_27_devc.csv', 'Sippola_Test_28_devc.csv' ... - 'Sippola_Test_29_devc.csv', 'Sippola_Test_30_devc.csv' ... - 'Sippola_Test_31_devc.csv'}; - -% Check for missing files -skip_case = 0; -for i=1:length(filename) - if ~exist([outdir, filename{i}]) - display(['Error: File ',[outdir, filename{i}],' does not exist. Skipping case.']) - skip_case = 1; - end -end -if skip_case - return -end - -% Friction velocity (m/s) for 16 test cases -friction_velocity = {0.12, 0.12, 0.12, 0.13, 0.12, 0.28, 0.26, 0.26 ... - 0.27, 0.28, 0.28, 0.45, 0.42, 0.44, 0.46, 0.45 ... - 0.16, 0.16, 0.16, 0.16, 0.16, 0.37, 0.37, 0.37 ... - 0.38, 0.38, 0.62, 0.62, 0.62, 0.64, 0.64}; - -% Air velocity (m/s) -air_velocity = {2.2, 2.2, 2.1, 2.2, 2.2, 5.3, 5.2, 5.2 ... - 5.4, 5.3, 5.3, 9.0, 9.0, 8.8, 9.2, 9.1 ... - 2.2, 2.2, 2.2, 2.2, 2.2, 5.3, 5.2, 5.2 ... - 5.3, 5.3, 8.9, 8.7, 8.9, 8.9, 8.9}; - -% Particle Diameter (m) -particle_diameter = {1.0e-6, 2.8e-6, 5.2e-6, 9.1e-6 ... - 16.e-6, 1.0e-6, 1.0e-6, 3.1e-6 ... - 5.2e-6, 9.8e-6, 16.e-6, 1.0e-6 ... - 3.1e-6, 5.4e-6, 8.7e-6, 15e-6 ... - 1.0e-6, 3.0e-6, 5.3e-6, 8.4e-6 ... - 13.e-6, 1.0e-6, 2.9e-6, 4.9e-6 ... - 8.2e-6, 13.e-6, 1.0e-6, 2.8e-6 ... - 5.0e-6, 8.4e-6, 13.e-6}; - - -% Primary calculations -for i=1:length(filename) - test = importdata([outdir, filename{i}],',',2); - - V_d_ceiling{i} = test.data(end,7); - V_d_wall{i} = test.data(end,8); - V_d_floor{i} = test.data(end,6); - - V_d_ceiling_nondim{i} = V_d_ceiling{i} / friction_velocity{i}; - V_d_wall_nondim{i} = V_d_wall{i} / friction_velocity{i}; - V_d_floor_nondim{i} = V_d_floor{i} / friction_velocity{i}; -end - -% Write out results file -fid = fopen([outdir,'Sippola_All_Tests.csv'],'wt','n'); -fprintf(fid,'Test,Air Velocity 1 um (m/s),Friction Velocity 1 um (m/s),Ceiling Deposition Velocity 1 um (m/s),Wall Deposition Velocity 1 um (m/s),Floor Deposition Velocity 1 um (m/s),Dimensionless Ceiling Deposition Velocity 1 um (m/s),Dimensionless Wall Deposition Velocity 1 um (m/s),Dimensionless Floor Deposition Velocity 1 um (m/s),Test,Air Velocity 3 um (m/s),Friction Velocity 3 um (m/s),Ceiling Deposition Velocity 3 um (m/s),Wall Deposition Velocity 3 um (m/s),Floor Deposition Velocity 3 um (m/s),Dimensionless Ceiling Deposition Velocity 3 um (m/s),Dimensionless Wall Deposition Velocity 3 um (m/s),Dimensionless Floor Deposition Velocity 3 um (m/s),Test,Air Velocity 5 um (m/s),Friction Velocity 5 um (m/s),Ceiling Deposition Velocity 5 um (m/s),Wall Deposition Velocity 5 um (m/s),Floor Deposition Velocity 5 um (m/s),Dimensionless Ceiling Deposition Velocity 5 um (m/s),Dimensionless Wall Deposition Velocity 5 um (m/s),Dimensionless Floor Deposition Velocity 5 um (m/s),Test,Air Velocity 9 um (m/s),Friction Velocity 9 um (m/s),Ceiling Deposition Velocity 9 um (m/s),Wall Deposition Velocity 9 um (m/s),Floor Deposition Velocity 9 um (m/s),Dimensionless Ceiling Deposition Velocity 9 um (m/s),Dimensionless Wall Deposition Velocity 9 um (m/s),Dimensionless Floor Deposition Velocity 9 um (m/s),Test,Air Velocity 16 um (m/s),Friction Velocity 16 um (m/s),Ceiling Deposition Velocity 16 um (m/s),Wall Deposition Velocity 16 um (m/s),Floor Deposition Velocity 16 um (m/s),Dimensionless Ceiling Deposition Velocity 16 um (m/s),Dimensionless Wall Deposition Velocity 16 um (m/s),Dimensionless Floor Deposition Velocity 16 um (m/s)\n'); -fprintf(fid,'1, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 2, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 3, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 4, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 5, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{1}, friction_velocity{1}, V_d_ceiling{1}, V_d_wall{1}, V_d_floor{1}, V_d_ceiling_nondim{1}, V_d_wall_nondim{1}, V_d_floor_nondim{1}, air_velocity{2}, friction_velocity{2}, V_d_ceiling{2}, V_d_wall{2}, V_d_floor{2}, V_d_ceiling_nondim{2}, V_d_wall_nondim{2}, V_d_floor_nondim{2}, air_velocity{3}, friction_velocity{3}, V_d_ceiling{3}, V_d_wall{3}, V_d_floor{3}, V_d_ceiling_nondim{3}, V_d_wall_nondim{3}, V_d_floor_nondim{3}, air_velocity{4}, friction_velocity{4}, V_d_ceiling{4}, V_d_wall{4}, V_d_floor{4}, V_d_ceiling_nondim{4}, V_d_wall_nondim{4}, V_d_floor_nondim{4}, air_velocity{5}, friction_velocity{5}, V_d_ceiling{5}, V_d_wall{5}, V_d_floor{5}, V_d_ceiling_nondim{5}, V_d_wall_nondim{5}, V_d_floor_nondim{5}); -fprintf(fid,'6, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 8, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 9, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 10, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 11, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{6}, friction_velocity{6}, V_d_ceiling{6}, V_d_wall{6}, V_d_floor{6}, V_d_ceiling_nondim{6}, V_d_wall_nondim{6}, V_d_floor_nondim{6}, air_velocity{8}, friction_velocity{8}, V_d_ceiling{8}, V_d_wall{8}, V_d_floor{8}, V_d_ceiling_nondim{8}, V_d_wall_nondim{8}, V_d_floor_nondim{8}, air_velocity{9}, friction_velocity{9}, V_d_ceiling{9}, V_d_wall{9}, V_d_floor{9}, V_d_ceiling_nondim{9}, V_d_wall_nondim{9}, V_d_floor_nondim{9}, air_velocity{10}, friction_velocity{10}, V_d_ceiling{10}, V_d_wall{10}, V_d_floor{10}, V_d_ceiling_nondim{10}, V_d_wall_nondim{10}, V_d_floor_nondim{10}, air_velocity{11}, friction_velocity{11}, V_d_ceiling{11}, V_d_wall{11}, V_d_floor{11}, V_d_ceiling_nondim{11}, V_d_wall_nondim{11}, V_d_floor_nondim{11}); -fprintf(fid,'7, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 13, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 14, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 15, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 16, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{7}, friction_velocity{7}, V_d_ceiling{7}, V_d_wall{7}, V_d_floor{7}, V_d_ceiling_nondim{7}, V_d_wall_nondim{7}, V_d_floor_nondim{7}, air_velocity{13}, friction_velocity{13}, V_d_ceiling{13}, V_d_wall{13}, V_d_floor{13}, V_d_ceiling_nondim{13}, V_d_wall_nondim{13}, V_d_floor_nondim{13}, air_velocity{14}, friction_velocity{14}, V_d_ceiling{14}, V_d_wall{14}, V_d_floor{14}, V_d_ceiling_nondim{14}, V_d_wall_nondim{14}, V_d_floor_nondim{14}, air_velocity{15}, friction_velocity{15}, V_d_ceiling{15}, V_d_wall{15}, V_d_floor{15}, V_d_ceiling_nondim{15}, V_d_wall_nondim{15}, V_d_floor_nondim{15}, air_velocity{16}, friction_velocity{16}, V_d_ceiling{16}, V_d_wall{16}, V_d_floor{16}, V_d_ceiling_nondim{16}, V_d_wall_nondim{16}, V_d_floor_nondim{16}); -fprintf(fid,'12, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 18, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 19, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 20, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 21, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{12}, friction_velocity{12}, V_d_ceiling{12}, V_d_wall{12}, V_d_floor{12}, V_d_ceiling_nondim{12}, V_d_wall_nondim{12}, V_d_floor_nondim{12}, air_velocity{18}, friction_velocity{18}, V_d_ceiling{18}, V_d_wall{18}, V_d_floor{18}, V_d_ceiling_nondim{18}, V_d_wall_nondim{18}, V_d_floor_nondim{18}, air_velocity{19}, friction_velocity{19}, V_d_ceiling{19}, V_d_wall{19}, V_d_floor{19}, V_d_ceiling_nondim{19}, V_d_wall_nondim{19}, V_d_floor_nondim{19}, air_velocity{20}, friction_velocity{20}, V_d_ceiling{20}, V_d_wall{20}, V_d_floor{20}, V_d_ceiling_nondim{20}, V_d_wall_nondim{20}, V_d_floor_nondim{20}, air_velocity{21}, friction_velocity{21}, V_d_ceiling{21}, V_d_wall{21}, V_d_floor{21}, V_d_ceiling_nondim{21}, V_d_wall_nondim{21}, V_d_floor_nondim{21}); -fprintf(fid,'17, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 23, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 24, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 25, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 26, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{17}, friction_velocity{17}, V_d_ceiling{17}, V_d_wall{17}, V_d_floor{17}, V_d_ceiling_nondim{17}, V_d_wall_nondim{17}, V_d_floor_nondim{17}, air_velocity{23}, friction_velocity{23}, V_d_ceiling{23}, V_d_wall{23}, V_d_floor{23}, V_d_ceiling_nondim{23}, V_d_wall_nondim{23}, V_d_floor_nondim{23}, air_velocity{24}, friction_velocity{24}, V_d_ceiling{24}, V_d_wall{24}, V_d_floor{24}, V_d_ceiling_nondim{24}, V_d_wall_nondim{24}, V_d_floor_nondim{24}, air_velocity{25}, friction_velocity{25}, V_d_ceiling{25}, V_d_wall{25}, V_d_floor{25}, V_d_ceiling_nondim{25}, V_d_wall_nondim{25}, V_d_floor_nondim{25}, air_velocity{26}, friction_velocity{26}, V_d_ceiling{26}, V_d_wall{26}, V_d_floor{26}, V_d_ceiling_nondim{26}, V_d_wall_nondim{26}, V_d_floor_nondim{26}); -fprintf(fid,'22, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 28, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 29, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 30, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 31, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{22}, friction_velocity{22}, V_d_ceiling{22}, V_d_wall{22}, V_d_floor{22}, V_d_ceiling_nondim{22}, V_d_wall_nondim{22}, V_d_floor_nondim{22}, air_velocity{28}, friction_velocity{28}, V_d_ceiling{28}, V_d_wall{28}, V_d_floor{28}, V_d_ceiling_nondim{28}, V_d_wall_nondim{28}, V_d_floor_nondim{28}, air_velocity{29}, friction_velocity{29}, V_d_ceiling{29}, V_d_wall{29}, V_d_floor{29}, V_d_ceiling_nondim{29}, V_d_wall_nondim{29}, V_d_floor_nondim{29}, air_velocity{30}, friction_velocity{30}, V_d_ceiling{30}, V_d_wall{30}, V_d_floor{30}, V_d_ceiling_nondim{30}, V_d_wall_nondim{30}, V_d_floor_nondim{30}, air_velocity{31}, friction_velocity{31}, V_d_ceiling{31}, V_d_wall{31}, V_d_floor{31}, V_d_ceiling_nondim{31}, V_d_wall_nondim{31}, V_d_floor_nondim{31}); -fprintf(fid,'27, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 2, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 3, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 4, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 5, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{1}, friction_velocity{1}, V_d_ceiling{1}, V_d_wall{1}, V_d_floor{1}, V_d_ceiling_nondim{1}, V_d_wall_nondim{1}, V_d_floor_nondim{1}, air_velocity{2}, friction_velocity{2}, V_d_ceiling{2}, V_d_wall{2}, V_d_floor{2}, V_d_ceiling_nondim{2}, V_d_wall_nondim{2}, V_d_floor_nondim{2}, air_velocity{3}, friction_velocity{3}, V_d_ceiling{3}, V_d_wall{3}, V_d_floor{3}, V_d_ceiling_nondim{3}, V_d_wall_nondim{3}, V_d_floor_nondim{3}, air_velocity{4}, friction_velocity{4}, V_d_ceiling{4}, V_d_wall{4}, V_d_floor{4}, V_d_ceiling_nondim{4}, V_d_wall_nondim{4}, V_d_floor_nondim{4}, air_velocity{5}, friction_velocity{5}, V_d_ceiling{5}, V_d_wall{5}, V_d_floor{5}, V_d_ceiling_nondim{5}, V_d_wall_nondim{5}, V_d_floor_nondim{5}); -fprintf(fid,'1, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 8, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 9, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 10, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 11, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{6}, friction_velocity{6}, V_d_ceiling{6}, V_d_wall{6}, V_d_floor{6}, V_d_ceiling_nondim{6}, V_d_wall_nondim{6}, V_d_floor_nondim{6}, air_velocity{8}, friction_velocity{8}, V_d_ceiling{8}, V_d_wall{8}, V_d_floor{8}, V_d_ceiling_nondim{8}, V_d_wall_nondim{8}, V_d_floor_nondim{8}, air_velocity{9}, friction_velocity{9}, V_d_ceiling{9}, V_d_wall{9}, V_d_floor{9}, V_d_ceiling_nondim{9}, V_d_wall_nondim{9}, V_d_floor_nondim{9}, air_velocity{10}, friction_velocity{10}, V_d_ceiling{10}, V_d_wall{10}, V_d_floor{10}, V_d_ceiling_nondim{10}, V_d_wall_nondim{10}, V_d_floor_nondim{10}, air_velocity{11}, friction_velocity{11}, V_d_ceiling{11}, V_d_wall{11}, V_d_floor{11}, V_d_ceiling_nondim{11}, V_d_wall_nondim{11}, V_d_floor_nondim{11}); -fprintf(fid,'6, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 13, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 14, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 15, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 16, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{7}, friction_velocity{7}, V_d_ceiling{7}, V_d_wall{7}, V_d_floor{7}, V_d_ceiling_nondim{7}, V_d_wall_nondim{7}, V_d_floor_nondim{7}, air_velocity{13}, friction_velocity{13}, V_d_ceiling{13}, V_d_wall{13}, V_d_floor{13}, V_d_ceiling_nondim{13}, V_d_wall_nondim{13}, V_d_floor_nondim{13}, air_velocity{14}, friction_velocity{14}, V_d_ceiling{14}, V_d_wall{14}, V_d_floor{14}, V_d_ceiling_nondim{14}, V_d_wall_nondim{14}, V_d_floor_nondim{14}, air_velocity{15}, friction_velocity{15}, V_d_ceiling{15}, V_d_wall{15}, V_d_floor{15}, V_d_ceiling_nondim{15}, V_d_wall_nondim{15}, V_d_floor_nondim{15}, air_velocity{16}, friction_velocity{16}, V_d_ceiling{16}, V_d_wall{16}, V_d_floor{16}, V_d_ceiling_nondim{16}, V_d_wall_nondim{16}, V_d_floor_nondim{16}); -fprintf(fid,'7, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 18, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 19, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 20, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 21, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{12}, friction_velocity{12}, V_d_ceiling{12}, V_d_wall{12}, V_d_floor{12}, V_d_ceiling_nondim{12}, V_d_wall_nondim{12}, V_d_floor_nondim{12}, air_velocity{18}, friction_velocity{18}, V_d_ceiling{18}, V_d_wall{18}, V_d_floor{18}, V_d_ceiling_nondim{18}, V_d_wall_nondim{18}, V_d_floor_nondim{18}, air_velocity{19}, friction_velocity{19}, V_d_ceiling{19}, V_d_wall{19}, V_d_floor{19}, V_d_ceiling_nondim{19}, V_d_wall_nondim{19}, V_d_floor_nondim{19}, air_velocity{20}, friction_velocity{20}, V_d_ceiling{20}, V_d_wall{20}, V_d_floor{20}, V_d_ceiling_nondim{20}, V_d_wall_nondim{20}, V_d_floor_nondim{20}, air_velocity{21}, friction_velocity{21}, V_d_ceiling{21}, V_d_wall{21}, V_d_floor{21}, V_d_ceiling_nondim{21}, V_d_wall_nondim{21}, V_d_floor_nondim{21}); -fprintf(fid,'12, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 23, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 24, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 25, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 26, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{17}, friction_velocity{17}, V_d_ceiling{17}, V_d_wall{17}, V_d_floor{17}, V_d_ceiling_nondim{17}, V_d_wall_nondim{17}, V_d_floor_nondim{17}, air_velocity{23}, friction_velocity{23}, V_d_ceiling{23}, V_d_wall{23}, V_d_floor{23}, V_d_ceiling_nondim{23}, V_d_wall_nondim{23}, V_d_floor_nondim{23}, air_velocity{24}, friction_velocity{24}, V_d_ceiling{24}, V_d_wall{24}, V_d_floor{24}, V_d_ceiling_nondim{24}, V_d_wall_nondim{24}, V_d_floor_nondim{24}, air_velocity{25}, friction_velocity{25}, V_d_ceiling{25}, V_d_wall{25}, V_d_floor{25}, V_d_ceiling_nondim{25}, V_d_wall_nondim{25}, V_d_floor_nondim{25}, air_velocity{26}, friction_velocity{26}, V_d_ceiling{26}, V_d_wall{26}, V_d_floor{26}, V_d_ceiling_nondim{26}, V_d_wall_nondim{26}, V_d_floor_nondim{26}); -fprintf(fid,'17, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 28, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 29, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 30, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, 31, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{22}, friction_velocity{22}, V_d_ceiling{22}, V_d_wall{22}, V_d_floor{22}, V_d_ceiling_nondim{22}, V_d_wall_nondim{22}, V_d_floor_nondim{22}, air_velocity{28}, friction_velocity{28}, V_d_ceiling{28}, V_d_wall{28}, V_d_floor{28}, V_d_ceiling_nondim{28}, V_d_wall_nondim{28}, V_d_floor_nondim{28}, air_velocity{29}, friction_velocity{29}, V_d_ceiling{29}, V_d_wall{29}, V_d_floor{29}, V_d_ceiling_nondim{29}, V_d_wall_nondim{29}, V_d_floor_nondim{29}, air_velocity{30}, friction_velocity{30}, V_d_ceiling{30}, V_d_wall{30}, V_d_floor{30}, V_d_ceiling_nondim{30}, V_d_wall_nondim{30}, V_d_floor_nondim{30}, air_velocity{31}, friction_velocity{31}, V_d_ceiling{31}, V_d_wall{31}, V_d_floor{31}, V_d_ceiling_nondim{31}, V_d_wall_nondim{31}, V_d_floor_nondim{31}); -fprintf(fid,'22, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{22}, friction_velocity{22}, V_d_ceiling{22}, V_d_wall{22}, V_d_floor{22}, V_d_ceiling_nondim{22}, V_d_wall_nondim{22}, V_d_floor_nondim{22}); -fprintf(fid,'27, %f, %f, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e, %3.1e\n', air_velocity{27}, friction_velocity{27}, V_d_ceiling{27}, V_d_wall{27}, V_d_floor{27}, V_d_ceiling_nondim{27}, V_d_wall_nondim{27}, V_d_floor_nondim{27}); -fclose(fid); \ No newline at end of file diff --git a/Utilities/Matlab/scripts/spray_pattern.m b/Utilities/Matlab/scripts/spray_pattern.m deleted file mode 100644 index 5802fd2bcea..00000000000 --- a/Utilities/Matlab/scripts/spray_pattern.m +++ /dev/null @@ -1,54 +0,0 @@ -% McDermott -% 2-23-2021 -% spray_pattern.m -% -% help clarify spray_pattern parameters -% plots are saved to fds/Manuals/FDS_User_Guide/FIGURES/spray_pattern* - -close all -clear all -plot_style - -b = [0, 5, 10, 100, 1000]; -mu = [0,10,20] * pi/180; -mu_str = {'0' '10' '20'}; - -phi_min = 0; -phi_max = [22.5, 45, 90] * pi/180; -phi_str = {'22p5' '45' '90'}; - -for k=1:length(phi_max) - phi = linspace(phi_min,phi_max(k),1000); - for j=1:length(mu) - figure - set(gca,'Units',Plot_Units) - set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - for i=1:length(b) - f = exp(-b(i)*((phi-mu(j))/(phi_max(k)-phi_min)).^2); - H(i)=plot(phi*180./pi,f); hold on - Key{i}=['\beta=',num2str(b(i))]; - end - axis([0, 90, 0, 1.1]); - set(gca, 'YDir','reverse'); - xlabel('\phi (degrees)','Interpreter',Font_Interpreter,'FontSize',Label_Font_Size); - ylabel('{\itf} (\phi)' ,'Interpreter',Font_Interpreter,'FontSize',Label_Font_Size); - set(gca,'FontName',Font_Name); - set(gca,'FontSize',Label_Font_Size); - lh=legend(H,Key,'location','southeast'); - set(lh,'FontName',Font_Name,'FontSize',Key_Font_Size); - th=text(45,0.1,['\mu=',num2str(mu(j)*180/pi),', \phi_{max}=',num2str(phi_max(k)*180/pi),' degrees']); - set(th,'FontName',Font_Name,'FontSize',Label_Font_Size); - set(gcf,'Visible',Figure_Visibility); - set(gcf,'Units',Paper_Units); - set(gcf,'PaperUnits',Paper_Units); - set(gcf,'PaperSize',[Paper_Width Paper_Height]); - set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - print(gcf,'-dpdf',['../../../Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu_',mu_str{j},'_phimax_',phi_str{k}]); - clear H Key; - end -end - - - - - diff --git a/Utilities/Matlab/scripts/synthetic_eddy_method.m b/Utilities/Matlab/scripts/synthetic_eddy_method.m deleted file mode 100644 index f45564c51a9..00000000000 --- a/Utilities/Matlab/scripts/synthetic_eddy_method.m +++ /dev/null @@ -1,395 +0,0 @@ -% McDermott -% 3-8-13 -% synthetic_eddy_method.m - -close all -clear all - -plot_style - -datadir='../../Verification/Turbulence/'; -plotdir='../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/'; - -error_tolerance = 0.01; - -% Flat profile -% ------------ -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -if ~exist([datadir,'sem_flat_leddy_p2_line.csv']) - display(['Error: File ',[datadir,'sem_flat_leddy_p2_line.csv'],' does not exist. Skipping case.']) - return -end - -M = importdata([datadir,'sem_flat_leddy_p2_line.csv'],',',2); - -k = find(strcmp(M.colheaders,'umean')); -z = M.data(:,k-1); -umean = M.data(:,k); - -u0=1; -uprof = u0*ones(length(z),1); -H(1)=plot(uprof,z,'k-'); hold on -H(2)=plot(1.1*uprof,z,'k--'); -plot(0.9*uprof,z,'k--') - -H(3)=plot(umean,z,'b>-'); -axis([.4 1.2 0 1]) -xlabel('{\it u} (m/s)','FontName',Font_Name,'FontSize',Label_Font_Size) -ylabel('{\it z} (m)','FontName',Font_Name,'FontSize',Label_Font_Size) - -k = find(strcmp(M.colheaders,'urms')); -z = M.data(:,k-1); -urms = M.data(:,k); - -H(4)=plot(umean+urms,z,'r--'); -plot(umean-urms,z,'r--') - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -h = legend(H,'Prescribed mean','Prescribed rms','FDS mean','FDS rms','location','northwest'); -set(h,'Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Key_Font_Size) - -Git_Filename = [datadir,'sem_flat_leddy_p2_git.txt']; -addverstr(gca,Git_Filename,'linear') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - -% print to pdf -print(gcf,'-dpdf',[plotdir,'sem_flat_leddy_p2']) - -% compute error -umean_error = norm(umean-uprof)/u0/length(umean); -if umean_error>error_tolerance - display(['Matlab Warning: sem_flat_leddy_p2.fds umean_error = ',umean_error]) -end - -urms_error = norm(umean+urms-1.1*uprof)/u0/length(umean); -if urms_error>error_tolerance - display(['Matlab Warning: sem_flat_leddy_p2.fds urms_error = ',urms_error]) -end - - -% Parabolic profile -% ----------------- -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -if ~exist([datadir,'sem_par_leddy_p2_line.csv']) - display(['Error: File ',[datadir,'sem_par_leddy_p2_line.csv'],' does not exist. Skipping case.']) - return -end - -M = importdata([datadir,'sem_par_leddy_p2_line.csv'],',',2); - -k = find(strcmp(M.colheaders,'umean')); -z = M.data(:,k-1); -umean = M.data(:,k); - -umax=1; -h=.5; -a=umax/h^2; -uprof = umax - a*(z-h).^2; -H(1)=plot(uprof,z,'k-'); hold on -H(2)=plot(1.1*uprof,z,'k--'); -plot(0.9*uprof,z,'k--') - -H(3)=plot(umean,z,'b>-'); -axis([0 1.2 0 1]) -xlabel('{\it u} (m/s)','FontName',Font_Name,'FontSize',Label_Font_Size) -ylabel('{\itz} (m)','FontName',Font_Name,'FontSize',Label_Font_Size) - -k = find(strcmp(M.colheaders,'urms')); -z = M.data(:,k-1); -urms = M.data(:,k); - -H(4)=plot(umean+urms,z,'r--'); -plot(umean-urms,z,'r--') - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -h = legend(H,'Prescribed mean','Prescribed rms','FDS mean','FDS rms','location','west'); -set(h,'Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) - -Git_Filename = [datadir,'sem_par_leddy_p2_git.txt']; -addverstr(gca,Git_Filename,'linear') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - -% print to pdf -print(gcf,'-dpdf',[plotdir,'sem_par_leddy_p2']) - -% compute error -umean_error = norm(umean-uprof)/umax/length(umean); -if umean_error>error_tolerance - display(['Matlab Warning: sem_par_leddy_p2.fds umean_error = ',num2str(umean_error)]) -end - -urms_error = norm(umean+urms-1.1*uprof)/umax/length(umean); -if urms_error>error_tolerance - display(['Matlab Warning: sem_par_leddy_p2.fds urms_error = ',num2str(urms_error)]) -end - -% Atmospheric profile -% ------------------- -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -if ~exist([datadir,'sem_atm_leddy_p2_line.csv']) - display(['Error: File ',[datadir,'sem_atm_leddy_p2_line.csv'],' does not exist. Skipping case.']) - return -end - -M = importdata([datadir,'sem_atm_leddy_p2_line.csv'],',',2); - -k = find(strcmp(M.colheaders,'umean')); -z = M.data(:,k-1); -umean = M.data(:,k); - -u0=1; -z0=0.5; -p=0.3; -uprof = u0*(z/z0).^p; -H(1)=plot(uprof,z,'k-'); hold on -H(2)=plot(1.1*uprof,z,'k--'); -plot(0.9*uprof,z,'k--') - -H(3)=plot(umean,z,'b>-'); -axis([0 1.4 0 1]) -xlabel('{\it u} (m/s)','FontName',Font_Name,'FontSize',Label_Font_Size) -ylabel('{\it z} (m)','FontName',Font_Name,'FontSize',Label_Font_Size) - -k = find(strcmp(M.colheaders,'urms')); -z = M.data(:,k-1); -urms = M.data(:,k); - -H(4)=plot(umean+urms,z,'r--'); -plot(umean-urms,z,'r--') - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -h = legend(H,'Prescribed mean','Prescribed rms','FDS mean','FDS rms','location','northwest'); -set(h,'Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) - -Git_Filename = [datadir,'sem_atm_leddy_p2_git.txt']; -addverstr(gca,Git_Filename,'linear') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - -% print to pdf -print(gcf,'-dpdf',[plotdir,'sem_atm_leddy_p2']) - -% compute error -umean_error = norm(umean-uprof)/u0/length(umean); -if umean_error>error_tolerance - display(['Matlab Warning: sem_atm_leddy_p2.fds umean_error = ',num2str(umean_error)]) -end - -urms_error = norm(umean+urms-1.1*uprof)/u0/length(umean); -if urms_error>error_tolerance - display(['Matlab Warning: sem_atm_leddy_p2.fds urms_error = ',num2str(urms_error)]) -end - -% RAMP profile -% ------------------- -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -if ~exist([datadir,'sem_ramp_leddy_p2_line.csv']) - display(['Error: File ',[datadir,'sem_ramp_leddy_p2_line.csv'],' does not exist. Skipping case.']) - return -end - -M = importdata([datadir,'sem_ramp_leddy_p2_line.csv'],',',2); - -k = find(strcmp(M.colheaders,'umean')); -z = M.data(:,k-1); -umean = M.data(:,k); - -u0=1; -for i=1:length(z) - if z(i)<.5 - uprof(i) = z(i)*2*u0; - else - uprof(i) = (1-z(i))*2*u0; - end -end - -H(1)=plot(uprof,z,'k-'); hold on -H(2)=plot(1.1*uprof,z,'k--'); -plot(0.9*uprof,z,'k--') - -H(3)=plot(umean,z,'b>-'); -axis([0 1.2 0 1]) -xlabel('{\it u} (m/s)','FontName',Font_Name,'FontSize',Label_Font_Size) -ylabel('{\it z} (m)','FontName',Font_Name,'FontSize',Label_Font_Size) - -k = find(strcmp(M.colheaders,'urms')); -z = M.data(:,k-1); -urms = M.data(:,k); - -H(4)=plot(umean+urms,z,'r--'); -plot(umean-urms,z,'r--') - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -h = legend(H,'Prescribed mean','Prescribed rms','FDS mean','FDS rms','location','northeast'); -set(h,'Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) - -Git_Filename = [datadir,'sem_ramp_leddy_p2_git.txt']; -addverstr(gca,Git_Filename,'linear') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - -% print to pdf -print(gcf,'-dpdf',[plotdir,'sem_ramp_leddy_p2']) - -% compute error -umean_error = norm(umean-uprof)/u0/length(umean); -if umean_error>error_tolerance - display(['Matlab Warning: sem_ramp_leddy_p2.fds umean_error = ',num2str(umean_error)]) -end - -urms_error = norm(umean+urms-1.1*uprof)/u0/length(umean); -if urms_error>error_tolerance - display(['Matlab Warning: sem_ramp_leddy_p2.fds urms_error = ',num2str(urms_error)]) -end - -% Monin-Obukhov profile at OPEN inflow boundary VELOCITY -% ------------------------------------------------------ -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -if ~exist([datadir,'sem_open_wind_line.csv']) - display(['Error: File ',[datadir,'sem_open_wind_line.csv'],' does not exist. Skipping case.']) - return -end - -% expected values -E = importdata([datadir,'sem_open_wind_MO_profile.csv'],',',1); -z_exp = E.data(:,find(strcmp(E.colheaders,'z'))); -u_exp = E.data(:,find(strcmp(E.colheaders,'u'))); -T_exp = E.data(:,find(strcmp(E.colheaders,'T'))); - -M = importdata([datadir,'sem_open_wind_line.csv'],',',2); - -z_fds = M.data(:,find(strcmp(M.colheaders,'UMEAN-z'))); -u_fds = M.data(:,find(strcmp(M.colheaders,'UMEAN'))); -u_fds_rms = M.data(:,find(strcmp(M.colheaders,'URMS'))); -T_fds = M.data(:,find(strcmp(M.colheaders,'TMEAN'))); -T_fds_rms = M.data(:,find(strcmp(M.colheaders,'TRMS'))); - -I = 0.1; % turbulence intensity (I), VEL_RMS=1 m/s, U_REF = 10 m/s from input file -H(1)=plot(u_exp,z_exp,'k>'); hold on -H(2)=plot((1+I)*u_exp,z_exp,'k:'); -plot((1-I)*u_exp,z_exp,'k:') - -H(3)=plot(u_fds,z_fds,'b-'); -H(4)=plot(u_fds+u_fds_rms,z_fds,'b--'); -plot(u_fds-u_fds_rms,z_fds,'b--') -axis([0 12 0 10]) -xlabel('{\it u} (m/s)','FontName',Font_Name,'FontSize',Label_Font_Size) -ylabel('{\it z} (m)','FontName',Font_Name,'FontSize',Label_Font_Size) - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -h = legend(H,'Monin-Obukhov profile','Prescribed rms','FDS mean','FDS rms','location','northwest'); -set(h,'Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) - -Git_Filename = [datadir,'sem_open_wind_git.txt']; -addverstr(gca,Git_Filename,'linear') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - -% print to pdf -print(gcf,'-dpdf',[plotdir,'sem_open_wind_u_prof']) - -% compute error -u_ref = 10; -kk = find(z_expmin(z_fds)); -u_fds_int = interp1(z_fds,u_fds,z_exp(kk)); -umean_error = norm(u_exp(kk)-u_fds_int)/u_ref/length(u_fds_int); -if umean_error>error_tolerance - display(['Matlab Warning: sem_open_wind.fds umean_error = ',num2str(umean_error)]) -end - -u_fds_rms_int = interp1(z_fds,u_fds_rms,z_exp(kk)); -urms_error = norm(u_fds_int+u_fds_rms_int-(1+I)*u_exp(kk))/u_ref/length(u_fds_rms_int); -if urms_error>error_tolerance - display(['Matlab Warning: sem_open_wind.fds urms_error = ',num2str(urms_error)]) -end - -% Monin-Obukhov profile at OPEN inflow boundary TEMPERATURE -% --------------------------------------------------------- -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -H(1)=plot(T_exp,z_exp,'ko'); hold on -H(2)=plot(T_fds,z_fds,'r-'); -xlabel('{\it T} (C)','FontName',Font_Name,'FontSize',Label_Font_Size) -ylabel('{\it z} (m)','FontName',Font_Name,'FontSize',Label_Font_Size) - -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -h = legend(H(1:2),'Monin-Obukhov profile','FDS mean','location','northeast'); -set(h,'Interpreter',Font_Interpreter,'FontName',Font_Name,'FontSize',Label_Font_Size) - -Git_Filename = [datadir,'sem_open_wind_git.txt']; -addverstr(gca,Git_Filename,'linear') - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - -% print to pdf -print(gcf,'-dpdf',[plotdir,'sem_open_wind_T_prof']) - -% compute error -T_ref = 20+273; -kk = find(z_expmin(z_fds)); -T_fds_int = interp1(z_fds,T_fds,z_exp(kk)); -Tmean_error = norm(T_exp(kk)-T_fds_int)/T_ref/length(T_fds_int); -if Tmean_error>error_tolerance - display(['Matlab Warning: sem_open_wind.fds Tmean_error = ',num2str(Tmean_error)]) -end - - - - - - diff --git a/Utilities/Matlab/scripts/umd_line_burner_process.m b/Utilities/Matlab/scripts/umd_line_burner_process.m deleted file mode 100644 index 6ade3e27190..00000000000 --- a/Utilities/Matlab/scripts/umd_line_burner_process.m +++ /dev/null @@ -1,48 +0,0 @@ -% McGrattan -% 2-26-2018 -% umd_line_burner_process.m -% -% Read and process FDS output files for UMD Line Burner - -close all -clear all - -Lf_dt = 10; - -outdir = '../../../out/UMD_Line_Burner/'; - -fuel_name = {'methane','propane'}; -res_name = {'1p25cm','p625cm','p3125cm'}; - -for i_fuel=1:2; - - for fds_resolution=1:3; - - DEV = importdata([outdir,fuel_name{i_fuel},'_dx_',res_name{fds_resolution},'_devc.csv'],',',2); - HRR = importdata([outdir,fuel_name{i_fuel},'_dx_',res_name{fds_resolution},'_hrr.csv'],',',2); - - Time_FDS = DEV.data(:,find(strcmp(DEV.colheaders,'Time'))); - XO2_FDS = DEV.data(:,find(strcmp(DEV.colheaders,'XO2'))); - Qdot_FDS = HRR.data(:,find(strcmp(HRR.colheaders,'HRR'))); - Qrad_FDS = HRR.data(:,find(strcmp(HRR.colheaders,'Q_RADI'))); - q_R_FDS = 0.5*( DEV.data(:,find(strcmp(DEV.colheaders,'qrad1'))) + DEV.data(:,find(strcmp(DEV.colheaders,'qrad2'))) ); - ntp = length(Time_FDS); - Lf_FDS = DEV.data(:,find(strcmp(DEV.colheaders,'L_F'))); - - Lf_tmp = Lf_FDS; - for n=1:ntp - indx_range = [find(Time_FDS>(Time_FDS(n)-Lf_dt),1):n]; - Lf_FDS(n) = mean(Lf_tmp(indx_range)); - end - - fid = fopen([outdir,fuel_name{i_fuel},'_dx_',res_name{fds_resolution},'.csv'],'wt','n'); - fprintf(fid,'%s\n','XO2,eta,Chi_R,Lf,q_R'); - for ii=1:ntp - fprintf(fid,'%5.3f,%6.2f,%6.2f,%6.2f,%6.2f\n',XO2_FDS(ii),Qdot_FDS(ii)/50.,max(0,-Qrad_FDS(ii)/max(0.001,Qdot_FDS(ii))),Lf_FDS(ii),q_R_FDS(ii)); - end - fclose(fid); - - end - -end - diff --git a/Utilities/Matlab/scripts/vege_mass_conservation.m b/Utilities/Matlab/scripts/vege_mass_conservation.m deleted file mode 100644 index 01d6fa3e7ac..00000000000 --- a/Utilities/Matlab/scripts/vege_mass_conservation.m +++ /dev/null @@ -1,53 +0,0 @@ -% -% This test is now being driven from dataplot. Retain -% the file as an example -% - -close all -clear all - -% Define standard plotting parameters -plot_style - -% Directories -data_dir = '../../Verification/Vegetation/'; -plot_dir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/'; - -% Read the output data -if ~exist([data_dir,'vege_mass_conservation_devc.csv']) - display(['Error File vege_mass_conservation_devc.csv does not exist. Skipping case.']); - return; -end - -M = csvread([data_dir,'vege_mass_conservation_devc.csv'],2); - -% Total mass should sum to 1.0 at every time -mass_delta = 1.0 - sum( M(:,[2:4]), 2 ); - -% Plot mass_delta versus time, M(:,1) -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - -plot(M(:,1),mass_delta,'LineWidth',Line_Width); hold on - -xlabel('Time (s)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter,'FontName',Font_Name) -ylabel('\Delta mass from expected (kg)','FontSize',Title_Font_Size,'Interpreter',Font_Interpreter,'FontName',Font_Name) -axis([0 max(M(:,1)) -0.5 1]) -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Title_Font_Size) - -% Add Git revision if file is available - -Git_Filename = [data_dir,'vege_mass_conservation_git.txt']; -addverstr(gca,Git_Filename,'linear') - -hold off - -% Print to pdf -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Height]); -set(gcf,'Position',[0 0 Paper_Width Paper_Height]); -print(gcf,'-dpdf',[plot_dir,'vege_mass_conservation']) diff --git a/Utilities/Matlab/scripts/vegetation_absorb.m b/Utilities/Matlab/scripts/vegetation_absorb.m deleted file mode 100644 index 1f31668644a..00000000000 --- a/Utilities/Matlab/scripts/vegetation_absorb.m +++ /dev/null @@ -1,26 +0,0 @@ -% McGrattan -% 6-1-2018 -% vegetation_absorb.m -% - -close all -clear all - -outdir = '../../Verification/WUI/'; -infile = 'vegetation_absorb_devc.csv'; - -if ~exist([outdir, infile]) - display(['Error: File ',infile,' does not exist. Skipping case.']) - return -end - -M = importdata([outdir,infile],',',2); - -fid = fopen([outdir,'vegetation_absorb_FDS.csv'],'wt','n'); -fprintf(fid,'%s\n','mpuv,rad'); -mpuv = [0.0 0.1 0.2 0.4 0.8 1.6]; -for i=1:6 - fprintf(fid,'%5.1f,%5.2f\n',mpuv(i),M.data(end,i+1)); -end -fclose(fid); - diff --git a/Utilities/Matlab/scripts/vort2d.m b/Utilities/Matlab/scripts/vort2d.m deleted file mode 100644 index 6cdbf91edeb..00000000000 --- a/Utilities/Matlab/scripts/vort2d.m +++ /dev/null @@ -1,305 +0,0 @@ -%-------------------------------------------------------------------------% -% FILE: vort2d.m -% AUTHOR: Max Gould -% LAST DATE EDITED: 06 August 2012 -%-------------------------------------------------------------------------% - -%-------------------------------------------------------------------------% -% Generate all plots for the 2D Vortex section -% of the FDS Verification Guide -% -% Dependencies: -% ../scripts/vort2d_diagram.m -% ../scripts/arrows.m -%-------------------------------------------------------------------------% -close all -clear all - -% Open directory with input files -input_dir = '../../Verification/NS_Analytical_Solution/'; - -%-------------------------------------------------------------------------% -% Define Parameters and Variables -%-------------------------------------------------------------------------% - -% Define basic flow parameters -L = 0.3112; -U0 = 35.0; -Rc = 0.01556; -BigGamma = 0.0359157; - -% Define mesh sizes to be analyzed -meshsize = [40 80 160 320]; -meshname = {'40' '80' '160' '320'}; - -% Set time step of DEVC output -DT = 1.1114*10.^(-4); - -% Set the flow-through time - % The time period required for the vortex to pass through the - % entire computational domain and return to where it was initialized -FLOWTIME = int16(0.3112/(U0*DT)); - -% Set the number of time steps to be analyzed -% Do not set below 3 (see 'Export Error for Plotting') -TIMESTEPS = [4 4 4 3]; - -% Allocate space for arrays -DEVCNUM = zeros(1,4); -STEPSIZE = zeros(1,4); -AxisPlotLabels = cell(1,TIMESTEPS(1)+1); -COUNT = zeros(4,TIMESTEPS(1)); -RMS = zeros(4,TIMESTEPS(1)); - -% Define step sizes for each mesh -for m = 1:4 - DEVCNUM(m) = meshsize(m)/5; - STEPSIZE(m) = 0.311200/meshsize(m); -end - -%-------------------------------------------------------------------------% -% Import Data -%-------------------------------------------------------------------------% - -for m = 1:4 - filename = [input_dir,'vort2d_',meshname{m},'_devc.csv']; - if ~exist(filename) - display(['Error: File ',filename,' does not exist. Skipping case.']) - return - end - M{m} = importdata(filename,',',2); - %M{m}.data -end - -%-------------------------------------------------------------------------% -% Plot Data -%-------------------------------------------------------------------------% - -% Open directory for plot output -plot_dir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/'; - -% Define standard plotting parameters -plot_style - -% Run for each mesh size -for m = 1:4 - - %-----------------------------------------------------------------% - % Plot U-Velocity at X=0 Data for a Range of Times - % Calculate RMS Error Values - %-----------------------------------------------------------------% - - figure - set(gca,'Units',Plot_Units) - set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Height]) - - % Define plot range - Z0 = STEPSIZE(m)/2; - Z = -2*Rc+Z0:STEPSIZE(m):2*Rc-Z0; - - % Plot analytical solution - AxisPlotExact = plot(Z,U0-BigGamma.*Z.*exp(-Z.^2./(2*Rc.^2))./Rc.^2,'--'); - - % Define plot color as black - set(AxisPlotExact,'Color',[0 0 0],'LineWidth',1.4); - - % Hold analytical solution plot to be included in future plot - hold on - - % Plot FDS simulation values with - % different colors for each time step - for t = 1:TIMESTEPS(m)+1 - - % Set time steps to be integer multiples - % of the flow-through time - TIME = FLOWTIME*(t-1)+1; - - % Initialize error arrays - COUNT(m,t) = 0.0; - RMS(m,t) = 0.0; - - % Allocate space for array - UArray = zeros(1,DEVCNUM(m)); - - for k = 2:DEVCNUM(m)+1 - % Create array of u-velocity values - UArray(k-1) = M{m}.data(TIME,k); - - % Define actual z-coordinate (see UZEXACT) - ZVAL = -2*Rc+Z0+(k-2)*STEPSIZE(m); - - % Calculate analytical u-velocity values - AxisExact = U0-BigGamma.*ZVAL.*exp(-ZVAL.^2./(2*Rc.^2))./Rc.^2; - - % Calculate initial error values - RMS(m,t) = RMS(m,t)+((UArray(k-1)-AxisExact)).^2; - COUNT(m,t) = COUNT(m,t)+1.0; - end - - % Calculate averaged error values - RMS(m,t) = sqrt(RMS(m,t)/COUNT(m,t)); - - % Create plot of u-velocity along a line at x=0 - AxisPlotFDS = plot(Z,UArray); - - % Define color functions - CFRed = real(0.5*(tanh(6*t/TIMESTEPS(m)-3)+1)); - CFGreen = real(-0.5*(tanh(7*t/TIMESTEPS(m)-6)-1)); - - % Define plot colors - set(AxisPlotFDS,'Color',[CFRed CFGreen 0]); - end - - % Plot all plots together (from hold on) - hold off - - % Specify axes for above plots - axis([-2*Rc+Z0 2*Rc-Z0 33.4 36.6]); - - % Set standard plotting parameters - set(gca,'FontName',Font_Name) - set(gca,'FontSize',Title_Font_Size) - - set(gcf,'Visible',Figure_Visibility); - set(gcf,'Units',Paper_Units); - set(gcf,'PaperUnits',Paper_Units); - set(gcf,'PaperSize',[Paper_Width Paper_Height]); - set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - - % Label axes - xlabel('z-coordinate (m)','FontSize',Title_Font_Size,... - 'Interpreter',Font_Interpreter); - ylabel('u-velocity (m/s)','FontSize',Title_Font_Size,... - 'Interpreter',Font_Interpreter); - - % Define legend-label strings - AxisPlotLabels{1} = 'Analytical'; - for t = 2:TIMESTEPS(m)+2 - TIME_INDEX = num2str(double((t-2)*FLOWTIME)*DT,'%6.3f'); - AxisPlotLabels{t} = ['FDS (t=',TIME_INDEX,' s)']; - end - - % Create legend - AxisPlotLeg = legend(AxisPlotLabels(1:m),'Location','NorthEast'); - set(AxisPlotLeg,'FontSize',Title_Font_Size,'Interpreter',Font_Interpreter); - - % add Git revision if file is available - - Git_Filename = [input_dir,'vort2d_40_git.txt']; - addverstr(gca,Git_Filename,'linear') - - % Save plot to file - print(gcf,'-dpdf',[plot_dir,'vort2d_',meshname{m},'_uzgraph']); - - %-----------------------------------------------------------------% - % Plot U-Velocity at a Point as a Function of Time - %-----------------------------------------------------------------% - - % Define plot range - T = 0.0:DT:DT*double(FLOWTIME*TIMESTEPS(m)+1); - - % Define actual coordinates of point for analytical solution - % Must correspond to device coordinates - % in numerical simulation (see UPGRAPH) - XP = 0.0; - ZP = -2*Rc+Z0; - - % Plot analytical solution (periodic to 6 loops) - PointPlotExact = plot(T,U0-BigGamma.*ZP.*... - (exp(-(XP.^2+ZP.^2+(U0.^2).*(T.^2)-... - 2.*U0.*XP.*T)./(2.*Rc.^2))+... - exp(-((XP+1*L).^2+ZP.^2+(U0.^2).*(T.^2)-... - 2.*U0.*(XP+1*L).*T)./(2*Rc.^2))+... - exp(-((XP+2*L).^2+ZP.^2+(U0.^2).*(T.^2)-... - 2.*U0.*(XP+2*L).*T)./(2*Rc.^2))+... - exp(-((XP+3*L).^2+ZP.^2+(U0.^2).*(T.^2)-... - 2.*U0.*(XP+3*L).*T)./(2*Rc.^2))+... - exp(-((XP+4*L).^2+ZP.^2+(U0.^2).*(T.^2)-... - 2.*U0.*(XP+4*L).*T)./(2*Rc.^2))+... - exp(-((XP+5*L).^2+ZP.^2+(U0.^2).*(T.^2)-... - 2.*U0.*(XP+5*L).*T)./(2*Rc.^2))+... - exp(-((XP+6*L).^2+ZP.^2+(U0.^2).*(T.^2)-... - 2.*U0.*(XP+6*L).*T)./(2*Rc.^2)))./Rc.^2); - - % Hold analytical solution plot to be included in future plot - hold on - - % Create plot of FDS simulation values - % Device specification must correspond to - % point location for analytical solution - % ---------------------------v - T = M{m}.data(:,1); - PointPlotFDS = plot(T,M{m}.data(:,2),'--'); - - % Plot all plots together (from hold on) - hold off - - % Define plot colors - set(PointPlotExact,'Color',[0.3 0.3 0.3]); - set(PointPlotFDS,'Color',[1 0 0]); - - % Specify axes for above plots - axis([0.0 0.037 34.6 36.0]); - - % Set standard plotting parameters - set(gca,'FontName',Font_Name) - set(gca,'FontSize',Title_Font_Size) - - set(gcf,'Visible',Figure_Visibility); - set(gcf,'Units',Paper_Units); - set(gcf,'PaperUnits',Paper_Units); - set(gcf,'PaperSize',[Paper_Width Paper_Height]); - set(gcf,'Position',[0 0 Paper_Width Paper_Height]); - - % Label axes - xlabel('Time (s)','FontSize',Title_Font_Size,... - 'Interpreter',Font_Interpreter); - ylabel('u-velocity (m/s)','FontSize',Title_Font_Size,... - 'Interpreter',Font_Interpreter); - - % Create legend - PointPlotLeg = legend('Analytical','FDS','Location','SouthEast'); - set(PointPlotLeg,'FontSize',Title_Font_Size,'Interpreter',Font_Interpreter); - - % add Git revision if file is available - - Git_Filename = [input_dir,'vort2d_40_git.txt']; - addverstr(gca,Git_Filename,'linear') - - % Save plot to file - print(gcf,'-dpdf',[plot_dir,'vort2d_',meshname{m},'_upgraph']); -end - -%-------------------------------------------------------------------------% -% Generate Flow Diagram -%-------------------------------------------------------------------------% - -vort2d_diagram - -%-------------------------------------------------------------------------% -% Export Error Data for Plotting -%-------------------------------------------------------------------------% - -% Define dx and dx^2 values -dx =[0.0077800 0.0038900 0.0019450 0.0009725]; -dx2=[0.0000605 0.0000151 0.0000038 0.0000009]; - -% Open data file for reference from FDS_verification_script.m -RMSFile = fopen([input_dir,'vort2d_error.csv'],'wt'); - -% Write column headers -fprintf(RMSFile,'%s\n','dx, dxmod, dx^2, rms1, rms2, rms3'); - -% Write error data for all meshes -for m = 1:4 - fprintf(RMSFile,'%12.9f, %12.9f, %12.9f, %12.9f, %12.9f, %12.9f\n',... - dx(m),120*dx(m),4500*dx2(m),RMS(m,2),RMS(m,3),RMS(m,4)); -end - - - - - - - - diff --git a/Utilities/Matlab/scripts/vort2d_diagram.m b/Utilities/Matlab/scripts/vort2d_diagram.m deleted file mode 100644 index fe8fe748160..00000000000 --- a/Utilities/Matlab/scripts/vort2d_diagram.m +++ /dev/null @@ -1,126 +0,0 @@ -%-------------------------------------------------------------------------% -% FILE: vort2d_diagram.m -% AUTHOR: Max Gould -% LAST DATE EDITED: 06 August 2012 -%-------------------------------------------------------------------------% - -%-------------------------------------------------------------------------% -% Generate flow diagram for the 2D Vortex section -% of the FDS Verification Guide -% -% Dependencies: -% ../scripts/arrows.m -%-------------------------------------------------------------------------% - -%-------------------------------------------------------------------------% -% Define Parameters -%-------------------------------------------------------------------------% - -% Define basic flow parameters -U0 = 0.7; -Rc = 0.01556; -BigGamma = 0.0359157; - -% Define plot parameters -Min = -0.05; -Max = 0.05; -Step = 0.005; - -% Define plot region -[X,Z] = meshgrid(Min:Step:Max); - -%-------------------------------------------------------------------------% -% Setup Flow Field -%-------------------------------------------------------------------------% - -% Define flow field -Psi = BigGamma.*exp(-(X.^2+Z.^2)./(2.*Rc.^2)); - -% Calculate gradient and define velocity components -[DX,DZ] = gradient(Psi,0.005,0.005); -U = U0+DZ; -W = -DX; - -%-------------------------------------------------------------------------% -% Plot Vector Field -%-------------------------------------------------------------------------% - -% Define standard plot-style parameters -plot_style -figure -set(gca,'Units',Plot_Units) -set(gca,'Position',[Plot_X Plot_Y Plot_Width Plot_Width]) - -% Plot vector field -quiver(X,Z,U,W,2,'Color',[0.3 0.7 1],'ShowArrowHead','off'); -hold on - -% Hold plot for arrow heads -arrows(X,Z,U,W,0.32,0.25); -hold off - -%-------------------------------------------------------------------------% -% Plot Arrow Heads Without arrows.m -%-------------------------------------------------------------------------% -% %-----------------------------------------------------------------% -% % Plot Arrow Heads -% %-----------------------------------------------------------------% -% -% % Define arrow-head dimension and scaling parameters -% Alpha = 0.32; %primary scaling factor (arrow size) -% Beta = 0.25; %secondary scaling factor (width to length ratio) -% Scale = 1.6*Step; %scales arrow-head placement with vector lines -% -% % Convert arrays to vectors and scale -% X=X(:).'; -% Z=Z(:).'; -% U=Scale*U(:).'; -% W=Scale*W(:).'; -% -% % Allocate space for arrays -% hu = zeros(length(U),4); -% hw = zeros(length(U),4); -% -% % Define arrow geometry and plot arrows -% for i = 1:length(U) -% hu(i,1) = X(i)+U(i)-Alpha*(U(i)+Beta*(W(i)+eps)); -% hu(i,2) = X(i)+U(i); -% hu(i,3) = X(i)+U(i)-Alpha*(U(i)-Beta*(W(i)+eps)); -% hu(i,4) = X(i)+U(i)-Alpha*(U(i)+Beta*(W(i)+eps)); -% hw(i,1) = Z(i)+W(i)-Alpha*(W(i)-Beta*(U(i)+eps)); -% hw(i,2) = Z(i)+W(i); -% hw(i,3) = Z(i)+W(i)-Alpha*(W(i)+Beta*(U(i)+eps)); -% hw(i,4) = Z(i)+W(i)-Alpha*(W(i)-Beta*(U(i)+eps)); -% h2 = fill(hu(i,:),hw(i,:),[0.3 0.7 1]); -% end -% -% % Plot arrow heads with vector lines -% hold off -%-------------------------------------------------------------------------% - -%-------------------------------------------------------------------------% -% Produce Plot -%-------------------------------------------------------------------------% - -% Define output location -plot_dir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/'; - -% Define plot range -axis([-0.05,0.05,-0.05,0.05]); - -set(gca,'XTick',-0.04:0.02:0.04); -set(gca,'YTick',-0.04:0.02:0.04); -set(gca,'FontName',Font_Name) -set(gca,'FontSize',Label_Font_Size) - -set(gcf,'Visible',Figure_Visibility); -set(gcf,'Units',Paper_Units); -set(gcf,'PaperUnits',Paper_Units); -set(gcf,'PaperSize',[Paper_Width Paper_Width]); -set(gcf,'Position',[0 0 Paper_Width Paper_Width]); - -% Save plot to file -print(gcf,'-dpdf',[plot_dir,'vort2d_diagram']); - -%-------------------------------------------------------------------------% -%-------------------------------------------------------------------------% diff --git a/Utilities/Matlab/scripts/water_evap_1_const_gamma.m b/Utilities/Matlab/scripts/water_evap_1_const_gamma.m deleted file mode 100644 index 63773b91920..00000000000 --- a/Utilities/Matlab/scripts/water_evap_1_const_gamma.m +++ /dev/null @@ -1,94 +0,0 @@ -% McDermott -% 11-1-2016 -% water_evap_1_const_gamma.m -% -% Calculation of expected values for water_evap_1_const_gamma.fds verification case. -% See fds/Verification/Sprinklers_and_Sprays/water_evap_1_const_gamma.csv -% -% Time,Rel. Hum,h_gas,h_water,dens,temp,pres,vapor -% 8,2.109675497,-27660.3572,1.9757398E+001,0.01,153.8927169,-7902.9592,0.01 -% 10,2.109675497,-27660.3572,1.9757398E+001,0.01,153.8927169,-7902.9592,0.01 - -close all -clear all -%format long g - -H_L = -1.9757398E+004; % J/kg (see _devc file) -R = 8314.5; % Pa * m3 / (kmol * K) -gam = 1.4; -P_1 = 101325; % Pa -V = 1; % m3 -T_1 = 200 + 273.15; % K -T_w = 20 + 273.15; % K -M_w = 0.01; % kg (known from problem statement, see input file) - -W_a = 28.84834; % kg/kmol (see .out file) -W_w = 18.01528; % kg/kmol (see .out file) - -% ideal gas specific heats -cv_a = R/W_a * 1/(gam-1); -cv_w = R/W_w * 1/(gam-1); -cp_a = R/W_a * gam/(gam-1); -cp_w = R/W_w * gam/(gam-1); - -% compute initial mass of air -RHO_1 = P_1 * W_a / (R * T_1); -M_a = RHO_1 * V; - -% determine final mass fraction of water vapor in gas -% and compute new mixture molecular weight -Y_w = M_w/(M_a+M_w); -Y_a = 1-Y_w; -W = 1/(Y_w/W_w + Y_a/W_a); - -% compute final density -RHO_2 = (M_w+M_a)/V; - -% form energy balance (internal energy remains constant) determine final temperature -% and from ideal gas determine final pressure -T_2 = ( M_a*cv_a*T_1 + H_L ) / (M_a*cv_a + M_w*cv_w); -P_2 = RHO_2*R*T_2/W; - -dP = P_2-P_1; % change in pressure, Pa - -dH = (M_a*cp_a + M_w*cp_w)*T_2 - M_a*cp_a*T_1; % change in gas enthalpy, kJ - -% output the results to the working directory - -ddir = '../../Verification/Sprinklers_and_Sprays/'; - -fid = fopen([ddir,'water_evap_1_const_gamma.csv'],'w+'); - -fprintf(fid,'%s,%s,%s,%s,%s,%s,%s,%s\n','Time','Rel. Hum','h_gas','h_water','dens','temp','pres','vapor'); - -fprintf(fid,'%i,%11.9f,%14.7e,%14.7e,%6.4f,%10.7f,%14.7e,%6.4f\n', ... - 8,2.109675497,dH/1000,-H_L/1000,RHO_2-RHO_1,T_2-273.15,dP,M_w); - -fprintf(fid,'%i,%11.9f,%14.7e,%14.7e,%6.4f,%10.7f,%14.7e,%6.4f\n', ... - 10,2.109675497,dH/1000,-H_L/1000,RHO_2-RHO_1,T_2-273.15,dP,M_w); - -fclose(fid); - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Utilities/Python/FDS_verification_script.py b/Utilities/Python/FDS_verification_script.py index a5e3865458c..c3610b7eb47 100644 --- a/Utilities/Python/FDS_verification_script.py +++ b/Utilities/Python/FDS_verification_script.py @@ -4,15 +4,26 @@ import subprocess import fdsplotlib +import runpy import importlib importlib.reload(fdsplotlib) # use for development (while making changes to fdsplotlib.py) print("Using:", fdsplotlib.__file__) - # Scripts to run prior to dataplot -# print("ignition_delay..."); subprocess.run(["python","./scripts/cantera_ignition_delay.py"]) -# print("reaction_rates..."); subprocess.run(["python","./scripts/cantera_reaction_rates.py"]) -# print("turbulent_batch_reactor..."); subprocess.run(["python","./scripts/cantera_turbulent_batch_reactor.py"]) +# print("ignition_delay..."); runpy.run_path("./scripts/cantera_ignition_delay.py", run_name="__main__") +# print("reaction_rates..."); runpy.run_path("./scripts/cantera_reaction_rates.py", run_name="__main__") +# print("turbulent_batch_reactor..."); runpy.run_path("./scripts/cantera_turbulent_batch_reactor.py", run_name="__main__") +print("ashrae_7..."); runpy.run_path("./scripts/ashrae_7.py", run_name="__main__") +print('burke_schumann...'); runpy.run_path("./scripts/burke_schumann.py", run_name="__main__") +print('cat_propane_depo...'); runpy.run_path("./scripts/cat_propane_depo.py", run_name="__main__") +print('flame_species...'); runpy.run_path("./scripts/flame_species.py", run_name="__main__") +print("ns2d..."); runpy.run_path("./scripts/ns2d.py", run_name="__main__") +print("radiation_box..."); runpy.run_path("./scripts/radiation_box.py", run_name="__main__") +print("radiation_plane_layer..."); runpy.run_path("./scripts/radiation_plane_layer.py", run_name="__main__") +print("random_walk_soln..."); runpy.run_path("./scripts/random_walk_soln.py", run_name="__main__") +print('rms_cov_corr...'); runpy.run_path("./scripts/rms_cov_corr.py", run_name="__main__") +print('vegetation_absorb...'); runpy.run_path("./scripts/vegetation_absorb.py", run_name="__main__") +print('water_evap_1_const_gamma...'); runpy.run_path("./scripts/water_evap_1_const_gamma.py", run_name="__main__") # Dataplot and scatplot options @@ -30,22 +41,40 @@ # Special cases -print("blasius..."); subprocess.run(["python","./scripts/blasius.py"]) -print("fds_moody_chart..."); subprocess.run(["python","./scripts/fds_moody_chart.py"]) -print("heated_channel..."); subprocess.run(["python","./scripts/heated_channel.py"]) -print("jet_decay..."); subprocess.run(["python","./scripts/jet_decay.py"]) -print("law_of_the_wall..."); subprocess.run(["python","./scripts/law_of_the_wall.py"]) -print("plate_view_factor..."); subprocess.run(["python","./scripts/plate_view_factor.py"]) -print("pulsating..."); subprocess.run(["python","./scripts/pulsating.py"]) -print("pyrolysis..."); subprocess.run(["python","./scripts/pyrolysis.py"]) -print("ribbed_channel..."); subprocess.run(["python","./scripts/ribbed_channel.py"]) -print("saad_mms..."); subprocess.run(["python","./scripts/saad_mms_temporal_error.py"]) -print("shunn_mms..."); subprocess.run(["python","./scripts/shunn_mms.py"]) -print("soborot_mass_transport..."); subprocess.run(["python","./scripts/soborot_mass_transport.py"]) -print("terminal_velocity_convergence..."); subprocess.run(["python","./scripts/terminal_velocity_convergence.py"]) -print("tree_shapes..."); subprocess.run(["python","./scripts/tree_shapes.py"]) -print("turb_model..."); subprocess.run(["python","./scripts/turb_model.py"]) -print("wall_internal_radiation..."); subprocess.run(["python","./scripts/wall_internal_radiation.py"]) -print("yplus..."); subprocess.run(["python","./scripts/yplus.py"]) +print("atmospheric_boundary_layer..."); runpy.run_path("./scripts/atmospheric_boundary_layer.py", run_name="__main__") +print("blasius..."); runpy.run_path("./scripts/blasius.py", run_name="__main__") +print('extinction...'); runpy.run_path("./scripts/extinction.py", run_name="__main__") +print("fan_curve..."); runpy.run_path("./scripts/fan_curve.py", run_name="__main__") +print("favre_test..."); runpy.run_path("./scripts/favre_test.py", run_name="__main__") +print("fds_moody_chart..."); runpy.run_path("./scripts/fds_moody_chart.py", run_name="__main__") +print("fluid_part..."); runpy.run_path("./scripts/fluid_part.py", run_name="__main__") +print("heated_channel..."); runpy.run_path("./scripts/heated_channel.py", run_name="__main__") +print('hot_layer_collapse...'); runpy.run_path("./scripts/hot_layer_collapse.py", run_name="__main__") +print("ht3d_sphere..."); runpy.run_path("./scripts/ht3d_sphere.py", run_name="__main__") +print('hvac_mass_transport...'); runpy.run_path("./scripts/hvac_mass_transport.py", run_name="__main__") +print("jet_decay..."); runpy.run_path("./scripts/jet_decay.py", run_name="__main__") +print("law_of_the_wall..."); runpy.run_path("./scripts/law_of_the_wall.py", run_name="__main__") +print("level_set_ellipse..."); runpy.run_path("./scripts/level_set_ellipse.py", run_name="__main__") +print("mesh_transformation..."); runpy.run_path("./scripts/mesh_transformation.py", run_name="__main__") +print("mass_balance..."); runpy.run_path("./scripts/mass_balance.py", run_name="__main__") +print("openmp_timing_benchmarks..."); runpy.run_path("./scripts/openmp_timing_benchmarks.py", run_name="__main__") +print("particle_size_distribution..."); runpy.run_path("./scripts/particle_size_distribution.py", run_name="__main__") +print("plate_view_factor..."); runpy.run_path("./scripts/plate_view_factor.py", run_name="__main__") +print("pulsating..."); runpy.run_path("./scripts/pulsating.py", run_name="__main__") +print("pyrolysis..."); runpy.run_path("./scripts/pyrolysis.py", run_name="__main__") +print('radiating_polygon...'); runpy.run_path("./scripts/radiating_polygon.py", run_name="__main__") +print("ribbed_channel..."); runpy.run_path("./scripts/ribbed_channel.py", run_name="__main__") +print("saad_mms..."); runpy.run_path("./scripts/saad_mms_temporal_error.py", run_name="__main__") +print("scaling_tests..."); runpy.run_path("./scripts/scaling_tests.py", run_name="__main__") +print("shunn_mms..."); runpy.run_path("./scripts/shunn_mms.py", run_name="__main__") +print("soborot_mass_transport..."); runpy.run_path("./scripts/soborot_mass_transport.py", run_name="__main__") +print("synthetic_eddy_method..."); runpy.run_path("./scripts/synthetic_eddy_method.py", run_name="__main__") +print("terminal_velocity_convergence..."); runpy.run_path("./scripts/terminal_velocity_convergence.py", run_name="__main__") +print("tree_shapes..."); runpy.run_path("./scripts/tree_shapes.py", run_name="__main__") +print("turb_model..."); runpy.run_path("./scripts/turb_model.py", run_name="__main__") +print("vort2d..."); runpy.run_path("./scripts/vort2d.py", run_name="__main__") +print("wall_internal_radiation..."); runpy.run_path("./scripts/wall_internal_radiation.py", run_name="__main__") +print("yplus..."); runpy.run_path("./scripts/yplus.py", run_name="__main__") +print('impinging_jet...'); runpy.run_path("./scripts/impinging_jet.py", run_name="__main__") print("verification scripts completed successfully!") diff --git a/Utilities/Python/fdsplotlib.py b/Utilities/Python/fdsplotlib.py index 5d11671f6da..769ef2674e5 100644 --- a/Utilities/Python/fdsplotlib.py +++ b/Utilities/Python/fdsplotlib.py @@ -502,11 +502,8 @@ def plot_to_fig(x_data,y_data,**kwargs): default_markevery = 1 markerfacecolor = None markeredgecolor = 'black' - markeredgewidth = 1 marker = None - markersize = 5 linestyle = '-' - linewidth = 1 color = 'black' ############################### @@ -576,10 +573,37 @@ def plot_to_fig(x_data,y_data,**kwargs): error_fill_color = kwargs.get('error_fill_color',None) + # adjust sizes if requested + linewidth = kwargs.get('linewidth',1) + markeredgewidth = kwargs.get('markeredgewidth',1) + markersize = kwargs.get('markersize',5) + + # adjust ticks if required + xnumticks = kwargs.get('xnumticks',None) + ynumticks = kwargs.get('ynumticks',None) + xticks = kwargs.get('xticks',None) + yticks = kwargs.get('yticks',None) + # other plot parameters markevery = kwargs.get('data_markevery',default_markevery) legend_location = kwargs.get('legend_location',default_legend_location) legend_framealpha = kwargs.get('legend_framealpha',default_legend_framealpha) + + # set dashes to default, or user requested + # This set is the matplotlib default + if linestyle == '': dashes = (None, None); linewidth = 0; + if linestyle == '-': dashes = (None, None) + if linestyle == '--': dashes = kwargs.get('line_dashes',(6, 6)) + if linestyle == '-.': dashes = kwargs.get('line_dashes',(6, 3, 1, 3)) + if linestyle == ':': dashes = kwargs.get('line_dashes',(1, 3)) + + # This set is what we were using in Matlab + # if linestyle == '': dashes = (None, None); linewidth = 0; + # if linestyle == '-': dashes = (None, None) + # if linestyle == '--': dashes = kwargs.get('line_dashes',(10, 6.2)) + # if linestyle == '-.': dashes = kwargs.get('line_dashes',(12, 7.4, 3, 7.4)) + # if linestyle == ':': dashes = kwargs.get('line_dashes',(1, 3)) + data_label = kwargs.get('data_label',None) @@ -599,7 +623,8 @@ def plot_to_fig(x_data,y_data,**kwargs): markersize=markersize, linestyle=linestyle, linewidth=linewidth, - color=color) + color=color, + dashes=dashes) if plot_type=='loglog': ax.loglog(x_data,y_data, @@ -612,7 +637,8 @@ def plot_to_fig(x_data,y_data,**kwargs): markersize=markersize, linestyle=linestyle, linewidth=linewidth, - color=color) + color=color, + dashes=dashes) if plot_type=='semilogx': ax.semilogx(x_data,y_data, @@ -625,7 +651,8 @@ def plot_to_fig(x_data,y_data,**kwargs): markersize=markersize, linestyle=linestyle, linewidth=linewidth, - color=color) + color=color, + dashes=dashes) if plot_type=='semilogy': ax.semilogy(x_data,y_data, @@ -638,7 +665,8 @@ def plot_to_fig(x_data,y_data,**kwargs): markersize=markersize, linestyle=linestyle, linewidth=linewidth, - color=color) + color=color, + dashes=dashes) # if y fill range is passed, add it to the plot if kwargs.get('y_error_fill_absolute') and not kwargs.get('y_error_fill_relative'): @@ -762,6 +790,23 @@ def plot_to_fig(x_data,y_data,**kwargs): ax.set_xlim(xmin,xmax) ax.set_ylim(ymin,ymax) + + # set number of ticks if requested by the user + if ynumticks != None: + if plot_type in ('loglog', 'semilogx'): + ax.set_xticks(np.logspace(xmin, xmax, xnumticks)) + else: + ax.set_xticks(np.linspace(xmin, xmax, xnumticks)) + if ynumticks != None: + if plot_type in ('loglog', 'semilogy'): + ax.set_yticks(np.logspace(ymin, ymax, ynumticks)) + else: + ax.set_yticks(np.linspace(ymin, ymax, ynumticks)) + + # set ticks if requested by the user + if xticks is not None: ax.set_xticks(xticks) + if yticks is not None: ax.set_yticks(yticks) + if plot_type in ('loglog', 'semilogy'): apply_global_exponent(ax, axis='y', fontsize=axeslabel_fontsize) @@ -772,6 +817,8 @@ def plot_to_fig(x_data,y_data,**kwargs): add_version_string(ax=ax, version_str=kwargs.get('revision_label'), plot_type=plot_type, font_size=version_fontsize) # fig.tight_layout() # this should not be needed if figure_size and plot_size are both specified + + set_ticks_like_matlab(fig) return fig @@ -911,6 +958,7 @@ def get_version_string(filename): file1.close() return version_str + def add_version_string(ax, version_str, plot_type='linear', scale_x=1.00, scale_y=1.02, font_name='Times', font_size=10): """ @@ -1065,110 +1113,6 @@ def get_plot_style(style="fds"): raise ValueError(f"Unknown style '{style}'. Please choose 'fds' or 'paper'.") -def define_plot_parameters(C, irow): - import numpy as np - import re - - class plot_parameters: - def __init__(self): - self.switch_id = C.values[irow,C.columns.get_loc('switch_id')] - self.Dataname = C.values[irow,C.columns.get_loc('Dataname')] - self.VerStr_Filename = C.values[irow,C.columns.get_loc('VerStr_Filename')] - self.d1_Filename = C.values[irow,C.columns.get_loc('d1_Filename')] - self.d1_Col_Name_Row = C.values[irow,C.columns.get_loc('d1_Col_Name_Row')] - self.d1_Data_Row = C.values[irow,C.columns.get_loc('d1_Data_Row')] - self.d1_Ind_Col_Name = C.values[irow,C.columns.get_loc('d1_Ind_Col_Name')] - self.d1_Dep_Col_Name = C.values[irow,C.columns.get_loc('d1_Dep_Col_Name')] - self.d1_Key = C.values[irow,C.columns.get_loc('d1_Key')] - self.d1_Style = C.values[irow,C.columns.get_loc('d1_Style')] - self.d1_Start = C.values[irow,C.columns.get_loc('d1_Start')] - self.d1_End = C.values[irow,C.columns.get_loc('d1_End')] - self.d1_Tick = C.values[irow,C.columns.get_loc('d1_Tick')] - self.d1_Comp_Start = C.values[irow,C.columns.get_loc('d1_Comp_Start')] - self.d1_Comp_End = C.values[irow,C.columns.get_loc('d1_Comp_End')] - self.d1_Dep_Comp_Start = C.values[irow,C.columns.get_loc('d1_Dep_Comp_Start')] - self.d1_Dep_Comp_End = C.values[irow,C.columns.get_loc('d1_Dep_Comp_End')] - self.d1_Initial_Value = C.values[irow,C.columns.get_loc('d1_Initial_Value')] - self.d2_Filename = C.values[irow,C.columns.get_loc('d2_Filename')] - self.d2_Col_Name_Row = C.values[irow,C.columns.get_loc('d2_Col_Name_Row')] - self.d2_Data_Row = C.values[irow,C.columns.get_loc('d2_Data_Row')] - self.d2_Ind_Col_Name = C.values[irow,C.columns.get_loc('d2_Ind_Col_Name')] - self.d2_Dep_Col_Name = C.values[irow,C.columns.get_loc('d2_Dep_Col_Name')] - self.d2_Key = C.values[irow,C.columns.get_loc('d2_Key')] - self.d2_Style = C.values[irow,C.columns.get_loc('d2_Style')] - self.d2_Start = C.values[irow,C.columns.get_loc('d2_Start')] - self.d2_End = C.values[irow,C.columns.get_loc('d2_End')] - self.d2_Tick = C.values[irow,C.columns.get_loc('d2_Tick')] - self.d2_Comp_Start = C.values[irow,C.columns.get_loc('d2_Comp_Start')] - self.d2_Comp_End = C.values[irow,C.columns.get_loc('d2_Comp_End')] - self.d2_Dep_Comp_Start = C.values[irow,C.columns.get_loc('d2_Dep_Comp_Start')] - self.d2_Dep_Comp_End = C.values[irow,C.columns.get_loc('d2_Dep_Comp_End')] - self.d2_Initial_Value = C.values[irow,C.columns.get_loc('d2_Initial_Value')] - self.Plot_Title = C.values[irow,C.columns.get_loc('Plot_Title')] - self.Ind_Title = C.values[irow,C.columns.get_loc('Ind_Title')] - self.Dep_Title = C.values[irow,C.columns.get_loc('Dep_Title')] - self.Min_Ind = C.values[irow,C.columns.get_loc('Min_Ind')] - self.Max_Ind = C.values[irow,C.columns.get_loc('Max_Ind')] - self.Scale_Ind = C.values[irow,C.columns.get_loc('Scale_Ind')] - self.Min_Dep = C.values[irow,C.columns.get_loc('Min_Dep')] - self.Max_Dep = C.values[irow,C.columns.get_loc('Max_Dep')] - self.Scale_Dep = C.values[irow,C.columns.get_loc('Scale_Dep')] - self.Flip_Axis = C.values[irow,C.columns.get_loc('Flip_Axis')] - self.Title_Position = C.values[irow,C.columns.get_loc('Title_Position')] - self.Key_Position = C.values[irow,C.columns.get_loc('Key_Position')] - self.Legend_XYWidthHeight = C.values[irow,C.columns.get_loc('Legend_XYWidthHeight')] - self.Paper_Width_Factor = C.values[irow,C.columns.get_loc('Paper_Width_Factor')] - self.Plot_Type = C.values[irow,C.columns.get_loc('Plot_Type')] - self.Plot_Filename = C.values[irow,C.columns.get_loc('Plot_Filename')] - self.Quantity = C.values[irow,C.columns.get_loc('Quantity')] - self.Metric = C.values[irow,C.columns.get_loc('Metric')] - self.Error_Tolerance = C.values[irow,C.columns.get_loc('Error_Tolerance')] - self.Group_Key_Label = C.values[irow,C.columns.get_loc('Group_Key_Label')] - self.Group_Style = C.values[irow,C.columns.get_loc('Group_Style')] - self.Fill_Color = C.values[irow,C.columns.get_loc('Fill_Color')] - self.Font_Interpreter = C.values[irow,C.columns.get_loc('Font_Interpreter')] - - def __repr__(self): - return str(self.__dict__) - - inst = plot_parameters() - - specials = { - "&": r"\&", "%": r"\%", "_": r"\_", "#": r"\#", - "$": r"\$", "{": r"\{", "}": r"\}", "^": r"\^{}", "~": r"\~{}", - } - - def sanitize(text: str) -> str: - parts = re.split(r"(\$.*?\$)", text) - sanitized = [] - for part in parts: - if part.startswith("$") and part.endswith("$"): - sanitized.append(part) # math untouched - else: - s = part - for k, v in specials.items(): - s = s.replace(k, v) - sanitized.append(s) - return "".join(sanitized) - - def safe_strip(val): - if isinstance(val, str): - return val.strip() - return "" # or return val if you prefer to keep None - - # Explicit sanitization of only the human-facing fields - inst.Plot_Title = sanitize(safe_strip(inst.Plot_Title)) - inst.Ind_Title = sanitize(safe_strip(inst.Ind_Title)) - inst.Dep_Title = sanitize(safe_strip(inst.Dep_Title)) - inst.Quantity = sanitize(safe_strip(inst.Quantity)) - inst.Metric = sanitize(safe_strip(inst.Metric)) - inst.Group_Key_Label = sanitize(safe_strip(inst.Group_Key_Label)) - inst.d1_Key = sanitize(safe_strip(inst.d1_Key)) - inst.d2_Key = sanitize(safe_strip(inst.d2_Key)) - - return inst - - def matlab_legend_to_matplotlib(position): """ Convert a MATLAB legend position string to the corresponding matplotlib location string. @@ -1201,6 +1145,86 @@ def matlab_legend_to_matplotlib(position): return mapping.get(position.strip().lower(), 'best') +def define_plot_parameters(D, irow): + import numpy as np + + class plot_parameters: + def __init__(self): + self.switch_id = D.values[irow,D.columns.get_loc('switch_id')] + self.Dataname = D.values[irow,D.columns.get_loc('Dataname')] + self.VerStr_Filename = D.values[irow,D.columns.get_loc('VerStr_Filename')] + self.d1_Filename = D.values[irow,D.columns.get_loc('d1_Filename')] + self.d1_Col_Name_Row = D.values[irow,D.columns.get_loc('d1_Col_Name_Row')] + self.d1_Data_Row = D.values[irow,D.columns.get_loc('d1_Data_Row')] + self.d1_Ind_Col_Name = D.values[irow,D.columns.get_loc('d1_Ind_Col_Name')] + self.d1_Dep_Col_Name = D.values[irow,D.columns.get_loc('d1_Dep_Col_Name')] + self.d1_Key = D.values[irow,D.columns.get_loc('d1_Key')] + self.d1_Style = D.values[irow,D.columns.get_loc('d1_Style')] + self.d1_Start = D.values[irow,D.columns.get_loc('d1_Start')] + self.d1_End = D.values[irow,D.columns.get_loc('d1_End')] + self.d1_Tick = D.values[irow,D.columns.get_loc('d1_Tick')] + self.d1_Comp_Start = D.values[irow,D.columns.get_loc('d1_Comp_Start')] + self.d1_Comp_End = D.values[irow,D.columns.get_loc('d1_Comp_End')] + self.d1_Dep_Comp_Start = D.values[irow,D.columns.get_loc('d1_Dep_Comp_Start')] + self.d1_Dep_Comp_End = D.values[irow,D.columns.get_loc('d1_Dep_Comp_End')] + self.d1_Initial_Value = D.values[irow,D.columns.get_loc('d1_Initial_Value')] + self.d2_Filename = D.values[irow,D.columns.get_loc('d2_Filename')] + self.d2_Col_Name_Row = D.values[irow,D.columns.get_loc('d2_Col_Name_Row')] + self.d2_Data_Row = D.values[irow,D.columns.get_loc('d2_Data_Row')] + self.d2_Ind_Col_Name = D.values[irow,D.columns.get_loc('d2_Ind_Col_Name')] + self.d2_Dep_Col_Name = D.values[irow,D.columns.get_loc('d2_Dep_Col_Name')] + self.d2_Key = D.values[irow,D.columns.get_loc('d2_Key')] + self.d2_Style = D.values[irow,D.columns.get_loc('d2_Style')] + self.d2_Start = D.values[irow,D.columns.get_loc('d2_Start')] + self.d2_End = D.values[irow,D.columns.get_loc('d2_End')] + self.d2_Tick = D.values[irow,D.columns.get_loc('d2_Tick')] + self.d2_Comp_Start = D.values[irow,D.columns.get_loc('d2_Comp_Start')] + self.d2_Comp_End = D.values[irow,D.columns.get_loc('d2_Comp_End')] + self.d2_Dep_Comp_Start = D.values[irow,D.columns.get_loc('d2_Dep_Comp_Start')] + self.d2_Dep_Comp_End = D.values[irow,D.columns.get_loc('d2_Dep_Comp_End')] + self.d2_Initial_Value = D.values[irow,D.columns.get_loc('d2_Initial_Value')] + self.Plot_Title = D.values[irow,D.columns.get_loc('Plot_Title')] + self.Ind_Title = D.values[irow,D.columns.get_loc('Ind_Title')] + self.Dep_Title = D.values[irow,D.columns.get_loc('Dep_Title')] + self.Min_Ind = D.values[irow,D.columns.get_loc('Min_Ind')] + self.Max_Ind = D.values[irow,D.columns.get_loc('Max_Ind')] + self.Scale_Ind = D.values[irow,D.columns.get_loc('Scale_Ind')] + self.Min_Dep = D.values[irow,D.columns.get_loc('Min_Dep')] + self.Max_Dep = D.values[irow,D.columns.get_loc('Max_Dep')] + self.Scale_Dep = D.values[irow,D.columns.get_loc('Scale_Dep')] + self.Flip_Axis = D.values[irow,D.columns.get_loc('Flip_Axis')] + self.Title_Position = D.values[irow,D.columns.get_loc('Title_Position')] + self.Key_Position = D.values[irow,D.columns.get_loc('Key_Position')] + self.Legend_XYWidthHeight = D.values[irow,D.columns.get_loc('Legend_XYWidthHeight')] + self.Paper_Width_Factor = D.values[irow,D.columns.get_loc('Paper_Width_Factor')] + self.Plot_Type = D.values[irow,D.columns.get_loc('Plot_Type')] + self.Plot_Filename = D.values[irow,D.columns.get_loc('Plot_Filename')] + self.Quantity = D.values[irow,D.columns.get_loc('Quantity')] + self.Metric = D.values[irow,D.columns.get_loc('Metric')] + self.Error_Tolerance = D.values[irow,D.columns.get_loc('Error_Tolerance')] + self.Group_Key_Label = D.values[irow,D.columns.get_loc('Group_Key_Label')] + self.Group_Style = D.values[irow,D.columns.get_loc('Group_Style')] + self.Fill_Color = D.values[irow,D.columns.get_loc('Fill_Color')] + self.Font_Interpreter = D.values[irow,D.columns.get_loc('Font_Interpreter')] + + def __repr__(self): + return str(self.__dict__) + + d = plot_parameters() + + # Explicit sanitization of only the human-facing fields + d.Plot_Title = sanitize(safe_strip(d.Plot_Title)) + d.Ind_Title = sanitize(safe_strip(d.Ind_Title)) + d.Dep_Title = sanitize(safe_strip(d.Dep_Title)) + d.Quantity = sanitize(safe_strip(d.Quantity)) + d.Metric = sanitize(safe_strip(d.Metric)) + d.Group_Key_Label = sanitize(safe_strip(d.Group_Key_Label)) + d.d1_Key = sanitize(safe_strip(d.d1_Key)) + d.d2_Key = sanitize(safe_strip(d.d2_Key)) + + return d + + def define_qrow_variables(Q, j): """ Define scatterplot parameters from the Scatterplot_Inputs.csv row j. @@ -1220,7 +1244,6 @@ def define_qrow_variables(Q, j): q : object Object with attributes corresponding to scatterplot input fields. """ - import re class qrow: def __init__(self): @@ -1242,32 +1265,6 @@ def __repr__(self): q = qrow() - # --- Sanitization helpers (same style as define_plot_parameters) --- - specials = { - "&": r"\&", "%": r"\%", "_": r"\_", "#": r"\#", - "$": r"\$", "{": r"\{", "}": r"\}", "^": r"\^{}", "~": r"\~{}", - } - - def sanitize(text: str) -> str: - if not isinstance(text, str): - return text - parts = re.split(r"(\$.*?\$)", text) - sanitized = [] - for part in parts: - if part.startswith("$") and part.endswith("$"): - sanitized.append(part) - else: - s = part - for k, v in specials.items(): - s = s.replace(k, v) - sanitized.append(s) - return "".join(sanitized) - - def safe_strip(val): - if isinstance(val, str): - return val.strip() - return val - # Sanitize only human-readable fields q.Scatter_Plot_Title = sanitize(safe_strip(q.Scatter_Plot_Title)) q.Ind_Title = sanitize(safe_strip(q.Ind_Title)) @@ -1310,6 +1307,36 @@ def to_float(val): return q +def sanitize(text: str) -> str: + """Escape LaTeX specials outside math mode ($...$).""" + if not isinstance(text, str): + return text + + specials = { + "&": r"\&", "%": r"\%", "_": r"\_", "#": r"\#", + "$": r"\$", "{": r"\{", "}": r"\}", "^": r"\^{}", "~": r"\~{}", + } + + # Split into math and text segments + import re + parts = re.split(r"(\$.*?\$)", text) + sanitized = [] + for part in parts: + if part.startswith("$") and part.endswith("$"): + sanitized.append(part) # math untouched + else: + s = part + for k, v in specials.items(): + s = s.replace(k, v) + sanitized.append(s) + return "".join(sanitized) + + +def safe_strip(val): + """Strip whitespace safely from strings; return empty string otherwise.""" + return val.strip() if isinstance(val, str) else "" + + def scatplot(saved_data, drange, **kwargs): """ Generate scatter plots and compute validation/verification statistics. @@ -1322,6 +1349,7 @@ def scatplot(saved_data, drange, **kwargs): import numpy as np import pandas as pd import matplotlib.pyplot as plt + import fdsplotlib Manuals_Dir = kwargs.get("Manuals_Dir", "") Scatterplot_Inputs_File = kwargs.get("Scatterplot_Inputs_File", "") @@ -1329,6 +1357,11 @@ def scatplot(saved_data, drange, **kwargs): Scatterplot_Dir = kwargs.get("Scatterplot_Dir", "") verbose = kwargs.get("verbose", True) + plot_style = get_plot_style("fds") + scat_figure_size = (plot_style["Scat_Paper_Width"],plot_style["Scat_Paper_Height"]) + scat_plot_size = (plot_style["Scat_Plot_Width"],plot_style["Scat_Plot_Height"]) + scat_plot_origin = (plot_style["Scat_Plot_X"],plot_style["Scat_Plot_Y"]) + if not os.path.exists(Scatterplot_Inputs_File): raise FileNotFoundError(f"[scatplot] Missing input file: {Scatterplot_Inputs_File}") os.makedirs(Scatterplot_Dir, exist_ok=True) @@ -1430,26 +1463,25 @@ def scatplot(saved_data, drange, **kwargs): delta = np.exp(log_M_bar - log_E_bar + 0.5 * Sigma_M ** 2 - 0.5 * Sigma_E ** 2) # --- Scatter Plot --- - fig, ax = plt.subplots(figsize=(5, 5)) - if Plot_Type == "loglog": - ax.loglog(Measured_Values, Predicted_Values, "o", color="k", alpha=0.6) - else: - ax.plot(Measured_Values, Predicted_Values, "o", color="k", alpha=0.6) - - ax.plot([Plot_Min, Plot_Max], [Plot_Min, Plot_Max], "k-") + fig = fdsplotlib.plot_to_fig(x_data=[-1], y_data=[-1], + figure_size=scat_figure_size, + plot_size=scat_plot_size, + plot_origin=scat_plot_origin, + plot_type=Plot_Type, + x_min=Plot_Min, x_max=Plot_Max, y_min=Plot_Min, y_max=Plot_Max, + x_label=row["Ind_Title"], + y_label=row["Dep_Title"]) + + fdsplotlib.plot_to_fig(x_data=[Plot_Min, Plot_Max], y_data=[Plot_Min, Plot_Max], line_style="k-", figure_handle=fig) if Sigma_E > 0: - ax.plot([Plot_Min, Plot_Max], np.array([Plot_Min, Plot_Max]) * (1 + 2 * Sigma_E), "k--") - ax.plot([Plot_Min, Plot_Max], np.array([Plot_Min, Plot_Max]) / (1 + 2 * Sigma_E), "k--") - ax.plot([Plot_Min, Plot_Max], np.array([Plot_Min, Plot_Max]) * delta, "r-") - ax.plot([Plot_Min, Plot_Max], np.array([Plot_Min, Plot_Max]) * delta * (1 + 2 * Sigma_M), "r--") - ax.plot([Plot_Min, Plot_Max], np.array([Plot_Min, Plot_Max]) * delta / (1 + 2 * Sigma_M), "r--") - - ax.set_xlim([Plot_Min, Plot_Max]) - ax.set_ylim([Plot_Min, Plot_Max]) - ax.set_xlabel(row["Ind_Title"]) - ax.set_ylabel(row["Dep_Title"]) - ax.grid(True, which="both", linestyle=":") - ax.set_title(Scatter_Plot_Title) + fdsplotlib.plot_to_fig(x_data=[Plot_Min, Plot_Max], y_data=np.array([Plot_Min, Plot_Max]) * (1 + 2 * Sigma_E), line_style="k--", figure_handle=fig) + fdsplotlib.plot_to_fig(x_data=[Plot_Min, Plot_Max], y_data=np.array([Plot_Min, Plot_Max]) / (1 + 2 * Sigma_E), line_style="k--", figure_handle=fig) + fdsplotlib.plot_to_fig(x_data=[Plot_Min, Plot_Max], y_data=np.array([Plot_Min, Plot_Max]) * delta, line_style="r-", figure_handle=fig) + fdsplotlib.plot_to_fig(x_data=[Plot_Min, Plot_Max], y_data=np.array([Plot_Min, Plot_Max]) * delta * (1 + 2 * Sigma_M), line_style="r--", figure_handle=fig) + fdsplotlib.plot_to_fig(x_data=[Plot_Min, Plot_Max], y_data=np.array([Plot_Min, Plot_Max]) * delta / (1 + 2 * Sigma_M), line_style="r--", figure_handle=fig) + + # plot data last so it shows on top of stat lines + fdsplotlib.plot_to_fig(x_data=Measured_Values, y_data=Predicted_Values, marker_style="ko", figure_handle=fig) pdf_path = os.path.join(Manuals_Dir, Plot_Filename + ".pdf") os.makedirs(os.path.dirname(pdf_path), exist_ok=True) @@ -1700,3 +1732,12 @@ def statistics_histogram(Measured_Values, Predicted_Values, print(f"[statistics_histogram] {Scatter_Plot_Title}: p = {pval:.2f}") return f"{os.path.basename(Plot_Filename)}_Histogram", pval + +def set_ticks_like_matlab(fig): + ax = fig.axes[0] + ax.tick_params(axis="both", direction="in", top=True, right=True, width=0.5) + + for axis in ['top','bottom','left','right']: + ax.spines[axis].set_linewidth(0.5) + + diff --git a/Utilities/Python/scripts/ashrae_7.py b/Utilities/Python/scripts/ashrae_7.py new file mode 100644 index 00000000000..b5598149f7b --- /dev/null +++ b/Utilities/Python/scripts/ashrae_7.py @@ -0,0 +1,80 @@ +# Roger Wang +# 7-20-11 +# ashrae_7.m +# +# Converted by Floyd + +import os +import numpy as np +import pandas as pd + +datadir = '../../Verification/HVAC/' +filename = [ + 'ashrae_7_exp.csv', + 'ashrae7_fixed_flow_devc.csv', + 'ashrae7_quadratic_devc.csv', + 'ashrae7_table_devc.csv' +] + +label = [ + 'Experiment &', + 'Fixed Flow & ', + 'Quadratic & ', + 'Table & ' +] + +# duct = ['1', '2', '3', '4', '5', '56', '6', '7'] + +pressure = np.zeros((4, 8)) + +skip_case = False + +for i in range(len(filename)): + name = datadir+filename[i] + if not os.path.exists(name): + skip_case = True + print('Error: File ', filename[i], ' does not exist. Skipping case.') + +if skip_case: quit() + +M = pd.read_csv(datadir+filename[0],skiprows=6,header=None) + +for n in range(1, len(filename)): + df_sim = pd.read_csv(datadir+filename[n],skiprows=2,header=None) + last_row_data = df_sim.iloc[-1].values + pressure[n, :] = last_row_data[1:9] + +# --- Write to LaTeX File --- + +texname = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/ashrae_7.tex' + +with open(texname, 'w') as fid: + + # Boilerplate LaTeX environment opening + fid.write('\\begin{center}\n') + fid.write('\\begin{tabular}{|c|c|c|c|c|c|c|c|c|} \\hline\n') + + # Header Row + fid.write('Duct Number & 1 & 2 & 3 & 4 & 5 & 56 & 6 & 7 \\\\ \\hline\n') + + # Experiment Row (M) + format_str_exp =label[0] + ' %6.3f &' * 7 + ' %6.3f \\\\ \n' + + # The '*' operator unpacks the NumPy array 'M' into arguments for the format string. + fid.write(format_str_exp % tuple(M.iloc[0,1:9])) + + # Simulation Rows (pressure) + for i in range(1, len(filename)): + + # Build the format string using the label prefix + format_str_sim = label[i] + ('%6.3f & ' * 7) + '%6.3f \\\\ \n' + + # Unpack the pressure data and write the line + fid.write(format_str_sim % tuple(pressure[i,:])) + + # Boilerplate LaTeX environment closing + fid.write('\\hline\n') + fid.write('\\end{tabular}\n') + fid.write('\\end{center}\n') + +print(f"\n? Successfully generated LaTeX table in {texname}") \ No newline at end of file diff --git a/Utilities/Python/scripts/atmospheric_boundary_layer.py b/Utilities/Python/scripts/atmospheric_boundary_layer.py new file mode 100644 index 00000000000..177bafb32c8 --- /dev/null +++ b/Utilities/Python/scripts/atmospheric_boundary_layer.py @@ -0,0 +1,114 @@ + +# Atmospheric Boundary Layer profiles, based on M-O theory as described in +# "Falcon Series Data Report", GRI-89/0138, June 1990. +# These plots are used as illustrations in the FDS User's Guide. + +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +outdir = '../../Verification/Atmospheric_Effects/' +pltdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/' + +git_file = outdir + 'atmospheric_boundary_layer_1_git.txt' +version_string = fdsplotlib.get_version_string(git_file) + +basein = outdir + 'atmospheric_boundary_layer' +baseout = pltdir + 'atmospheric_boundary_layer' + +for i in range(1, 5): # Loop from 1 to 4 (inclusive) + + datafile = basein + '_' + str(i) + outfile = baseout + '_' + str(i) + + M1 = pd.read_csv(datafile + '_devc.csv', sep=',', skiprows=1) + M2 = pd.read_csv(datafile + '_line.csv', sep=',', skiprows=1) + + u_r = M1.iloc[-1, 1] + T_r = M1.iloc[-1, 2] + 273.15 + + rho_0 = 1.2 + g = 9.81 + cp = 1005 + kappa = 0.41 + p_0 = 100000 + qdot = {1: 50, 2: -50, 3: 25, 4: -25} + z_0 = {1: 0.25, 2: 0.25, 3: 0.125, 4: 0.125} + T_low = {1: 15, 2: 15, 3: 15, 4: 15} + T_high = {1: 25, 2: 25, 3: 25, 4: 25} + u_high = {1: 20, 2: 20, 3: 10, 4: 15} + fvec = {1: 0.01, 2: 0.01, 3: 0.002, 4: 0.005} + s = {1: 8.15, 2: 8.15, 3: 4.075, 4: 4.075} + + theta_0 = T_r + z_r = 10. + p_r = p_0 - rho_0 * g * (z_r - z_0[i]) + theta_r = T_r * (p_0 / p_r) ** 0.285 + u_star = kappa * u_r / np.log(z_r / z_0[i]) + L = -u_star**3 * theta_0 * rho_0 * cp / (g * kappa * qdot[i]) + theta_star = u_star**2 * theta_0 / (g * kappa * L) + + z = np.array([z_0[i], 10*z_0[i], 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30, 50, 100]) + + # Create figure 1 for velocity + + if L < 0: + x = (1 - 16*z/L)**0.25 + psi_m = 2*np.log((1+x)/2) + np.log((1+x**2)/2) - 2*np.arctan(x) + np.pi/2 + psi_h = 2*np.log((1+x**2)/2) + else: + psi_m = -5*z/L + psi_h = psi_m + + u = (u_star/kappa) * (np.log(z/z_0[i]) - psi_m) + theta = theta_0 + (theta_star/kappa) * (np.log(z/z_0[i]) - psi_h) + T = theta * (p_0 / (p_0 - rho_0*g*(z - z_0[i])))**(-0.285) + + T = T + (theta_0 - T[11]) + + ERROR = abs(u[-1] - M2.iloc[-1, 1]) + if ERROR > 2.: + print(f'Python Warning: atmospheric_boundary_layer Case {i} velocity out of tolerance. ERROR = {ERROR} m/s') + + fig = fdsplotlib.plot_to_fig(x_data=M2.iloc[:, 1].values, y_data=M2.iloc[:, 0].values, marker_style='k-', data_label='FDS', + x_label='Velocity (m/s)', y_label='Height (m)', + x_min=0, x_max=u_high[i], y_min=0, y_max=100) + + fdsplotlib.plot_to_fig(x_data=u, y_data=z, figure_handle=fig, marker_style='ko', data_label='M-O Theory') + + ax1 = fig.axes[0] + + ax1.text(0.05, 0.90, f'Case {i}', transform=ax1.transAxes) + ax1.text(0.05, 0.80, f'$F={fvec[i]:.3f}' + r'\; \mathrm{Pa/m}$', transform=ax1.transAxes) + ax1.text(0.05, 0.70, f'$s={s[i]:.2f}' + r'\; \mathrm{m}$', transform=ax1.transAxes) + ax1.text(0.05, 0.60, f'$\\dot{{q}}_{{\\rm c}}\\prime \\prime={qdot[i]/1000:.3f}' + r'\; \mathrm{kW/m}^2$', transform=ax1.transAxes) + ax1.text(0.05, 0.50, f'$u({z_r:.0f}' + r'\; \mathrm{m})=' + f'{u_r:.1f}' + r'\; \mathrm{m/s}$', transform=ax1.transAxes) + ax1.text(0.05, 0.40, f'$L={L:.0f}$ m', transform=ax1.transAxes) + ax1.text(0.05, 0.30, f'$z_0={z_0[i]:.3f}$ m', transform=ax1.transAxes) + + plt.savefig(outfile + '_vel.pdf', format='pdf') + plt.close() + + # Create figure 2 for temperature + + ERROR = abs(T[-1] - 273.15 - M2.iloc[-1, 2]) + if ERROR > 1.0: + print(f'Python Warning: atmospheric_boundary_layer Case {i} temperature out of tolerance. ERROR = {ERROR} K') + + fig = fdsplotlib.plot_to_fig(x_data=M2.iloc[:,2].values, y_data=M2.iloc[:,0].values, marker_style='k-', data_label='FDS', + x_label='Temperature (°C)', y_label='Height (m)', + x_min=T_low[i], x_max=T_high[i], y_min=0, y_max=100) + + fdsplotlib.plot_to_fig(x_data=T - 273.15, y_data=z, figure_handle=fig, marker_style='ko', data_label='M-O Theory') + + ax2 = fig.axes[0] + + ax2.text(0.05, 0.90, f'Case {i}', transform=ax2.transAxes) + ax2.text(0.05, 0.80, f'$T({z_r:.0f}' + r'\; \mathrm{m})=' + f'{T_r-273:.1f}' + r'\;^\circ$C', transform=ax2.transAxes) + + plt.savefig(outfile + '_tmp.pdf', format='pdf') + plt.close() + diff --git a/Utilities/Python/scripts/burke_schumann.py b/Utilities/Python/scripts/burke_schumann.py new file mode 100644 index 00000000000..baa9c02988b --- /dev/null +++ b/Utilities/Python/scripts/burke_schumann.py @@ -0,0 +1,180 @@ +# C Weinschenk +# Verification of Mixture Fraction (Species,Temp,Pres) +# Fuel: Methane +# burke_schumann.m +# 9/2012 +# +# Converted by Floyd +# 10-16-2025 + +import pandas as pd +import numpy as np +import os + +# --- File Paths --- +base_dir = '../../Verification/Species/' +input_file_name = 'burke_schumann_devc.csv' + +skip_case = False + +if not os.path.exists(base_dir+input_file_name): + skip_case = True + print('Error: File ', input_file_name, ' does not exist. Skipping case.') + +if skip_case: quit() + +df = pd.read_csv(base_dir+input_file_name, skiprows=2, header=None) + +burke = df.values + +temperature = np.zeros((burke.shape[0], 15)) +rho = np.zeros((burke.shape[0], 15)) +h = np.zeros((burke.shape[0], 15)) +hrrpuv = np.zeros((burke.shape[0], 15)) +pressure = np.zeros((burke.shape[0], 15)) +mix_frac = np.zeros((burke.shape[0], 15)) +o2 = np.zeros((burke.shape[0], 15)) +ch4 = np.zeros((burke.shape[0], 15)) +h2o = np.zeros((burke.shape[0], 15)) +co2 = np.zeros((burke.shape[0], 15)) +n2 = np.zeros((burke.shape[0], 15)) + +for i in range(15): + start_idx = 1 + 11 * i + temperature[:, i] = burke[:, start_idx + 0] + 273.15 + rho[:, i] = burke[:, start_idx + 1] + h[:, i] = burke[:, start_idx + 2] + hrrpuv[:, i] = burke[:, start_idx + 3] + pressure[:, i] = burke[:, start_idx + 4] + 101325 + mix_frac[:, i] = burke[:, start_idx + 5] + o2[:, i] = burke[:, start_idx + 6] + ch4[:, i] = burke[:, start_idx + 7] + h2o[:, i] = burke[:, start_idx + 8] + co2[:, i] = burke[:, start_idx + 9] + n2[:, i] = burke[:, start_idx + 10] + +n2_o2_ratio = n2[0, 0] / o2[0, 0] # Initial o2/n2 ratio + +# Initialize as 2D arrays (time steps x 15 columns) +ox = np.zeros_like(o2) +prod = np.zeros_like(o2) + +for i in range(o2.shape[1]): + ox[:, i] = o2[:, i] + n2_o2_ratio * o2[:, i] + prod[:, i] = h2o[:, i] + co2[:, i] + (n2[:, i] - n2_o2_ratio * o2[:, i]) + +# --- Calculate Expected Species and Temperature Profiles --- + +volume = 0.001 +temp_0 = temperature[0, 0] +density = rho[0, 4] +R = 8.314472 + +# Molecular weights and heats of formation +y_MW = np.array([28.0134, 16.042460, 31.9988, 44.0095, 18.015280]) # [g/mol] +y_hf = np.array([0.0, -74873, 0.0, 0.0, 0.0]) # [J/mol] + +# Initial and final mass fractions (5 species x 15 probe points) +yf0 = np.vstack([n2[0, :], ch4[0, :], o2[0, :], co2[0, :], h2o[0, :]]) +yff = np.vstack([n2[-1, :], ch4[-1, :], o2[-1, :], co2[-1, :], h2o[-1, :]]) # row end is index -1 + +# Initialize arrays for loop +N0 = np.zeros_like(yf0) +Nf = np.zeros_like(yff) +mean_mw_f = np.zeros(15) +Rw = np.zeros(15) + +for i in range(15): + y_MW_kg_mol = y_MW / 1000.0 + mass_point = volume * density # mass is constant for all 15 points in this block + + N0[:, i] = (mass_point * yf0[:, i]) / y_MW_kg_mol + Nf[:, i] = (mass_point * yff[:, i]) / y_MW_kg_mol + + mole_frac_f = Nf[:, i] / np.sum(Nf[:, i]) + mean_mw_f[i] = np.sum(y_MW * mole_frac_f) + + Rw[i] = (R / mean_mw_f[i]) * 1000 + +# Heat of combustion [J/kg] +# hc = -y_hf(2)/y_MW(2)*1000; (y_hf(2) is index 1, y_MW(2) is index 1) +hc = -y_hf[1] / y_MW[1] * 1000 +cp = 1000 # [J/kg/K] set constant for all species +cv = cp - Rw # [J/kg/K] + +# --- Calculate State Relationships (Burke-Schumann) --- + +z_st = yf0[1, 4] +f = mix_frac[0, :] + +# Initialize arrays +Yf = np.zeros_like(f) +Yo2 = np.zeros_like(f) +Yp = np.zeros_like(f) +T_calc = np.zeros_like(f) + +for i in range(len(f)): + cv_i = cv[i] + + if f[i] > z_st and f[i] <= 1: + # Fuel-rich side + Yf[i] = (f[i] - z_st) / (1 - z_st) + Yo2[i] = 0 + Yp[i] = (1 - f[i]) / (1 - z_st) + T_calc[i] = f[i] * (-(z_st / (1 - z_st)) * (hc / cv_i)) + temp_0 + (z_st / ((1 - z_st) * cv_i)) * hc + elif f[i] >= 0 and f[i] < z_st: + # Fuel-lean side + Yf[i] = 0 + Yo2[i] = 1 - f[i] / z_st + Yp[i] = f[i] / z_st + # T_calc(i) = f(i)*((hc)/(cv(i)))+temp_0; + T_calc[i] = f[i] * (hc / cv_i) + temp_0 + else: + # Stoichiometric point (should be covered by the previous cases, but for completeness) + Yf[i] = 0 + Yo2[i] = 0 + Yp[i] = 1 + T_calc[i] = yf0[1, 4] * (hc / cv_i) + temp_0 + +T_adiab = T_calc[4] + +# Normalized Temperatures +T_calc_norm = (T_calc - temp_0) / (T_adiab - temp_0) +# temperature(end,:) is the final time step's temperature row +FDS_temp_norm = (temperature[-1, :] - temp_0) / (T_adiab - temp_0) + +# --- Write FDS and Expected Data to CSV Files --- + +# 1. Write Expected Data +burke_expected = np.zeros((len(mix_frac[0, :]), 5)) # 15 rows, 5 columns + +for i in range(len(mix_frac[0, :])): + burke_expected[i, 0] = mix_frac[0, i] + burke_expected[i, 1] = T_calc_norm[i] + burke_expected[i, 2] = Yf[i] + burke_expected[i, 3] = Yo2[i] + burke_expected[i, 4] = Yp[i] + +header1_expected = ['Mixture_Fraction', 'Temperature', 'Fuel', 'Ox', 'Prod'] + +# Create DataFrame for easy CSV writing with header +df_expected = pd.DataFrame(burke_expected, columns=header1_expected) +df_expected.to_csv(base_dir+'burke_schumann_expected.csv', index=False) +print(f"Written expected data to burke_schumann_expected.csv") + +# 2. Write FDS Data +burke_FDS = np.zeros((len(mix_frac[0, :]), 5)) # 15 rows, 5 columns + +for i in range(len(mix_frac[0, :])): + burke_FDS[i, 0] = mix_frac[0, i] + burke_FDS[i, 1] = FDS_temp_norm[i] + burke_FDS[i, 2] = ch4[-1, i] + burke_FDS[i, 3] = ox[-1, i] + burke_FDS[i, 4] = prod[-1, i] + +header1_FDS = ['Mixture_Fraction', 'FDS_Temperature', 'FDS_Fuel', 'FDS_Ox', 'FDS_Prod'] + +# Create DataFrame for easy CSV writing with header +df_FDS = pd.DataFrame(burke_FDS, columns=header1_FDS) +df_FDS.to_csv(base_dir+'burke_schumann_FDS.csv', index=False) +print(f"Written FDS data to burke_schumann_FDS.csv") \ No newline at end of file diff --git a/Utilities/Python/scripts/cat_propane_depo.py b/Utilities/Python/scripts/cat_propane_depo.py new file mode 100644 index 00000000000..aa505dc2005 --- /dev/null +++ b/Utilities/Python/scripts/cat_propane_depo.py @@ -0,0 +1,167 @@ +# Overholt +# 6-13-2012 +# cat_propane_depo.m +# +# Concatenates columns from Propane flame deposition FDS cases (/Verification/Aerosols) +# +# Converted by Floyd +# 10-16-2025 + + +import pandas as pd +import numpy as np +import os + + +outdir = '../../Verification/Aerosols/' + +# --- Condensed phase aerosol (Wall Deposition) --- + +# List of files for condensed phase aerosol (wall deposition) +wall_files = [ + 'propane_flame_deposition_devc.csv', + 'propane_flame_deposition_none_devc.csv', + 'propane_flame_deposition_gravitational_devc.csv', + 'propane_flame_deposition_thermophoretic_devc.csv', + 'propane_flame_deposition_turbulent_devc.csv' +] + +wall_columns = [ + 'depo_all', + 'depo_none', + 'depo_gravitational', + 'depo_thermophoretic', + 'depo_turbulent' +] + +skip_case = False + +for i in range(len(wall_files)): + name = outdir+wall_files[i] + if not os.path.exists(name): + skip_case = True + print('Error: File ', wall_files[i], ' does not exist. Skipping case.') + +if skip_case: quit() + +# Read data from the wall deposition files +wall_data = {} +for i, file in enumerate(wall_files): + wall_data[wall_columns[i]] = pd.read_csv(outdir+wall_files[i], skiprows=2, header=None) + +# Extract the relevant columns: +time_col = wall_data[wall_columns[0]].iloc[:, 0] +depo_all_col = wall_data[wall_columns[0]].iloc[:, 1] +depo_none_col = wall_data[wall_columns[1]].iloc[:, 1] +depo_grav_col = wall_data[wall_columns[2]].iloc[:, 1] +depo_therm_col = wall_data[wall_columns[3]].iloc[:, 1] +depo_turb_col = wall_data[wall_columns[4]].iloc[:, 1] + +# Create a DataFrame D1 +D1 = pd.DataFrame({ + 'Time': time_col, + 'depo_all': depo_all_col, + 'depo_none': depo_none_col, + 'depo_gravitational': depo_grav_col, + 'depo_thermophoretic': depo_therm_col, + 'depo_turbulent': depo_turb_col +}) + +# Add the two header rows defined in MATLAB +H1_units = ['s', 'kg', 'kg', 'kg', 'kg', 'kg'] +H1_names = ['Time', 'depo_all', 'depo_none', 'depo_gravitational', 'depo_thermophoretic', 'depo_turbulent'] + +# Create a dummy DataFrame for the headers +H1_df = pd.DataFrame([H1_units, H1_names], columns=D1.columns) + +# Concatenate headers and data +D1_final = pd.concat([H1_df, D1]).reset_index(drop=True) + +D1_final.to_csv(outdir+'propane_flame_deposition_cat_wall.csv', header=False, index=False) +print(f"Written condensed phase aerosol data to propane_flame_deposition_cat_wall.csv") + +# List of files for gas phase aerosol (mass loss) +gas_files = [ + 'propane_flame_deposition_mass.csv', + 'propane_flame_deposition_none_mass.csv', + 'propane_flame_deposition_gravitational_mass.csv', + 'propane_flame_deposition_thermophoretic_mass.csv', + 'propane_flame_deposition_turbulent_mass.csv' +] + +gas_columns = [ + 'depo_all', # Reused names for D2 columns, N1, N2, etc. are the source files + 'depo_none', + 'depo_gravitational', + 'depo_thermophoretic', + 'depo_turbulent' +] + +for i in range(len(gas_files)): + name = outdir+gas_files[i] + if not os.path.exists(name): + skip_case = True + print('Error: File ', gas_files[i], ' does not exist. Skipping case.') + +if skip_case: quit() + +# Read data from the gas mass files +gas_data = {} +for i, file in enumerate(gas_files): + gas_data[gas_columns[i]] = pd.read_csv(outdir+gas_files[i], skiprows=2, header=None) + +# Extract the relevant columns: +N1_time_col = gas_data[gas_columns[0]].iloc[:, 0] +N1_mass_col = gas_data[gas_columns[0]].iloc[:, 7] +N2_mass_col = gas_data[gas_columns[1]].iloc[:, 7] +N3_mass_col = gas_data[gas_columns[2]].iloc[:, 7] +N4_mass_col = gas_data[gas_columns[3]].iloc[:, 7] +N5_mass_col = gas_data[gas_columns[4]].iloc[:, 7] + +# Create a DataFrame D2 +D2 = pd.DataFrame({ + 'Time': N1_time_col, + 'depo_all': N1_mass_col, + 'depo_none': N2_mass_col, + 'depo_gravitational': N3_mass_col, + 'depo_thermophoretic': N4_mass_col, + 'depo_turbulent': N5_mass_col +}) + +# Add the two header rows defined in MATLAB (H2 is identical to H1) +H2_units = ['s', 'kg', 'kg', 'kg', 'kg', 'kg'] +H2_names = ['Time', 'depo_all', 'depo_none', 'depo_gravitational', 'depo_thermophoretic', 'depo_turbulent'] + +# Create a dummy DataFrame for the headers +H2_df = pd.DataFrame([H2_units, H2_names], columns=D2.columns) + +# Concatenate headers and data +D2_final = pd.concat([H2_df, D2]).reset_index(drop=True) + +# Write to CSV +D2_final.to_csv(outdir+'propane_flame_deposition_cat_gas.csv', header=False, index=False) +print(f"Written gas phase aerosol data to propane_flame_deposition_cat_gas.csv") + +# Create DataFrame D3 +D3 = pd.DataFrame({ + 'Time': N1_time_col, + 'depo_all': depo_all_col + N1_mass_col, + 'depo_none': depo_none_col + N2_mass_col, + 'depo_gravitational':depo_grav_col + N3_mass_col, + 'depo_thermophoretic': depo_therm_col + N4_mass_col, + 'depo_turbulent': depo_turb_col + N5_mass_col +}) + +# Add the two header rows defined in MATLAB (H3 is identical to H1 and H2) +H3_units = ['s', 'kg', 'kg', 'kg', 'kg', 'kg'] +H3_names = ['Time', 'depo_all', 'depo_none', 'depo_gravitational', 'depo_thermophoretic', 'depo_turbulent'] + +# Create a dummy DataFrame for the headers +H3_df = pd.DataFrame([H3_units, H3_names], columns=D3.columns) + +# Concatenate headers and data +D3_final = pd.concat([H3_df, D3]).reset_index(drop=True) + +# Write to CSV +D3_final.to_csv(outdir+ 'propane_flame_deposition_cat_total.csv', header=False, index=False) +print(f"Written total aerosol data to propane_flame_deposition_cat_total.csv") \ No newline at end of file diff --git a/Utilities/Python/scripts/catchpole_spread_rates.py b/Utilities/Python/scripts/catchpole_spread_rates.py index b5d44fd7303..dc65c5e845b 100644 --- a/Utilities/Python/scripts/catchpole_spread_rates.py +++ b/Utilities/Python/scripts/catchpole_spread_rates.py @@ -8,16 +8,13 @@ import warnings warnings.simplefilter('ignore', np.RankWarning) -# include FDS plot styles, etc. filedir = os.path.dirname(__file__) firemodels = os.path.join(filedir,'..','..','..','..') sys.path.append(filedir+os.sep+'..'+os.sep) import fdsplotlib -# Get plot style parameters plot_style = fdsplotlib.get_plot_style("fds") -# Define paths base_path = os.path.join(firemodels,'out','USFS_Catchpole') fig_path = os.path.join(firemodels,'fds','Manuals','FDS_Validation_Guide','SCRIPT_FIGURES','USFS_Catchpole') validation_path = os.path.join(firemodels,'fds','Validation','USFS_Catchpole','FDS_Input_Files') @@ -32,8 +29,6 @@ git_file = os.path.join(base_path, f"{chid}_git.txt") fig_file = os.path.join(fig_path, f"{chid}.pdf") - print(" plotting {}...".format(chid)) - if os.path.exists(fds_file) is False: print(f'Error: File {fds_file} does not exist. Skipping case.') continue @@ -52,30 +47,20 @@ if R_FDS<0: R_FDS=0 - # Exp results x_exp = np.array([0., 8.]) t_exp = np.array([0., 8./R]) version_string = fdsplotlib.get_version_string(git_file) fig = fdsplotlib.plot_to_fig(x_data=t_exp, y_data=x_exp, + revision_label=version_string, + x_min=0., x_max=8./R, y_min=0., y_max=8., + x_label='Time (s)', y_label='Distance (m)', data_label='EXP', marker_style='k-') - fdsplotlib.plot_to_fig(x_data=fds_data['Time'].values, y_data=fds_data['x'].values, - revision_label=version_string, - figure_handle=fig, - data_label='FDS', - x_label='Time (s)', - y_label='Distance (m)', - marker_style='k--', - y_min=0.,y_max=8., - x_min=0.,x_max=8./R, - legend_location="lower right", - show_legend='show', - ) + fdsplotlib.plot_to_fig(x_data=fds_data['Time'].values, y_data=fds_data['x'].values, figure_handle=fig, data_label='FDS', marker_style='k--') - #fig.supertitle(chid) - fig.savefig(fig_file) - plt.close(fig) + plt.savefig(fig_file) + plt.close() # write table for dataplot tests.loc[tests['Test'].index[ti],'R_FDS'] = R_FDS @@ -87,32 +72,29 @@ # add fds data to full table for summary plotting tests.loc[ti,'R_FDS'] = R_FDS -##### Create summary plots +# Create summary plots -# variables of interest dep_variables={"s":"Surface-to-Volume Ratio (1/m)", "beta":"Packing Ratio (-)", "U":"Wind Speed (m/s)", "M":"FMC (-)"} -# fuel labels for filtering data fuel_labels=["MF","EXSC","PPMC","EX"] +colors = ['b','g','r','c','m','y','k'] # matlab defauls + for dvar in dep_variables: - plt.rcParams['mathtext.fontset'] = 'stix' #'dejavuserif' - plt.rcParams['mathtext.default'] = 'rm' - plt.rcParams['axes.formatter.use_mathtext'] = False fig_file = os.path.join(fig_path, f"Catchpole_R_v_{dvar}.pdf") # show +/- 20% relative error [xmin,xmax] = [tests[dvar].min(),tests[dvar].max()] - colors = ['b','g','r','c','m','y','k'] # matlab defauls fig = fdsplotlib.plot_to_fig(x_data=[xmin, xmax], y_data=[0.8,0.8], plot_type='semilogy', marker_style='k--', x_min=xmin, x_max=xmax, y_min=3e-3, y_max=1.1e1, - x_label=dep_variables[dvar],y_label=r"$\mathrm{R_{FDS}/R_{Exp}}$ $\mathrm{(-)}$", - show_legend='show', legend_framealpha=1.0, legend_location=2, + x_label=dep_variables[dvar], y_label=r"$\mathrm{R_{FDS}/R_{Exp}}$", revision_label=version_string) + fdsplotlib.plot_to_fig(x_data=[xmin, xmax], y_data=[1.2,1.2], marker_style='k--', figure_handle=fig) + for i in range(0, len(fuel_labels)): fuel = fuel_labels[i] filtered_data = tests[tests['Test'].str.startswith(fuel)] @@ -121,13 +103,8 @@ filtered_data = tests[ (tests['Test'].str.startswith(fuel))&(~tests['Test'].str.startswith('EXSC'))] fdsplotlib.plot_to_fig(x_data=filtered_data[dvar], y_data=filtered_data['R_FDS']/filtered_data['R'], - data_label=fuel, plot_type='semilogy', marker_style=colors[i]+'o', figure_handle=fig) - - fdsplotlib.plot_to_fig(x_data=[xmin, xmax], y_data=[1.2,1.2], - plot_type='semilogy', marker_style='k--', figure_handle=fig) + data_label=fuel, marker_style=colors[i]+'o', figure_handle=fig) - plt.gca().yaxis.set_major_formatter(ScalarFormatter()) - plt.savefig(fig_file) plt.close(fig) @@ -156,11 +133,8 @@ ax.set_ylim([0, 1]) ax.set_yticks([0, 1],['min','max']) -plt.legend(loc="upper left", fontsize=plot_style["Key_Font_Size"], - framealpha=1,frameon=True) +plt.legend(loc="upper left", fontsize=plot_style["Key_Font_Size"], framealpha=1,frameon=True) -# Show the plot -plt.tight_layout() plt.savefig(fig_file) plt.close() diff --git a/Utilities/Python/scripts/extinction.py b/Utilities/Python/scripts/extinction.py index 4ba426ab92f..2dc14423733 100644 --- a/Utilities/Python/scripts/extinction.py +++ b/Utilities/Python/scripts/extinction.py @@ -1,18 +1,18 @@ -# Extinction Verification -# Jonathan Hodges -# 2024-06-17 -# Based on original matlab script: -#----------------------- -# C Weinschenk -# Verification of Extinction Model -# Fuel: Methane -# 6/2012 -#----------------------- +#!/usr/bin/env python3 +""" +extinction.py +Converted from MATLAB script extinction.m to Python. +----------------------- +C Weinschenk +Verification of Extinction Model +Fuel: Methane +6/2012 +----------------------- +""" import os import numpy as np import pandas as pd -import matplotlib.pyplot as plt -plt.rcParams["pdf.use14corefonts"] = True +import fdsplotlib #----------------------- # Initialize species @@ -38,13 +38,15 @@ y_hf = [0.0, -74873, 0.0, -393522, -241826] # [J/mol] pres_0 = 1.013253421185575e+05 # initial presure [Pa] -# Plotting params -Scat_Label_Font_Size = 16 -Key_Font_Size = 12 -default_ticklabel_fontsize = 16 -default_stamp_fontsize = 12 -figsize=(6,6) -pltdir = '../../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/' +# ----------------------------- +# Paths and identifiers +# ----------------------------- +firemodels_dir = os.path.normpath(os.path.join(os.path.dirname(__file__),'..','..','..','..')) +fds_dir = os.path.normpath(os.path.join(os.path.dirname(__file__),'..','..','..')) +#outdir = os.path.join(firemodels_dir, 'out','Convection','') +results_dir = os.path.join(fds_dir, 'Verification','Extinction','') +pltdir = os.path.join(fds_dir, 'Manuals','FDS_User_Guide','SCRIPT_FIGURES','') +os.makedirs(pltdir, exist_ok=True) # Initialize variable arrays num_samp = 100 # number of input sets @@ -234,9 +236,8 @@ #----------------------- epsilon = 1e-10 -results_dir = '../../../Verification/Extinction/' -fds_file = [results_dir + 'extinction_1_devc.csv', - results_dir + 'extinction_2_devc.csv'] +fds_file = [os.path.join(results_dir, 'extinction_1_devc.csv'), + os.path.join(results_dir + 'extinction_2_devc.csv')] X_ignite=np.zeros((num_samp,2)) X_fds_ignite=np.zeros((num_samp,2)) @@ -277,8 +278,6 @@ # Make the plot - fig, ax = plt.subplots(1, 1, figsize=figsize) - tmpm = 273 X_simple_o2 = (simple_o2/32)/(simple_o2/32 + (1-simple_o2)/28) X_ignite[:,1] = (ignite[:,1]/32)/(ignite[:,1]/32 + (1-ignite[:,1])/28) @@ -295,30 +294,25 @@ ignite[jj,0]=extinct_o2[jj,0] extinct_o2[jj,0]=0 - ax.plot(simple_temp-tmpm,X_simple_o2,'k',linewidth=1.0,markersize=4, label='Simple Model') - ax.scatter(ignite[:,0]-tmpm,X_ignite[:,1],80,marker='s',label='Expected Burning', facecolors='none', edgecolors='r', linewidths=1) - ax.scatter(fds_ignite[:,0]-tmpm,X_fds_ignite[:,1],40,color='r',marker='+', label='FDS Burning', linewidths=1) - ax.scatter(extinct_o2[:,0]-tmpm,X_extinct_o2[:,1],80,marker='o',label='Expected Extinction', facecolors='none', edgecolors='b', linewidths=1) - ax.scatter(fds_ext_o2[:,0]-tmpm,X_fds_ext_o2[:,1],40,color='b',marker='*',label='FDS Extinction', linewidths=1) - ax.set_xlim(0, 1700) - ax.set_ylim(0, 0.21) - ax.set_xticks([0, 500, 1000, 1500]) - ax.set_yticks([0, 0.02, 0.04, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.20]) - ax.set_xlabel('Temperature (°C)',fontsize=Scat_Label_Font_Size) - ax.set_ylabel('Oxygen Volume Fraction',fontsize=Scat_Label_Font_Size) - lh=plt.legend(fontsize=Key_Font_Size, loc=1, framealpha=1) - ax.tick_params(labelsize=default_ticklabel_fontsize) - - # add Git if file is available - git_file = results_dir + 'extinction_1_git.txt' - - if (os.path.exists(git_file)): - file1 = open(git_file,"r") - Lines = file1.readlines() - version_string = Lines[0].strip() - file1.close() - ax.text(0.975, 1.01, version_string, fontsize=default_stamp_fontsize, ha='right', transform=ax.transAxes) - - plt.tight_layout() - plt.savefig(pltdir + 'extinction_%d.pdf'%(ifile+1), backend='pdf') + git_file = os.path.join(results_dir, 'extinction_1_git.txt') + version_string = fdsplotlib.get_version_string(git_file) + fig = fdsplotlib.plot_to_fig(x_data=simple_temp-tmpm, y_data=X_simple_o2, marker_style='k-', data_label='Simple Model', linewidth=1, + x_min=0.0, x_max=1700, y_min=0, y_max=0.21, xticks=[0, 500, 1000, 1500], yticks=np.linspace(0, 0.2, 11), + revision_label=version_string, figure_handle=None, + x_label='Temperature (°C)', + y_label='Oxygen Volume Fraction', + figure_size=(6,6), plot_size=(4.5,4.5), plot_origin=(1.125,1.0)) + fdsplotlib.plot_to_fig(x_data=ignite[:,0]-tmpm, y_data=X_ignite[:,1], marker_style='rs', data_label='Expected Burning', + marker_fill_color=(1,1,1,0.0), markersize=6, markeredgewidth=0.5, figure_handle=fig) + fdsplotlib.plot_to_fig(x_data=fds_ignite[:,0]-tmpm, y_data=X_fds_ignite[:,1], marker_style='r+', data_label='FDS Burning', + marker_fill_color=(1,1,1,0.0), markersize=4, markeredgewidth=0.5, figure_handle=fig) + fdsplotlib.plot_to_fig(x_data=extinct_o2[:,0]-tmpm, y_data=X_extinct_o2[:,1], marker_style='bo', data_label='Expected Extinction', + marker_fill_color=(1,1,1,0.0), markersize=7, markeredgewidth=0.5, figure_handle=fig) + fdsplotlib.plot_to_fig(x_data=fds_ext_o2[:,0]-tmpm, y_data=X_fds_ext_o2[:,1], marker_style='b*', data_label='FDS Extinction', + markersize=4, markeredgewidth=0.5, figure_handle=fig) + fig.axes[0].xaxis.set_tick_params(pad=10) + fig.axes[0].yaxis.set_tick_params(pad=10) + local_pdf = os.path.join(pltdir, 'extinction_%d.pdf'%(ifile+1)) + fig.savefig(local_pdf) + \ No newline at end of file diff --git a/Utilities/Python/scripts/extinction_1_sketch.py b/Utilities/Python/scripts/extinction_1_sketch.py new file mode 100644 index 00000000000..8391509c375 --- /dev/null +++ b/Utilities/Python/scripts/extinction_1_sketch.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +""" +extinction_1_sketch.py +Converted from MATLAB script extinction_1_sketch.m to Python. + +Makes figure for 'EXTINCTION 1' model for Tech Guide +""" + +import os +import numpy as np +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style("fds") + +# ----------------------------- +# Paths (mirror extinction.py layout) +# ----------------------------- +# Repository roots relative to this file +firemodels_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')) +fds_dir = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', '..')) + +# Output directory consistent with MATLAB script intent +plot_dir = os.path.join(fds_dir, 'Manuals', 'FDS_Technical_Reference_Guide', 'FIGURES') +os.makedirs(plot_dir, exist_ok=True) + +# ----------------------------- +# Data (from MATLAB script) +# ----------------------------- +# Temperature in °C +T1 = np.arange(0, 600 + 1, 1) # 0:600 +T2 = np.arange(600, 1500 + 1, 1) # 600:1500 + +# Oxygen volume fraction pieces +X_O2_1 = 0.135 * (1.0 - (T1 - 20.0) / 1427.0) +X_O2_2 = 0.135 * (1.0 - (T2 - 20.0) / 1427.0) + +# ----------------------------- +# Make the figure (fdsplotlib style) +# ----------------------------- +# Base figure with first segment (solid 'k-') +fig = fdsplotlib.plot_to_fig( + x_data=T1, + y_data=X_O2_1, + marker_style='k-', + linewidth=1, + data_label=None, + x_min=0.0, x_max=1500.0, + y_min=0.0, y_max=0.2, + xticks=[0, 500, 1000, 1500], + yticks=np.linspace(0.0, 0.2, 5), + x_label='Temperature (°C)', + y_label='Oxygen Volume Fraction', +) + +# Second segment (dashed 'k--') +fdsplotlib.plot_to_fig( + x_data=T2, + y_data=X_O2_2, + marker_style='k--', + linewidth=1, + figure_handle=fig +) + +# Vertical line at T = 600 °C from y=0 to y=0.08013 +fdsplotlib.plot_to_fig( + x_data=[600, 600], + y_data=[0.0, 0.08013], + marker_style='k-', + linewidth=1, + figure_handle=fig +) + +# Axis label padding similar to extinction.py +ax = fig.axes[0] +ax.xaxis.set_tick_params(pad=10) +ax.yaxis.set_tick_params(pad=10) + +# Text annotations (positions from MATLAB) +ax.text(150, 0.06, 'No Burn', fontsize=plot_style['Label_Font_Size']) +ax.text(800, 0.03, 'Burn', fontsize=plot_style['Label_Font_Size']) +ax.text(700, 0.15, 'Burn', fontsize=plot_style['Label_Font_Size']) + +# Output path +out_pdf = os.path.join(plot_dir, 'extinction_1_sketch.pdf') + +fig.savefig(out_pdf) +print(f"Saved figure to {out_pdf}") \ No newline at end of file diff --git a/Utilities/Python/scripts/fan_curve.py b/Utilities/Python/scripts/fan_curve.py new file mode 100644 index 00000000000..d6cb2557688 --- /dev/null +++ b/Utilities/Python/scripts/fan_curve.py @@ -0,0 +1,45 @@ + +# Makes figure for HVAC Fan Parameters section of the FDS Users Guide + +import numpy as np +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +pltdir = '../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/' + +vdot_max = 10 +dp_max = 500 +dp = np.arange(-1000, 1001, 1) + +# Constant volume flow rate +vdot1 = 10 + +# Plot quadratic fan curve (black line) +vdot = vdot_max * np.sign(dp_max - dp) * np.sqrt(np.abs(dp - dp_max) / dp_max) + +# Create user fan curve (ramp) data points +rampx = [] +rampy = [] +i = 0 +for dp_val in range(-1000, 1001, 200): + rampx.append(vdot_max * np.sign(dp_max - dp_val) * np.sqrt(np.abs(dp_val - dp_max) / dp_max)) + rampy.append(dp_val) + i = i + 1 + +fig = fdsplotlib.plot_to_fig(x_data=[vdot1,vdot1], y_data=[-1000,1000], marker_style='r-', data_label='constant volume', + x_min=-10, x_max=20, y_min=-1000, y_max=1000, + x_label='Volume Flow Rate (m$^3$/s)', + y_label='Static Pressure (Pa)') + +fdsplotlib.plot_to_fig(x_data=vdot, y_data=dp, marker_style='k-', data_label='quadratic', figure_handle=fig) +fdsplotlib.plot_to_fig(x_data=rampx, y_data=rampy, marker_style='b-', data_label='user fan curve', figure_handle=fig) + +# Enable grid +ax = plt.gca() +ax.grid(True, which='both', axis='both') + +plt.savefig(pltdir + 'fan_curve.pdf', format='pdf') +plt.close() + diff --git a/Utilities/Python/scripts/favre_test.py b/Utilities/Python/scripts/favre_test.py new file mode 100644 index 00000000000..35f25ba36ca --- /dev/null +++ b/Utilities/Python/scripts/favre_test.py @@ -0,0 +1,178 @@ + +# compare TEMPORAL_STATISTIC='FAVRE AVERAGE' with brute force Favre average + +import pandas as pd +import numpy as np + +outdir = '../../Verification/Species/' + +# gather Favre averages from line file + +L = pd.read_csv(outdir + 'favre_test_line.csv', skiprows=1) +M = pd.read_csv(outdir + 'favre_test_devc.csv', skiprows=1) +t_stats_start = M.iloc[-1, 0] / 2 +t = M[M.iloc[:, 0] > t_stats_start].iloc[:, 0].values +T = t[-1] - t[0] + +# cell data + +YL1 = L.iloc[0, L.columns.get_loc('YTILDE_O2')] +YL2 = L.iloc[1, L.columns.get_loc('YTILDE_O2')] +YL3 = L.iloc[2, L.columns.get_loc('YTILDE_O2')] + +YRMSL1 = L.iloc[0, L.columns.get_loc('YO2_RMS')] +YRMSL2 = L.iloc[1, L.columns.get_loc('YO2_RMS')] +YRMSL3 = L.iloc[2, L.columns.get_loc('YO2_RMS')] + +RHO1 = M[M.iloc[:, 0] > t_stats_start]['RHO_1'].values +RHO2 = M[M.iloc[:, 0] > t_stats_start]['RHO_2'].values +RHO3 = M[M.iloc[:, 0] > t_stats_start]['RHO_3'].values +RHOYO2_1 = M[M.iloc[:, 0] > t_stats_start]['RHOYO2_1'].values +RHOYO2_2 = M[M.iloc[:, 0] > t_stats_start]['RHOYO2_2'].values +RHOYO2_3 = M[M.iloc[:, 0] > t_stats_start]['RHOYO2_3'].values + +# brute force integration for means + +NUM1 = 0 +NUM2 = 0 +NUM3 = 0 +DENOM1 = 0 +DENOM2 = 0 +DENOM3 = 0 +for i in range(1, len(t)): + dt = t[i] - t[i-1] + NUM1 = NUM1 + RHOYO2_1[i] * dt + NUM2 = NUM2 + RHOYO2_2[i] * dt + NUM3 = NUM3 + RHOYO2_3[i] * dt + DENOM1 = DENOM1 + RHO1[i] * dt + DENOM2 = DENOM2 + RHO2[i] * dt + DENOM3 = DENOM3 + RHO3[i] * dt + +YTILDE1 = NUM1 / DENOM1 +YTILDE2 = NUM2 / DENOM2 +YTILDE3 = NUM3 / DENOM3 + +# compute error and report if necessary + +e1 = abs(YL1 - YTILDE1) +e2 = abs(YL2 - YTILDE2) +e3 = abs(YL3 - YTILDE3) + +tol = 1e-4 +if e1 > tol: + print(f'Matlab Warning: e1 = {e1} in Species/favre_test mean cell data') +if e2 > tol: + print(f'Matlab Warning: e2 = {e2} in Species/favre_test mean cell data') +if e3 > tol: + print(f'Matlab Warning: e3 = {e3} in Species/favre_test mean cell data') + +# brute force integration for rms + +NUM1 = 0 +NUM2 = 0 +NUM3 = 0 +for i in range(1, len(t)): + dt = t[i] - t[i-1] + NUM1 = NUM1 + (RHOYO2_1[i] / RHO1[i] - YTILDE1)**2 * dt + NUM2 = NUM2 + (RHOYO2_2[i] / RHO2[i] - YTILDE2)**2 * dt + NUM3 = NUM3 + (RHOYO2_3[i] / RHO3[i] - YTILDE3)**2 * dt + +YRMS1 = np.sqrt(NUM1 / T) +YRMS2 = np.sqrt(NUM2 / T) +YRMS3 = np.sqrt(NUM3 / T) + +# compute error and report if necessary + +e1 = abs(YRMSL1 - YRMS1) +e2 = abs(YRMSL2 - YRMS2) +e3 = abs(YRMSL3 - YRMS3) + +tol = 1e-2 +if e1 > tol: + print(f'Matlab Warning: e1 = {e1} in Species/favre_test rms cell data') +if e2 > tol: + print(f'Matlab Warning: e2 = {e2} in Species/favre_test rms cell data') +if e3 > tol: + print(f'Matlab Warning: e3 = {e3} in Species/favre_test rms cell data') + +# interpolated data + +YL1 = L.iloc[0, L.columns.get_loc('YTILDE_O2_INT')] +YL2 = L.iloc[1, L.columns.get_loc('YTILDE_O2_INT')] +YL3 = L.iloc[2, L.columns.get_loc('YTILDE_O2_INT')] + +YRMSL1 = L.iloc[0, L.columns.get_loc('YO2_RMS_INT')] +YRMSL2 = L.iloc[1, L.columns.get_loc('YO2_RMS_INT')] +YRMSL3 = L.iloc[2, L.columns.get_loc('YO2_RMS_INT')] + +RHO1 = M[M.iloc[:, 0] > t_stats_start]['RHO_1_INT'].values +RHO2 = M[M.iloc[:, 0] > t_stats_start]['RHO_2_INT'].values +RHO3 = M[M.iloc[:, 0] > t_stats_start]['RHO_3_INT'].values +RHOYO2_1 = M[M.iloc[:, 0] > t_stats_start]['RHOYO2_1_INT'].values +RHOYO2_2 = M[M.iloc[:, 0] > t_stats_start]['RHOYO2_2_INT'].values +RHOYO2_3 = M[M.iloc[:, 0] > t_stats_start]['RHOYO2_3_INT'].values + +# brute force integration + +NUM1 = 0 +NUM2 = 0 +NUM3 = 0 +DENOM1 = 0 +DENOM2 = 0 +DENOM3 = 0 +for i in range(1, len(t)): + dt = t[i] - t[i-1] + NUM1 = NUM1 + RHOYO2_1[i] * dt + NUM2 = NUM2 + RHOYO2_2[i] * dt + NUM3 = NUM3 + RHOYO2_3[i] * dt + DENOM1 = DENOM1 + RHO1[i] * dt + DENOM2 = DENOM2 + RHO2[i] * dt + DENOM3 = DENOM3 + RHO3[i] * dt + +YTILDE1 = NUM1 / DENOM1 +YTILDE2 = NUM2 / DENOM2 +YTILDE3 = NUM3 / DENOM3 + +# compute error and report if necessary + +e1 = abs(YL1 - YTILDE1) +e2 = abs(YL2 - YTILDE2) +e3 = abs(YL3 - YTILDE3) + +tol = 1e-4 +if e1 > tol: + print(f'Matlab Warning: e1 = {e1} in Species/favre_test mean interpolated data') +if e2 > tol: + print(f'Matlab Warning: e2 = {e2} in Species/favre_test mean interpolated data') +if e3 > tol: + print(f'Matlab Warning: e3 = {e3} in Species/favre_test mean interpolated data') + +# brute force integration for rms + +NUM1 = 0 +NUM2 = 0 +NUM3 = 0 +for i in range(1, len(t)): + dt = t[i] - t[i-1] + NUM1 = NUM1 + (RHOYO2_1[i] / RHO1[i] - YTILDE1)**2 * dt + NUM2 = NUM2 + (RHOYO2_2[i] / RHO2[i] - YTILDE2)**2 * dt + NUM3 = NUM3 + (RHOYO2_3[i] / RHO3[i] - YTILDE3)**2 * dt + +YRMS1 = np.sqrt(NUM1 / T) +YRMS2 = np.sqrt(NUM2 / T) +YRMS3 = np.sqrt(NUM3 / T) + +# compute error and report if necessary + +e1 = abs(YRMSL1 - YRMS1) +e2 = abs(YRMSL2 - YRMS2) +e3 = abs(YRMSL3 - YRMS3) + +tol = 1e-2 +if e1 > tol: + print(f'Matlab Warning: e1 = {e1} in Species/favre_test rms interpolated data') +if e2 > tol: + print(f'Matlab Warning: e2 = {e2} in Species/favre_test rms interpolated data') +if e3 > tol: + print(f'Matlab Warning: e3 = {e3} in Species/favre_test rms interpolated data') + diff --git a/Utilities/Python/scripts/flame_species.py b/Utilities/Python/scripts/flame_species.py new file mode 100644 index 00000000000..a5c742cb159 --- /dev/null +++ b/Utilities/Python/scripts/flame_species.py @@ -0,0 +1,91 @@ +# C Weinschenk +# flame_species.m +# 10-2011 +# Combine outputs from Methane_flame_lumped and +# Methane_flame_primitive into 1 file +# ------------------------------------------------ +# +# Converted by Floyd +# 10/16/2025 + +import pandas as pd +import numpy as np +import os +import csv +from typing import List, Tuple, Optional + + +# Write directory +outdir = '../../Verification/Species/' +filename = [ + 'methane_flame_primitive_devc.csv', + 'methane_flame_primitive_2_devc.csv', + 'methane_flame_lumped_devc.csv', + 'methane_flame_lumped_fuel_devc.csv', + 'methane_flame_lumped_ox_devc.csv', +] + +skip_case = False + +for i in range(len(filename)): + name = outdir+filename[i] + if not os.path.exists(name): + skip_case = True + print('Error: File ', filename[i], ' does not exist. Skipping case.') + +if skip_case: quit() + +h_mf_p = pd.read_csv(outdir+filename[0],skiprows=1,nrows=1,header=None) +h_mf_p_2 = pd.read_csv(outdir+filename[1],skiprows=1,nrows=1,header=None) +h_mf_l = pd.read_csv(outdir+filename[2],skiprows=1,nrows=1,header=None) +h_mf_l_f = pd.read_csv(outdir+filename[3],skiprows=1,nrows=1,header=None) +h_mf_l_o = pd.read_csv(outdir+filename[4],skiprows=1,nrows=1,header=None) + +mf_p = pd.read_csv(outdir+filename[0],skiprows=2,header=None) +mf_p_2 = pd.read_csv(outdir+filename[1],skiprows=2,header=None) +mf_l = pd.read_csv(outdir+filename[2],skiprows=2,header=None) +mf_l_f = pd.read_csv(outdir+filename[3],skiprows=2,header=None) +mf_l_o = pd.read_csv(outdir+filename[4],skiprows=2,header=None) + +header_lp = tuple(h_mf_p.iloc[0,:]) + tuple(h_mf_l.iloc[0,1:]) + +print(header_lp) + +data_combined_lp = pd.concat([mf_p, mf_l.iloc[:, 1:4]], axis=1) +data_combined_lp.columns = header_lp + +print(data_combined_lp) + +header_ml = tuple(h_mf_p_2.iloc[0,:]) + tuple(h_mf_l_f.iloc[0,1:3]) + tuple(h_mf_l_o.iloc[0,1:3]) +print(header_ml) +data_combined_ml = pd.concat([mf_p_2, mf_l_f.iloc[:, 1:3], mf_l_o.iloc[:, 1:3]], axis=1) +data_combined_ml.columns = header_ml + +print(data_combined_ml) + +output_file_1 = outdir+'methane_flame_lumpedprimitive.csv' + +# The MATLAB script uses a hardcoded units line for the final output. +hardcoded_units = ['s', 'kg', 'kg', 'kg', 'kg', 'kg', 'kg'] + +# Create a temporary DataFrame for the two header rows +header_df_1 = pd.DataFrame([hardcoded_units, header_lp], columns=data_combined_lp.columns) + +# Concatenate headers and data +df_out_1 = pd.concat([header_df_1, data_combined_lp]).reset_index(drop=True) + +# Write to CSV without the pandas index or automatically generated header +df_out_1.to_csv(output_file_1, header=False, index=False) +print(f"Successfully wrote combined data to {output_file_1}") + +output_file_2 = outdir+'methane_flame_multilumped.csv' + +# Create a temporary DataFrame for the two header rows +header_df_2 = pd.DataFrame([hardcoded_units, header_ml], columns=data_combined_ml.columns) + +# Concatenate headers and data +df_out_2 = pd.concat([header_df_2, data_combined_ml]).reset_index(drop=True) + +# Write to CSV without the pandas index or automatically generated header +df_out_2.to_csv(output_file_2, header=False, index=False) +print(f"Successfully wrote multi-lumped data to {output_file_2}") diff --git a/Utilities/Python/scripts/fluid_part.py b/Utilities/Python/scripts/fluid_part.py new file mode 100644 index 00000000000..fa8c533fd24 --- /dev/null +++ b/Utilities/Python/scripts/fluid_part.py @@ -0,0 +1,487 @@ + +# Particle/Gas momentum transfer + +import struct +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +outdir = '../../Verification/Sprinklers_and_Sprays/' +pltdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/' + +git_file = outdir + 'fluid_part_mom_x_git.txt' +version_string = fdsplotlib.get_version_string(git_file) + + +def read_prt5(filename, precision, *varargin): + """ + Read FDS part file (*.prt5) + + Parameters: + ----------- + filename : str + Name of the .prt5 file + precision : str + 'real*4' or 'real*8' depending on EB_PART_FILE setting + *varargin : optional arguments + Pass 'evac', 'EVAC', or 'Evac' for FDS+Evac files + + Returns: + -------- + STIME : numpy.ndarray + Simulation times + XP : numpy.ndarray + X positions of particles + YP : numpy.ndarray + Y positions of particles + ZP : numpy.ndarray + Z positions of particles + QP : numpy.ndarray + Particle quantities + AP : numpy.ndarray (optional, only for evac mode with 6 outputs) + Additional particle data for evacuation mode + """ + + # Determine number of outputs requested by caller + # In Python, we'll return a tuple and let caller unpack as needed + # For now, we'll track if AP should be returned + nout = 6 if len(varargin) > 0 else 5 + + evac = False + if len(varargin) > 0: + if varargin[0] in ['evac', 'EVAC', 'Evac']: + evac = True + + fid = open(filename, 'rb') + + # Determine precision formats for struct + if precision == 'real*4': + real_format = ' 0: + DUMMY = struct.unpack(int_format, fid.read(int_size))[0] + + qp_class = [] + for NQ in range(N_QUANTITIES[NPC]): + qp_bytes = fid.read(NPLIM * real_size) + qp = np.frombuffer(qp_bytes, dtype=real_dtype) + qp_class.append(qp) + + QP_time.append(qp_class) + DUMMY = struct.unpack(int_format, fid.read(int_size))[0] + else: + QP_time.append([]) + + XP_list.append(XP_time) + YP_list.append(YP_time) + ZP_list.append(ZP_time) + QP_list.append(QP_time) + if evac and nout == 6: + AP_list.append(AP_time) + + n += 1 + + fid.close() + + # Convert lists to numpy arrays with proper dimensions + STIME = np.array(STIME_list) + + # Determine maximum number of particles across all time steps and classes + max_particles = 0 + for time_step in XP_list: + for particle_class in time_step: + max_particles = max(max_particles, len(particle_class)) + + # Initialize arrays with NaN for missing data + n_time = len(STIME_list) + XP = np.full((n_time, max_particles, N_PART), np.nan) + YP = np.full((n_time, max_particles, N_PART), np.nan) + ZP = np.full((n_time, max_particles, N_PART), np.nan) + + # Fill position arrays + for t in range(n_time): + for npc in range(N_PART): + n_particles = len(XP_list[t][npc]) + XP[t, :n_particles, npc] = XP_list[t][npc] + YP[t, :n_particles, npc] = YP_list[t][npc] + ZP[t, :n_particles, npc] = ZP_list[t][npc] + + # Handle QP array (4D) + max_quantities = max(N_QUANTITIES) if N_QUANTITIES else 0 + QP = np.full((n_time, max_particles, N_PART, max_quantities), np.nan) + + for t in range(n_time): + for npc in range(N_PART): + if len(QP_list[t][npc]) > 0: + n_particles = len(QP_list[t][npc][0]) + for nq in range(len(QP_list[t][npc])): + QP[t, :n_particles, npc, nq] = QP_list[t][npc][nq] + + # Handle AP array for evac mode + if evac and nout == 6: + AP = np.full((n_time, max_particles, N_PART, 4), np.nan) + for t in range(n_time): + for npc in range(N_PART): + n_particles = AP_list[t][npc].shape[0] + AP[t, :n_particles, npc, :] = AP_list[t][npc] + + return STIME, XP, YP, ZP, QP, AP + else: + return STIME, XP, YP, ZP, QP + + +# Read CSV files (skip 2 header rows) +M = pd.read_csv(outdir + 'fluid_part_mom_x_devc.csv', skiprows=1) +tx = M.iloc[:, 0].values +U = M.iloc[:, 1].values +MX = M.iloc[:, 2].values + +M = pd.read_csv(outdir + 'fluid_part_mom_y_devc.csv', skiprows=1) +ty = M.iloc[:, 0].values +V = M.iloc[:, 1].values +MY = M.iloc[:, 2].values + +M = pd.read_csv(outdir + 'fluid_part_mom_z_devc.csv', skiprows=1) +tz = M.iloc[:, 0].values +W = M.iloc[:, 1].values +MZ = M.iloc[:, 2].values + +# Create range for plotting (every 10th point) +range_idx = np.arange(0, min([len(tx), len(ty), len(tz)]), 10) + +# Create first figure +fig = fdsplotlib.plot_to_fig(x_data=[-1,-1], y_data=[-1,-1], + x_min=0, x_max=1, y_min=0, y_max=150, + revision_label=version_string, + figure_size=(plot_style['Paper_Width']+0.4,plot_style['Paper_Height']), + legend_location='outside', + x_label='Time (s)', + y_label='Momentum (kg m/s)') + +fdsplotlib.plot_to_fig(x_data=tx[range_idx], y_data=MX[range_idx]*U[range_idx], figure_handle=fig, marker_style='bo', marker_fill_color='none', data_label='FDS fluid $u$') +fdsplotlib.plot_to_fig(x_data=ty[range_idx], y_data=MY[range_idx]*V[range_idx], figure_handle=fig, marker_style='bv', marker_fill_color='none', data_label='FDS fluid $v$') +fdsplotlib.plot_to_fig(x_data=tz[range_idx], y_data=MZ[range_idx]*W[range_idx], figure_handle=fig, marker_style='b+', marker_fill_color='none', data_label='FDS fluid $w$') + +# Particle parameters +n = 1000 # number of particles +mpv = 10. # kg/m^3, mass_per_volume (from FDS input file) +v_xb = 1**3 # volume of XB region on init line in FDS input file +rho_p = 1000 # density of water, kg/m^3 +d_p = 1000e-6 # diameter, m +v_p = 4/3 * np.pi * (d_p/2)**3 # volume of a single droplet, m^3 +m_p = rho_p * v_p # mass of single droplet, kg +pwt = mpv * v_xb / (n * m_p) # particle weight factor + +# Read particle data from PRT5 files +STIME_X, XP_X, YP_X, ZP_X, QP_X = read_prt5(outdir + 'fluid_part_mom_x_1.prt5', 'real*4') +STIME_Y, XP_Y, YP_Y, ZP_Y, QP_Y = read_prt5(outdir + 'fluid_part_mom_y_1.prt5', 'real*4') +STIME_Z, XP_Z, YP_Z, ZP_Z, QP_Z = read_prt5(outdir + 'fluid_part_mom_z_1.prt5', 'real*4') + +# Calculate particle momentum +P_X = np.zeros(len(STIME_X)) +for i in range(len(STIME_X)): + for j in range(n): + P_X[i] = P_X[i] + pwt * m_p * QP_X[i, j, 0, 0] # momentum of particle at time STIME(i) + +P_Y = np.zeros(len(STIME_Y)) +for i in range(len(STIME_Y)): + for j in range(n): + P_Y[i] = P_Y[i] + pwt * m_p * QP_Y[i, j, 0, 0] + +P_Z = np.zeros(len(STIME_Z)) +for i in range(len(STIME_Z)): + for j in range(n): + P_Z[i] = P_Z[i] + pwt * m_p * QP_Z[i, j, 0, 0] + +# Create range for particle plotting +range_p = np.arange(0, min([len(STIME_X), len(STIME_Y), len(STIME_Z)]), 10) + +# Plot particle momentum +fdsplotlib.plot_to_fig(x_data=STIME_X[range_p], y_data=P_X[range_p], figure_handle=fig, marker_style='ro', marker_fill_color='none', data_label=r'FDS particle $u_\mathrm{p}$') +fdsplotlib.plot_to_fig(x_data=STIME_Y[range_p], y_data=P_Y[range_p], figure_handle=fig, marker_style='rv', marker_fill_color='none', data_label=r'FDS particle $v_\mathrm{p}$') +fdsplotlib.plot_to_fig(x_data=STIME_Z[range_p], y_data=P_Z[range_p], figure_handle=fig, marker_style='r+', marker_fill_color='none', data_label=r'FDS particle $w_\mathrm{p}$') + +# Calculate total momentum +P_total_X = P_X + (MX * U) # total momentum +P_total_Y = P_Y + (MY * V) +P_total_Z = P_Z + (MZ * W) + +# Plot total momentum +fdsplotlib.plot_to_fig(x_data=STIME_X[range_p], y_data=P_total_X[range_p], figure_handle=fig, marker_style='go', marker_fill_color='none', data_label=r'FDS total $U$') +fdsplotlib.plot_to_fig(x_data=STIME_Y[range_p], y_data=P_total_Y[range_p], figure_handle=fig, marker_style='gv', marker_fill_color='none', data_label=r'FDS total $V$') +fdsplotlib.plot_to_fig(x_data=STIME_Z[range_p], y_data=P_total_Z[range_p], figure_handle=fig, marker_style='g+', marker_fill_color='none', data_label=r'FDS total $W$') + +# analytical solution +rho = 1.1992661 # fluid density +Cd = 1 # drag coefficient +A_p = np.pi * (d_p/2)**2 # particle area + +u_p = QP_Z[0, 0, 0, 0] # initial velocity +U_p = U[0] + +M_p = MX[0] / (n * pwt) +alpha = M_p / m_p + +# Initialize solution arrays +u_soln = [] +U_soln = [] +t_soln = [] + +for i in range(len(tx) - 1): + u_soln.append(u_p) + U_soln.append(U_p) + t_soln.append(tx[i]) + + dt = tx[i + 1] - tx[i] + + u0 = u_p + U0 = U_p + + beta = 0.5 * rho * Cd * A_p * (1/m_p + 1/M_p) * abs(u0 - U0) + u_p = u0 / (1 + beta * dt) + (u0 + alpha * U0) / (1 + alpha) * (beta * dt) / (1 + beta * dt) + U_p = U0 + n * pwt * m_p / MX[0] * (u0 - u_p) + +# Convert lists to arrays +u_soln = np.array(u_soln) +U_soln = np.array(U_soln) +t_soln = np.array(t_soln) + +# Plot analytical solutions +fdsplotlib.plot_to_fig(x_data=t_soln, y_data=MX[0]*U_soln, figure_handle=fig, marker_style='b-', data_label='Analytical fluid') +fdsplotlib.plot_to_fig(x_data=t_soln, y_data=n*pwt*m_p*u_soln, figure_handle=fig, marker_style='r-', data_label='Analytical particle') + +plt.savefig(pltdir + 'fluid_part_momentum.pdf', format='pdf') +plt.close() + + +# plot velocities + +fig = fdsplotlib.plot_to_fig(x_data=[-1,-1], y_data=[-1,-1], + x_min=0, x_max=1, y_min=0, y_max=10, + revision_label=version_string, + figure_size=(plot_style['Paper_Width']+0.4,plot_style['Paper_Height']), + legend_location='outside', + x_label='Time (s)', + y_label='Velocity (m/s)') + +# Plot fluid velocities +fdsplotlib.plot_to_fig(x_data=tx[range_idx], y_data=U[range_idx], figure_handle=fig, marker_style='bo', marker_fill_color='none', data_label='FDS fluid $u$') +fdsplotlib.plot_to_fig(x_data=ty[range_idx], y_data=V[range_idx], figure_handle=fig, marker_style='bv', marker_fill_color='none', data_label='FDS fluid $v$') +fdsplotlib.plot_to_fig(x_data=tz[range_idx], y_data=W[range_idx], figure_handle=fig, marker_style='b+', marker_fill_color='none', data_label='FDS fluid $w$') + +# Calculate particle velocities +U_p = P_X / (n * pwt * m_p) +V_p = P_Y / (n * pwt * m_p) +W_p = P_Z / (n * pwt * m_p) + +# Plot particle velocities +fdsplotlib.plot_to_fig(x_data=tx[range_idx], y_data=U_p[range_idx], figure_handle=fig, marker_style='ro', marker_fill_color='none', data_label=r'FDS particle $u_\mathrm{p}$') +fdsplotlib.plot_to_fig(x_data=ty[range_idx], y_data=V_p[range_idx], figure_handle=fig, marker_style='rv', marker_fill_color='none', data_label=r'FDS particle $v_\mathrm{p}$') +fdsplotlib.plot_to_fig(x_data=tz[range_idx], y_data=W_p[range_idx], figure_handle=fig, marker_style='r+', marker_fill_color='none', data_label=r'FDS particle $w_\mathrm{p}$') + +# Calculate equilibrium velocities +U_eq = P_total_X / (MX[0] + n * pwt * m_p) +V_eq = P_total_Y / (MY[0] + n * pwt * m_p) +W_eq = P_total_Z / (MZ[0] + n * pwt * m_p) + +# Plot equilibrium velocities +fdsplotlib.plot_to_fig(x_data=tx, y_data=U_eq, figure_handle=fig, marker_style='g--', data_label='Equilibrium Velocity') +fdsplotlib.plot_to_fig(x_data=ty, y_data=V_eq, figure_handle=fig, marker_style='g--') +fdsplotlib.plot_to_fig(x_data=tz, y_data=W_eq, figure_handle=fig, marker_style='g--') + +# Save figure +plt.savefig(pltdir + 'fluid_part_velocity.pdf', format='pdf') +plt.close() + + +# Particle Drag Profile (formerly part_drag_profile.m) + +r_p = 0.001 # radius, m +l_p = 0.02 # length, m +v_p = np.pi*(r_p)**2*l_p # volume of a single particle, m^3 +shape_factor = 0.25 # assumes random orientation of cylinders +a_p = shape_factor*l_p*(2*np.pi*r_p) # projected area, m^2 + +z = np.linspace(0, 10, 20) +u_z = z +c_d = 2.8 # from FDS input file (specified) +rho_g = 1.195 # from FDS out file +f_x = c_d * a_p * 0.5*rho_g*(u_z**2) # drag experienced by a single particle + +fig = fdsplotlib.plot_to_fig(x_data=z, y_data=-f_x, line_style='k-', data_label='exact', + x_min=0, x_max=10, y_min=-0.01, y_max=0, + revision_label=version_string, + x_label='Position (m)', y_label='Drag Force (N)') + +ddir = '../../Verification/WUI/' +chid = ['part_drag_prof_ux', 'part_drag_prof_uy', 'part_drag_prof_uz', + 'part_drag_prof_vx', 'part_drag_prof_vy', 'part_drag_prof_vz', + 'part_drag_prof_wx', 'part_drag_prof_wy', 'part_drag_prof_wz'] +j = [1, 2, 3, 1, 2, 3, 1, 2, 3] # coordinate direction (x=1, y=2, z=3) + +for i in range(len(chid)): + + STIME, XP, YP, ZP, QP = read_prt5(ddir + chid[i] + '_1.prt5', 'real*4') + + if j[i] == 1: + fdsplotlib.plot_to_fig(x_data=XP[-1, :], y_data=QP[-1, :, 0, 0]/QP[-1, :, 0, 1], figure_handle=fig, marker_style='bo', data_label='FDS part') + v = np.abs(c_d * a_p * 0.5*rho_g*(XP[-1, :]**2) - QP[-1, :, 0, 0]/QP[-1, :, 0, 1]) + elif j[i] == 2: + fdsplotlib.plot_to_fig(x_data=YP[-1, :], y_data=QP[-1, :, 0, 0]/QP[-1, :, 0, 1], figure_handle=fig, marker_style='ro', data_label='FDS part') + v = np.abs(c_d * a_p * 0.5*rho_g*(YP[-1, :]**2) - QP[-1, :, 0, 0]/QP[-1, :, 0, 1]) + elif j[i] == 3: + fdsplotlib.plot_to_fig(x_data=ZP[-1, :], y_data=QP[-1, :, 0, 0]/QP[-1, :, 0, 1], figure_handle=fig, marker_style='go', data_label='FDS part') + v = np.abs(c_d * a_p * 0.5*rho_g*(ZP[-1, :]**2) - QP[-1, :, 0, 0]/QP[-1, :, 0, 1]) + + err = np.linalg.norm(v)/len(v) + #if err > 1e-4: + # print('Error: Case ' + ddir + chid[i] + ' error = ' + str(err)) + +plt.savefig(pltdir + 'part_drag_profile.pdf', format='pdf') +plt.close() + diff --git a/Utilities/Python/scripts/fm_data_center.py b/Utilities/Python/scripts/fm_data_center.py deleted file mode 100644 index 2c70289fda6..00000000000 --- a/Utilities/Python/scripts/fm_data_center.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python -""" -fm_data_center.py -Jason Floyd -""" - -# Generate FDS summary data for scatterplots - -import pandas as pd -import numpy as np -import fdsplotlib -import os - -outdir = '../../../out/FM_FPRF_Datacenter/' -expdir = '../../../exp/FM_FPRF_Datacenter/' - -# Experimental data -exp_data = pd.read_csv(os.path.join(expdir, 'fm_exp.csv'), skiprows=1, header=None).values.flatten() - -# --- Low flow test --- -fds_data = pd.read_csv(os.path.join(outdir, 'FM_Datacenter_Veltest_Low_devc.csv'), - skiprows=13, header=None).values -n_fds_data = fds_data.shape[0] - -# compute average pressures -fds_avg = [] -for i in range(1, 7): # MATLAB 2:7 → Python 1:7 - fds_avg.append(np.mean(fds_data[:, i])) - -fds_header = ['Time', 'Low SF-CA', 'Low HA-CP', 'High SF-CA', 'High HA-CP'] - -fds_out = np.zeros(23) # preallocate (we fill later) -fds_out[0] = 100 -fds_out[1] = fds_avg[0] - fds_avg[1] -fds_out[2] = fds_avg[4] - fds_avg[5] - -# --- High flow test --- -fds_data = pd.read_csv(os.path.join(outdir, 'FM_Datacenter_Veltest_High_devc.csv'), - skiprows=13, header=None).values -for i in range(1, 7): - fds_avg[i - 1] = np.mean(fds_data[:, i]) - -fds_out[3] = fds_avg[0] - fds_avg[1] -fds_out[4] = fds_avg[4] - fds_avg[5] - -# Write the first 5 outputs -with open(os.path.join(outdir, 'FM_Datacenter_fds_data.csv'), 'w') as fid: - fid.write(', '.join(fds_header) + '\n') - fid.write('{:.0f}, {:.3f}, {:.3f}, {:.3f}, {:.3f}\n'.format(*fds_out[0:5])) - -# --- get soot values --- -def mean_soot(filename, skiprows, cols): - data = pd.read_csv(os.path.join(outdir, filename), skiprows=skiprows, header=None).values - return [np.mean(data[:, c - 1]) * 1_000_000 for c in cols] # MATLAB is 1-based - -cols = [28, 46, 65] -fds_out[5:8] = mean_soot('FM_Datacenter_Low_C3H6_SF_devc.csv', 15, cols) -fds_out[8:11] = mean_soot('FM_Datacenter_High_C3H6_SF_devc.csv', 15, cols) -fds_out[11:14] = mean_soot('FM_Datacenter_Low_C3H6_HA_devc.csv', 15, cols) -fds_out[14:17] = mean_soot('FM_Datacenter_High_C3H6_HA_devc.csv', 15, cols) -fds_out[17:20] = mean_soot('FM_Datacenter_Low_Cable_SF_devc.csv', 13, cols) -fds_out[20:23] = mean_soot('FM_Datacenter_High_Cable_SF_devc.csv', 13, cols) - -# --- plotting --- -x = np.array([0.01, 0.122, 0.2, 0.3, 0.5, 1, 5, 10, 50, 100, 500, 1000]) -logx = np.minimum(np.maximum(-2.7, np.log(x + 0.00001)), 1) -errx = 0.01 * (3.8184 * logx ** 2 - 7.7783 * logx + 14.346) -toterr = np.sqrt(errx ** 2 + 0.1 ** 2 + 0.1 ** 2 + 0.05 ** 2) -xerrp = x + 2 * toterr * x -xerrm = np.maximum(0.00001, x - 2 * toterr * x) - -fig = fdsplotlib.plot_to_fig(x,x, - plot_type='loglog', - marker_style='k-', - x_min=0.01, x_max=300, y_min=0.01, y_max=300, - x_label='Measured Soot Concentration (mg/m$^3$)', - y_label='Predicted Soot Concentration (mg/m$^3$)', - legend_location='lower right') - -fdsplotlib.plot_to_fig(x, xerrp, figure_handle=fig, marker_style='k--') -fdsplotlib.plot_to_fig(x, xerrm, figure_handle=fig, marker_style='k--') -fdsplotlib.plot_to_fig(exp_data[5:8], fds_out[5:8], figure_handle=fig, marker_style='ro', data_label='C3H6 Low SF') -fdsplotlib.plot_to_fig(exp_data[8:11], fds_out[8:11], figure_handle=fig, marker_style='r+', data_label='C3H6 High SF') -fdsplotlib.plot_to_fig(exp_data[11:14], fds_out[11:14], figure_handle=fig, marker_style='bo', data_label='C3H6 Low HA') -fdsplotlib.plot_to_fig(exp_data[14:17], fds_out[14:17], figure_handle=fig, marker_style='b+', data_label='C3H6 High HA') -fdsplotlib.plot_to_fig(exp_data[17:20], fds_out[17:20], figure_handle=fig, marker_style='go', data_label='Cable Low SF') -fdsplotlib.plot_to_fig(exp_data[20:23], fds_out[20:23], figure_handle=fig, marker_style='g+', data_label='Cable High SF') - -fig.savefig('../../Manuals/FDS_Validation_Guide/SCRIPT_FIGURES/FM_FPRF_Datacenter/FM_Datacenter_Soot.pdf') - -# --- write pressure.tex --- -filename = '../../Manuals/FDS_Validation_Guide/SCRIPT_FIGURES/FM_FPRF_Datacenter/pressure.tex' -with open(filename, 'w') as fid: - pres_dump = np.zeros(12) - pres_dump[0] = fds_out[1] - pres_dump[1] = exp_data[1] - pres_dump[2] = exp_data[1] * .19 - pres_dump[3] = fds_out[2] - pres_dump[4] = exp_data[2] - pres_dump[5] = exp_data[2] * .19 - pres_dump[6] = fds_out[3] - pres_dump[7] = exp_data[3] - pres_dump[8] = exp_data[3] * .1 - pres_dump[9] = fds_out[4] - pres_dump[10] = exp_data[4] - pres_dump[11] = exp_data[4] * .1 - - fid.write('\\begin{center}\n') - fid.write('\\begin{tabular}{|c|c|c|c|c|} \\hline\n') - fid.write('Fan Speed & FDS SF to CA & Exp SF to CA & FDS HA to CP & Exp HA to CP \\\\\n') - fid.write(' & (Pa) & (Pa) & (Pa) & (Pa) \\\\ \\hline\\hline\n') - fid.write('78 ACH & {:5.1f} & {:5.1f} $\\pm$ {:5.1f} & {:5.1f} & {:5.1f} $\\pm$ {:5.1f} \\\\\n'.format(*pres_dump[0:6])) - fid.write('265 ACH & {:5.1f} & {:5.1f} $\\pm$ {:5.1f} & {:5.1f} & {:5.1f} $\\pm$ {:5.1f} \\\\\n'.format(*pres_dump[6:12])) - fid.write('\\hline\n') - fid.write('\\end{tabular}\n') - fid.write('\\end{center}\n') - diff --git a/Utilities/Python/scripts/hot_layer_collapse.py b/Utilities/Python/scripts/hot_layer_collapse.py new file mode 100644 index 00000000000..586bcdaae3c --- /dev/null +++ b/Utilities/Python/scripts/hot_layer_collapse.py @@ -0,0 +1,316 @@ +# McDermott +# 10-7-14 +# hot_layer_collapse.m +# +# H. Baum. "Collapse of a Hot Layer in a Micro-Gravity Environment", Sep 2, 2014 (personal notes) +# +# Converted by Floyd +# 10/16/2025 + +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +import os +import fdsplotlib +from scipy.special import erfc, erfinv + +# --- Configuration (Approximation of MATLAB external variables) --- +datadir = '../../Verification/Flowfields/' +plotdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/' +filename = 'hot_layer_360_devc.csv' +git_file = datadir+ 'hot_layer_360_git.txt' + +skip_case = False + +name = datadir+filename +if not os.path.exists(name): + skip_case = True + print('Error: File ', filename, ' does not exist. Skipping case.') + +if skip_case: quit() + +error_tolerance = 0.01 + +L = 2.0 # height of domain 2*d where d is the layer depth at t=0 +N = 360 # number of cells in vertical direction +T_0 = 293.15 # cold wall temperature (K) +T_h = 1172.6 # hot layer initial temperature (K) +k_0 = 1.0 # W/m/K +rho_0 = 1.0 # kg/m^3 +Cp = 1000.0 # J/kg/K +d = 1.0 # m +v0 = k_0 / (rho_0 * Cp * d) # m/s + +dz = L / N + +t = np.array([.2, .4, .6, .8, 1, 2, 4, 6, 8, 10]) +tau = t * 1e-3 +marker_style = ['ko', 'mo', 'ro', 'go', 'bo'] +exact_soln_style = ['k-', 'm-', 'r-', 'g-', 'b-'] +legend_entries = [r'$\tau = 2 \times 10^{-4}$', r'$\tau = 4 \times 10^{-4}$', r'$\tau = 6 \times 10^{-4}$', r'$\tau = 8 \times 10^{-4}$', r'$\tau = 10 \times 10^{-4}$'] +legend_entries_2 = [r'$\tau = 2 \times 10^{-3}$', r'$\tau = 4 \times 10^{-3}$', r'$\tau = 6 \times 10^{-3}$', r'$\tau = 8 \times 10^{-3}$', r'$\tau = 10 \times 10^{-3}$'] + +def f(lambda_in, tau_in, a_in): + term1 = -2 * np.sqrt(tau_in / np.pi) * np.exp(-(a_in - lambda_in)**2 / (4 * tau_in)) + term2 = (a_in + lambda_in) * erfc((a_in + lambda_in) / (2 * np.sqrt(tau_in))) + return term1 + term2 + +def F(lambda_in, tau_in, a_in): + return f(lambda_in, tau_in, a_in) - f(0, tau_in, a_in) + +def U(lambda_in, tau_in, T_h_in, T_0_in): + arg1 = lambda_in / (2 * np.sqrt(tau_in)) + arg2 = (lambda_in - T_0_in / T_h_in) / (2 * np.sqrt(tau_in)) + arg3 = (lambda_in + T_0_in / T_h_in) / (2 * np.sqrt(tau_in)) + + return -erfc(arg1) + 0.5 * (erfc(arg2) + erfc(arg3)) + +def Theta(lambda_in, tau_in, T_h_in, T_0_in): + return 1.0 + ((T_h_in - T_0_in) / T_0_in) * U(lambda_in, tau_in, T_h_in, T_0_in) + +def G(lambda_in, tau_in, a_in): + term1 = -np.exp(-(a_in + lambda_in)**2 / (4 * tau_in)) + term2 = np.exp(-a_in**2 / (4 * tau_in)) + return (1 / np.sqrt(np.pi * tau_in)) * (term1 + term2) + +def V(lambda_in, tau_in, T_h_in, T_0_in): + term1 = -G(lambda_in, tau_in, 0) + term2 = 0.5 * (G(lambda_in, tau_in, T_0_in / T_h_in) + G(lambda_in, tau_in, -T_0_in / T_h_in)) + return ((T_h_in - T_0_in) / T_0_in) * (term1 + term2) + +def Y(lambda_in, tau_in, T_h_in, T_0_in): + term1 = -F(lambda_in, tau_in, 0) + term2 = 0.5 * (F(lambda_in, tau_in, T_0_in / T_h_in) + F(lambda_in, tau_in, -T_0_in / T_h_in)) + return lambda_in + ((T_h_in - T_0_in) / T_0_in) * (term1 + term2) + + +lambda_range = np.linspace(0, 10 * T_0 / T_h, 1000) + +df = pd.read_csv(datadir+filename, skiprows=2, header=None) + +# Find row indices 'J' corresponding to times 't' +J = [] +for time_t in t: + try: + index_j = df[df[0] >= time_t].index[0] + J.append(index_j) + except IndexError: + print(f"Warning: Time {time_t} not found in data. Stopping.") + break +if not J: + exit() + +T_range_indices = slice(1, 41) +W_range_indices = slice(41, 81) + +dz_40 = L / 40.0 +dz_360 = L / 360.0 +z_T = np.arange(dz_40 / 2, L, dz_40) +z_W = np.arange(dz_40 / 2 + dz_360 / 2, L, dz_40) + +if len(z_T) > 40: + z_T = z_T[:40] +if len(z_W) > 40: + z_W = z_W[:40] + +version_string = fdsplotlib.get_version_string(git_file) + +for j in range(5): # j=0 to 4 (corresponding to tau[0] to tau[4]) + T_C = df.iloc[J[j], T_range_indices].values + T_nondim = (T_C + 273.15) / T_0 + + if j==0: + fig = fdsplotlib.plot_to_fig(x_data=T_nondim, y_data=z_T, marker_style=marker_style[j], + revision_label=version_string,x_min=1,x_max=4,y_min=0,y_max=1.2, + data_label=legend_entries[j], + legend_location='center left', + y_label=r'$T/T_0$', + x_label=r'$y/d$') + else: + fdsplotlib.plot_to_fig(x_data=T_nondim, y_data=z_T, marker_style=marker_style[j], + figure_handle=fig, + data_label=legend_entries[j],) + + fdsplotlib.plot_to_fig(x_data=Theta(lambda_range, tau[j], T_h, T_0), y_data= Y(lambda_range, tau[j], T_h, T_0), marker_style=exact_soln_style[j], + figure_handle=fig) + +plotfile = plotdir + 'hot_layer_temp_1.pdf' +plt.savefig(plotfile, format='pdf') +plt.close() + +# --- Compute Temperature Error at tau[4] (j=5 in MATLAB, index 4 in Python) --- +j_err = 4 +T_C_err = df.iloc[J[j_err], T_range_indices].values +T_nondim_err = (T_C_err + 273.15) / T_0 + +# map nondimensional position: Find index 'I' where Y >= z_T +I = [] +Y_analytic = Y(lambda_range, tau[j_err], T_h, T_0) +for z_val in z_T: + # Find the first index in lambda_ where Y_analytic >= z_val + try: + I.append(np.where(Y_analytic >= z_val)[0][0]) + except IndexError: + print(f"Warning: Analytical Y does not cover z_T={z_val}") + I.append(I[-1] if I else 0) + +# Ensure I has the same length as z_T +I = np.array(I[:len(z_T)]) + +T_analytic_at_FDS_pos = Theta(lambda_range[I], tau[j_err], T_h, T_0) + +Error_T1 = np.linalg.norm(T_nondim_err - T_analytic_at_FDS_pos) / (np.max(T_nondim_err) * len(T_nondim_err)) + +if Error_T1 > error_tolerance: + print(f"Python Warning: hot_layer_360.fds Temp_1 Error = {Error_T1:.4e}") + +# --- Plot 2: Velocity v/v_0 (Short Times) --- +fig2, ax2 = plt.subplots() + +for j in range(5): + # Extract FDS Velocity, convert to v/v_0: W / v0 + W = df.iloc[J[j], W_range_indices].values + W_nondim = W / v0 + + if j==0: + fig = fdsplotlib.plot_to_fig(x_data=W_nondim, y_data=z_W, marker_style=marker_style[j], + revision_label=version_string,x_min=-200,x_max=0,y_min=0,y_max=1.2, + data_label=legend_entries[j], + y_label=r'$v/v_0$', + x_label=r'$y/d$') + else: + fdsplotlib.plot_to_fig(x_data=W_nondim, y_data=z_W, marker_style=marker_style[j], + figure_handle=fig, + data_label=legend_entries[j],) + + fdsplotlib.plot_to_fig(x_data=V(lambda_range, tau[j], T_h, T_0), y_data= Y(lambda_range, tau[j], T_h, T_0), marker_style=exact_soln_style[j], + figure_handle=fig) + +plotfile = plotdir + 'hot_layer_vel_1.pdf' +plt.savefig(plotfile, format='pdf') +plt.close() + +# --- Compute Velocity Error at tau[4] (j=5) --- +j_err = 4 +W_err = df.iloc[J[j_err], W_range_indices].values +W_nondim_err = W_err / v0 + +# map nondimensional position: Find index 'I' where Y >= z_W +I = [] +Y_analytic = Y(lambda_range, tau[j_err], T_h, T_0) +for z_val in z_W: + try: + I.append(np.where(Y_analytic >= z_val)[0][0]) + except IndexError: + I.append(I[-1] if I else 0) + +I = np.array(I[:len(z_W)]) + +V_analytic_at_FDS_pos = V(lambda_range[I], tau[j_err], T_h, T_0) + +Error_V1 = np.linalg.norm(W_nondim_err - V_analytic_at_FDS_pos) / (np.max(np.abs(W_nondim_err)) * len(W_nondim_err)) + +if Error_V1 > error_tolerance: + print(f"Python Warning: hot_layer_360.fds Vel_1 Error = {Error_V1:.4e}") + +# ---------------------------------------------------------------------- +# --- Second set of Plots (Longer Times: tau[5] to tau[9]) --- +# ---------------------------------------------------------------------- + +# --- Plot 3: Temperature T/T_0 (Longer Times) --- +fig3, ax3 = plt.subplots() + +for j in range(5, 10): # j=5 to 9 (corresponding to tau[5] to tau[9]) + jj = j - 5 # new index for markers/legend (0 to 4) + + T_C = df.iloc[J[j], T_range_indices].values + T_nondim = (T_C + 273.15) / T_0 + + if j==5: + fig = fdsplotlib.plot_to_fig(x_data=T_nondim, y_data=z_T, marker_style=marker_style[jj], + revision_label=version_string,x_min=1,x_max=4,y_min=0,y_max=1.2, + data_label=legend_entries[jj], + y_label=r'$T/T_0$', + x_label=r'$y/d$') + else: + fdsplotlib.plot_to_fig(x_data=T_nondim, y_data=z_T, marker_style=marker_style[jj], + figure_handle=fig, + data_label=legend_entries[jj],) + + fdsplotlib.plot_to_fig(x_data=Theta(lambda_range, tau[j], T_h, T_0), y_data= Y(lambda_range, tau[j], T_h, T_0), marker_style=exact_soln_style[jj], + figure_handle=fig) + +plotfile = plotdir + 'hot_layer_temp_2.pdf' +plt.savefig(plotfile, format='pdf') +plt.close() + +# --- Compute Temperature Error at tau[9] (j=10) --- +j_err = 9 +T_C_err = df.iloc[J[j_err], T_range_indices].values +T_nondim_err = (T_C_err + 273.15) / T_0 + +# map nondimensional position +I = [] +Y_analytic = Y(lambda_range, tau[j_err], T_h, T_0) +for z_val in z_T: + try: + I.append(np.where(Y_analytic >= z_val)[0][0]) + except IndexError: + I.append(I[-1] if I else 0) + +I = np.array(I[:len(z_T)]) + +T_analytic_at_FDS_pos = Theta(lambda_range[I], tau[j_err], T_h, T_0) +Error_T2 = np.linalg.norm(T_nondim_err - T_analytic_at_FDS_pos) / (np.max(T_nondim_err) * len(T_nondim_err)) + +if Error_T2 > error_tolerance: + print(f"Python Warning: hot_layer_360.fds Temp_2 Error = {Error_T2:.4e}") + +# --- Plot 4: Velocity v/v_0 (Longer Times) --- +fig4, ax4 = plt.subplots() + +for j in range(5, 10): + jj = j - 5 + + W = df.iloc[J[j], W_range_indices].values + W_nondim = W / v0 + + if j==5: + fig = fdsplotlib.plot_to_fig(x_data=W_nondim, y_data=z_W, marker_style=marker_style[jj], + revision_label=version_string,x_min=-60,x_max=0,y_min=0,y_max=1.6, + data_label=legend_entries[jj], + y_label=r'$v/v_0$', + x_label=r'$y/d$') + else: + fdsplotlib.plot_to_fig(x_data=W_nondim, y_data=z_W, marker_style=marker_style[jj], + figure_handle=fig, + data_label=legend_entries[jj],) + + fdsplotlib.plot_to_fig(x_data=V(lambda_range, tau[j], T_h, T_0), y_data= Y(lambda_range, tau[j], T_h, T_0), marker_style=exact_soln_style[jj], + figure_handle=fig) + +plotfile = plotdir + 'hot_layer_vel_2.pdf' +plt.savefig(plotfile, format='pdf') +plt.close() + +# --- Compute Velocity Error at tau[9] (j=10) --- +j_err = 9 +W_err = df.iloc[J[j_err], W_range_indices].values +W_nondim_err = W_err / v0 + +# map nondimensional position +I = [] +Y_analytic = Y(lambda_range, tau[j_err], T_h, T_0) +for z_val in z_W: + try: + I.append(np.where(Y_analytic >= z_val)[0][0]) + except IndexError: + I.append(I[-1] if I else 0) + +I = np.array(I[:len(z_W)]) + +V_analytic_at_FDS_pos = V(lambda_range[I], tau[j_err], T_h, T_0) +Error_V2 = np.linalg.norm(W_nondim_err - V_analytic_at_FDS_pos) / (np.max(np.abs(W_nondim_err)) * len(W_nondim_err)) + +if Error_V2 > error_tolerance: + print(f"Python Warning: hot_layer_360.fds Vel_2 Error = {Error_V2:.4e}") \ No newline at end of file diff --git a/Utilities/Python/scripts/ht3d_sphere.py b/Utilities/Python/scripts/ht3d_sphere.py new file mode 100644 index 00000000000..d34a1114aab --- /dev/null +++ b/Utilities/Python/scripts/ht3d_sphere.py @@ -0,0 +1,133 @@ + +# Heat transfer within a sphere +# The solution is from Carslaw and Jaeger, Sec. 9.8, p. 243, Eq. (6) +# The notation adopted here follows C. Lautenberger, IAFSS, 2014. + +import numpy as np +import matplotlib.pyplot as plt +import pandas as pd +import os +import sys +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +outdir = '../../Verification/Heat_Transfer/' +pltdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/' + +git_file = outdir + 'ht3d_sphere_48_git.txt' +version_string = fdsplotlib.get_version_string(git_file) + + +# analytical solution + +k = 1.0 # W/m/k +rho = 1000 # kg/m3 +cp = 1000 # J/kg/K +g0 = 2e5 # W/m3 +alpha = k/(rho*cp) # m2/s + +a1 = 0.1 # m (this should match the last cell face in ht3d_sphere_96.fds) +a2 = 0.1 # m (this should match the last cell face in ht3d_sphere_48.fds) +a3 = 0.1 # m (this should match the last cell face in ht3d_sphere_24.fds) + +n1 = 41 +n2 = 21 +n3 = 11 +r1 = np.linspace(0.00001, 0.1, n1) # this should match line DEVC in ht3d_sphere_96.fds +r2 = np.linspace(0.00001, 0.1, n2) # this should match line DEVC in ht3d_sphere_48.fds +r3 = np.linspace(0.00001, 0.1, n3) # this should match line DEVC in ht3d_sphere_24.fds + +t = [10, 20, 60, 120, 180] # seconds +markers = ['bo','go','ro','co','mo'] + +fig = fdsplotlib.plot_to_fig(x_data=[-1,-1], y_data=[-1,-1], + x_min=0, x_max=0.105, y_min=20, y_max=60, + revision_label=version_string, + x_label='Radial Distance (m)', + y_label=r'Temperature ($^\circ$C)') + +for m in range(len(t)): + + DT1 = np.zeros(len(r1)) + for ii in range(len(r1)): + sum_term = 0 + for n in range(1, n1+1): + sum_term = sum_term + (-1)**n/n**3 * np.sin(n*np.pi*r1[ii]/a1) * np.exp(-alpha*t[m]*(n*np.pi/a1)**2) + DT1[ii] = 20 + g0/(6*k) * (a1**2 - r1[ii]**2) + 2*g0*a1**3/(k*np.pi**3*r1[ii]) * sum_term + + DT2 = np.zeros(len(r2)) + for jj in range(len(r2)): + sum_term = 0 + for n in range(1, n2+1): + sum_term = sum_term + (-1)**n/n**3 * np.sin(n*np.pi*r2[jj]/a2) * np.exp(-alpha*t[m]*(n*np.pi/a2)**2) + DT2[jj] = 20 + g0/(6*k) * (a2**2 - r2[jj]**2) + 2*g0*a2**3/(k*np.pi**3*r2[jj]) * sum_term + + if m==0: + fdsplotlib.plot_to_fig(x_data=r2, y_data=DT2, figure_handle=fig, marker_style=markers[m], data_label='Exact') + else: + fdsplotlib.plot_to_fig(x_data=r2, y_data=DT2, figure_handle=fig, marker_style=markers[m]) + + DT3 = np.zeros(len(r3)) + for kk in range(len(r3)): + sum_term = 0 + for n in range(1, n3+1): + sum_term = sum_term + (-1)**n/n**3 * np.sin(n*np.pi*r3[kk]/a3) * np.exp(-alpha*t[m]*(n*np.pi/a3)**2) + DT3[kk] = 20 + g0/(6*k) * (a3**2 - r3[kk]**2) + 2*g0*a3**3/(k*np.pi**3*r3[kk]) * sum_term + +# gather FDS results + +fnt = ['ht3d_sphere_48'] +fileName = ['ht3d_sphere_24', 'ht3d_sphere_48', 'ht3d_sphere_96'] +nc_array = np.array([25, 50, 100]) +dx_array = 0.25 / nc_array + +M = pd.read_csv(outdir + fnt[0] + '_prof_1.csv', sep=',', skiprows=3, header=None) +T_fds1 = M.iloc[ 1, 63:].values +T_fds2 = M.iloc[ 2, 63:].values +T_fds3 = M.iloc[ 6, 63:].values +T_fds4 = M.iloc[12, 63:].values +T_fds5 = M.iloc[-1, 63:].values +fdsplotlib.plot_to_fig(x_data=r2, y_data=T_fds1, figure_handle=fig, marker_style='b--', data_label='FDS $t=10$ s') +fdsplotlib.plot_to_fig(x_data=r2, y_data=T_fds2, figure_handle=fig, marker_style='g--', data_label='FDS $t=20$ s') +fdsplotlib.plot_to_fig(x_data=r2, y_data=T_fds3, figure_handle=fig, marker_style='r--', data_label='FDS $t=60$ s') +fdsplotlib.plot_to_fig(x_data=r2, y_data=T_fds4, figure_handle=fig, marker_style='c--', data_label='FDS $t=120$ s') +fdsplotlib.plot_to_fig(x_data=r2, y_data=T_fds5, figure_handle=fig, marker_style='m--', data_label='FDS $t=180$ s') + +ERROR = abs(M.iloc[-1, 63] - DT2[1]) / (DT2[1] - 20) +if ERROR > 0.01: + print(f'ERROR: ht3d_sphere cases out of tolerance. ERROR = {ERROR}') + +plt.savefig(pltdir + 'ht3d_sphere_profile.pdf', format='pdf') +plt.close() + +# estimating L1 & L2 norm errors + +Linfe = [] # initialize L1 norm error vector +dxx = [] # init dxx vector +DT = [DT3[-1], DT2[-1], DT1[-1]] +r = [r3[-1], r2[-1], r1[-1]] + +for i in range(len(fileName)): + M1 = pd.read_csv(outdir + fileName[i] + '_prof_1.csv', sep=',', skiprows=3, header=0) + T_fds = M1.iloc[-1, -1] # FDS devices data (last row, last column) + T_fds1 = T_fds + Linfe.append(1/(1) * np.max(np.abs(DT[i] - T_fds1))) # populates Linf norm error vector, element-by-element + dxx.append(dx_array[i]) # populates dxx vector, element-by-element + +Linfe = np.array(Linfe) +dxx = np.array(dxx) + +fig = fdsplotlib.plot_to_fig(x_data=dxx, y_data=Linfe, marker_style='msq-', data_label='FDS', + x_min=2e-3, x_max=1e-2, y_min=5e-2, y_max=2, + plot_type='loglog', + revision_label=version_string, + x_label=r'$\delta x$ (m)', + y_label=r'$L_\infty$ Error ($^\circ$C)') + +fdsplotlib.plot_to_fig(x_data=dxx, y_data=1e2*dxx, marker_style='k--', data_label=r'$O(\delta x)$', figure_handle=fig) +fdsplotlib.plot_to_fig(x_data=dxx, y_data=1e4*dxx**2, marker_style='k-', data_label=r'$O(\delta x^2)$', figure_handle=fig) + +plt.savefig(pltdir + 'ht3d_sphere_convergence1.pdf', format='pdf') +plt.close() + diff --git a/Utilities/Python/scripts/hvac_mass_transport.py b/Utilities/Python/scripts/hvac_mass_transport.py new file mode 100644 index 00000000000..9bd355fb384 --- /dev/null +++ b/Utilities/Python/scripts/hvac_mass_transport.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 +# B M Ralph +# 12-8-2016 +# hvac_mass_transport.py +# +# Converted by Floyd +# 10-14-2025 +# +# Convergence study for HVAC transient mass transport (mass fraction at +# downstream duct node). + +import os +import numpy as np +import pandas as pd +import math +import matplotlib.pyplot as plt +import fdsplotlib + + +import os +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +datadir = '../../Verification/HVAC/' +plotdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/'; +filename = [ + 'HVAC_mass_transport_conv_0020_devc.csv', + 'HVAC_mass_transport_conv_0040_devc.csv', + 'HVAC_mass_transport_conv_0080_devc.csv', + 'HVAC_mass_transport_conv_0160_devc.csv', + 'HVAC_mass_transport_conv_0320_devc.csv' +] +PlotStyle = ['b-', 'g-', 'r-', 'm-', 'c-'] +nc_array = np.array([20, 40, 80, 160, 320]) +dx_array = np.array([1/20, 1/40, 1/80, 1/160, 1/320]) + +# Input parameters +t0 = 0.0 +t_end = 2.0 +u = 1.0 +L = 1.0 + +skip_case = False + +for i in range(len(filename)): + name = datadir+filename[i] + if not os.path.exists(name): + skip_case = True + print('Error: File ', filename[i], ' does not exist. Skipping case.') + +if skip_case: quit() + +# --- Analytical Solution --- + +# Analytical solution (using a lambda function which is similar to MATLAB's Anonymous Function) +# Y = t * (t <= 1) + 1 * (t > 1) +# Note: numpy arrays are required for element-wise comparison and multiplication + +# Create mass fraction plot and plot analytical solution +nt = 1000 +dt = t_end / nt +# Generate time vector similar to MATLAB's t0 : dt : t_end +tc = np.arange(t0, t_end + dt, dt) +Y =(lambda t: (t * (t <= 1) + 1.0 * (t > 1)).astype(float))(tc) + +L1e = [] # initialize L1 norm error vector +L2e = [] # initialize L2 norm error vector +dxx = [] # init dxx vector + +git_file = datadir+'HVAC_mass_transport_conv_0320_git.txt' +version_string = fdsplotlib.get_version_string(git_file) + +fig = fdsplotlib.plot_to_fig(x_data=tc, y_data=Y, marker_style='k--', + revision_label=version_string,x_min=0,x_max=2,y_min=0,y_max=1.2, + data_label = 'Exact Solution', + x_label='Time (s)', + y_label='Mass Fraction (kg/kg)') + +for i in range(len(filename)): + df = pd.read_csv(datadir+filename[i], skiprows=2) # The header is in row 1 (0-indexed) + + # Get column names (assuming standard FDS output of Time, Variable 1, Variable 2, ...) + # The MATLAB code uses M.data(1:end,1) for Time and M.data(1:end,2) for the species data. + t_fds = df.iloc[:, 0].values # Time (1st column, 0-indexed) + Y_fds = df.iloc[:, 1].values # FDS species data (2nd column, 1-indexed) + + # 3. Plot FDS results + fdsplotlib.plot_to_fig(x_data=t_fds, y_data=Y_fds, marker_style=PlotStyle[i], + figure_handle=fig, + data_label='FDS N_CELLS = '+str(nc_array[i])) + + # 4. Compute Error Norms (element-by-element appending) + + # Evaluate Analytical solution at FDS time points + Y_analytical_at_t_fds = (lambda t: (t * (t <= 1) + 1.0 * (t > 1)).astype(float))(t_fds) + + # L1 norm error: 1/nc * sum(|Y_analytical - Y_fds|) + L1_error = (1 / nc_array[i]) * np.sum(np.abs(Y_analytical_at_t_fds - Y_fds)) + L1e.append(L1_error) + + # L2 norm error: sqrt(1/nc * sum((Y_analytical - Y_fds)^2)) + L2_error = np.sqrt((1 / nc_array[i]) * np.sum((Y_analytical_at_t_fds - Y_fds)**2)) + L2e.append(L2_error) + +plotname = plotdir + 'HVAC_mass_transport_convergence_1.pdf' +plt.savefig(plotname, format='pdf') +plt.close() + +fig = fdsplotlib.plot_to_fig(x_data=dx_array, y_data=L1e, marker_style='ks-',plot_type='loglog', + revision_label=version_string,x_min=0.001,x_max=0.1,y_min=1E-4,y_max=0.1, + data_label = 'FDS', + x_label='$\\Delta x$ (m)', + y_label='L$_1$ error') + +fdsplotlib.plot_to_fig(x_data=dx_array, y_data=dx_array/10, marker_style='k--', +figure_handle=fig, +data_label='$O$($\\Delta x$)') + + +plotname = plotdir + 'HVAC_mass_transport_convergence_2.pdf' +plt.savefig(plotname, format='pdf') +plt.close() + +fig = fdsplotlib.plot_to_fig(x_data=dx_array, y_data=L2e, marker_style='ks-',plot_type='loglog', + revision_label=version_string,x_min=0.001,x_max=0.1,y_min=1E-4,y_max=0.1, + data_label = 'FDS', + x_label='$\\Delta x$ (m)', + y_label='L$_2$ error') + +fdsplotlib.plot_to_fig(x_data=dx_array, y_data=dx_array/10, marker_style='k--', +figure_handle=fig, +data_label='$O$($\\Delta x$)') + + +plotname = plotdir + 'HVAC_mass_transport_convergence_3.pdf' +plt.savefig(plotname, format='pdf') +plt.close() + diff --git a/Utilities/Python/scripts/impinging_jet.py b/Utilities/Python/scripts/impinging_jet.py new file mode 100644 index 00000000000..da5190282d4 --- /dev/null +++ b/Utilities/Python/scripts/impinging_jet.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +""" +impinging_jet.py +Converted from MATLAB script impinging_jet.m to Python. + +Generates: + - impinging_jet_correlation.pdf + - impinging_jet_local_Re_1e5.pdf + - impinging_jet_local_Re_4e5.pdf +""" + +import os +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style("fds") + +# ----------------------------- +# Paths and identifiers +# ----------------------------- +firemodels_dir = os.path.normpath(os.path.join(os.path.dirname(__file__),'..','..','..','..')) +fds_dir = os.path.normpath(os.path.join(os.path.dirname(__file__),'..','..','..')) +outdir = os.path.join(firemodels_dir, 'out','Convection','') +pltdir = os.path.join(fds_dir, 'Manuals','FDS_Verification_Guide','SCRIPT_FIGURES','') +os.makedirs(pltdir, exist_ok=True) + +chid = 'impinging_jet' + +# ----------------------------- +# Constants / inputs +# ----------------------------- +D_h = 0.2 # hydraulic diameter of the jet [m] +H = 1.0 # distance from jet to wall [m] +mu = 1.822e-05 # dynamic viscosity [kg/m/s] +k = 2.566e-02 # thermal conductivity [W/m/K] +Pr = 0.71 # Prandtl number [-] +T_j = 100.0 # temperature of jet exit [C] +T_w = 20.0 # constant plate temperature [C] +rho_a = 1.200 # ambient density [kg/m^3] +rho_j = rho_a * (T_w + 273.0) / (T_j + 273.0) # jet fluid density [kg/m^3] +nu = mu / rho_j # kinematic viscosity [m^2/s] +U_j = [10.0, 40.0] # jet exit velocities [m/s] corresponding to Re ~ 1e5 and 4e5 +A_r = 0.01 # D_h^2/(4 r^2), where r defines outer extent of the averaging region + +res_list = ['coarse', 'medium', 'fine'] +Re_str = ['1e5', '4e5'] + +# Relative error tolerance for Nu comparison +E_tol = 0.1 + +# Get git hash +git_file = os.path.join(outdir, 'impinging_jet_Re_1e5_coarse_git.txt') +version_string = fdsplotlib.get_version_string(git_file) + +# ----------------------------- +# Plot 1: Martin correlation vs Re and FDS points +# ----------------------------- +# Martin correlation coefficient G for given geometry +G = 2.0 * np.sqrt(A_r) * ((1 - 2.2*np.sqrt(A_r)) / (1 + 0.2*(H/D_h - 6)*np.sqrt(A_r))) + +RE = np.linspace(2e3, 5e5, 1000) +NU = G * 2*np.sqrt(RE) * np.sqrt(1 + 0.005*RE**0.55) * (Pr**0.42) + +fig = fdsplotlib.plot_to_fig(x_data=RE, y_data=NU, marker_style='k-', data_label='Martin', + x_min=0.0, x_max=5e5, y_min=0, y_max=600, + revision_label=version_string, + x_label='Re', + y_label='Nu') + + +markers = {'coarse': ('b', 's'), 'medium': ('r', 's'), 'fine': ('g', 's')} + +E_FDS = np.zeros((2, 3)) # shape: (len(Re_str), len(res_list)) + +# Loop over resolutions and Re cases +for j, res in enumerate(res_list): + for i, Re_tag in enumerate(Re_str): + # Compute Re from U_j for this case + Re_j = D_h * U_j[i] / nu + + # Martin Nu for this Re + Nu_cor = G * 2*np.sqrt(Re_j) * np.sqrt(1 + 0.005*Re_j**0.55) * (Pr**0.42) + + # FDS results: read *_devc.csv and get average HF over second half + devc_path = os.path.join(outdir, f'impinging_jet_Re_{Re_tag}_{res}_devc.csv') + df = pd.read_csv(devc_path, header=1) + + # Mean HF over second half of samples + n = len(df) + hf_col = 'HF' if 'HF' in df.columns else df.columns[-1] # simple fallback + HF_mean = df[hf_col].iloc[n // 2 :].mean() + + qconv = HF_mean * 1000.0 # W/m^2 + h_fds = qconv / (T_j - T_w) + Nu_fds = h_fds * D_h / k + + # relative error + E = abs(Nu_cor - Nu_fds) / abs(Nu_cor) + E_FDS[i, j] = E + if E > E_tol: + print(f'MATLAB Warning (ported): impinging jet error = {E:.3f} at Re_j={Re_tag}, Res={res}') + + label = f'FDS {res}' if i == 0 else None + fig = fdsplotlib.plot_to_fig(x_data=Re_j, y_data=Nu_fds, data_label=label, figure_handle=fig, marker_style=markers[res], marker_fill_color=(1,1,1,0.0)) + +# Convert exponential to scientific +fdsplotlib.apply_global_exponent(fig.axes[0], axis='x', fontsize=plot_style['Label_Font_Size']) + +# Save figure +corr_pdf = os.path.join(pltdir, 'impinging_jet_correlation.pdf') +fig.savefig(corr_pdf) +plt.close(fig) + +# ----------------------------- +# Plot 2: Local Nu(x) profiles for each Re case +# ----------------------------- +styles = ['k-.', 'k--', 'k-'] # coarse, medium, fine + +for i, Re_tag in enumerate(Re_str): + fig = None + for j, res in enumerate(res_list): + line_path = os.path.join(outdir, f'impinging_jet_Re_{Re_tag}_{res}_line.csv') + LINE = pd.read_csv(line_path, header=1) + + # x is first column; QCONV column used (match MATLAB) + x = LINE.iloc[:, 0].to_numpy() + q_col = 'QCONV' if 'QCONV' in LINE.columns else LINE.columns[-1] + q_x = LINE[q_col].to_numpy() * 1000.0 # W/m^2 + + Nu_x = (q_x / (T_j - T_w)) * D_h / k + + revlabel = version_string if j == 0 else None + fig = fdsplotlib.plot_to_fig(x_data=x, y_data=Nu_x, marker_style=styles[j], data_label=r'$D_{h}/\delta x$ = %d'%(7*(2**j)), + x_min=-0.5, x_max=0.5, y_min=0, y_max=1000, xnumticks=3, ynumticks=6, + revision_label=revlabel, figure_handle=fig, + x_label='$x$ (m)', + y_label=r'Nu$_{D_h}$($x$)', legend_location=2) + + fig.axes[0].xaxis.set_tick_params(pad=10) + local_pdf = os.path.join(pltdir, f'impinging_jet_local_Re_{Re_tag}.pdf') + fig.savefig(local_pdf) + plt.close(fig) + +print('Completed plots:') +print(' -', corr_pdf) +for Re_tag in Re_str: + print(' -', os.path.join(pltdir, f'impinging_jet_local_Re_{Re_tag}.pdf')) diff --git a/Utilities/Python/scripts/level_set_ellipse.py b/Utilities/Python/scripts/level_set_ellipse.py new file mode 100644 index 00000000000..2dd5834f610 --- /dev/null +++ b/Utilities/Python/scripts/level_set_ellipse.py @@ -0,0 +1,235 @@ +import os +import sys +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +# Paths and identifiers +outdir = '../../Verification/WUI/' +pltdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/' + +# Simulation parameters +U_vals = [0, 5] # wind speeds (m/s) +R0 = 0.05 # zero-wind, zero-slope spread rate (m/s) +theta_w = 90 # wind compass direction (deg) +theta_s = 45 # compass direction of increasing slope (deg) +slope_angles = [0, 30] # degrees of slope tested +theta_dev = np.arange(0, 360, 45) # device angles + +# Global parameters of fuel bed +sigma = 50.0 # svr (1/cm) +beta = 0.01 # packing ratio (-) + +def wind_phi(U: float, theta_w_deg: float) -> tuple[float, float]: + U_min = U * 60.0 + beta_op = 0.20395 * (sigma ** -0.8189) + beta_ratio = beta / beta_op + C = 7.47 * np.exp(-0.8711 * sigma ** 0.55) + B = 0.15988 * sigma ** 0.54 + E = 0.715 * np.exp(-0.01094 * sigma) + phi_w_x = C * (3.281 * U_min) ** B * (beta_ratio) ** -E * np.sin(np.deg2rad(theta_w_deg)) + phi_w_y = C * (3.281 * U_min) ** B * (beta_ratio) ** -E * np.cos(np.deg2rad(theta_w_deg)) + return phi_w_x, phi_w_y + + +def slope_phi(dzdx: float, dzdy: float) -> tuple[float, float]: + dzds = np.sqrt(dzdx ** 2 + dzdy ** 2) + coeff = 5.275 * beta ** -0.3 + phi_s_x = coeff * dzdx * dzds + phi_s_y = coeff * dzdy * dzds + return phi_s_y, phi_s_x + + +def virtual_wind(phi_s_x: float, phi_s_y: float) -> tuple[float, float]: + beta_op = 0.20395 * (sigma ** -0.8189) + beta_ratio = beta / beta_op + C = 7.47 * np.exp(-0.8711 * sigma ** 0.55) + B = 0.15988 * sigma ** 0.54 + E = 0.715 * np.exp(-0.01094 * sigma) + phi_s = np.sqrt(phi_s_x ** 2 + phi_s_y ** 2) + if phi_s > 0: + uv_tmp = 0.3048 / phi_s * (phi_s / C * beta_ratio ** E) ** (1 / B) + else: + uv_tmp = 0.0 + u_virtual = uv_tmp * phi_s_x / 60.0 + v_virtual = uv_tmp * phi_s_y / 60.0 + return u_virtual, v_virtual + + +colors = ['k', 'r', 'b', 'g'] +error_table = None + +for slope in slope_angles: + fig = None + + for idx_u, U in enumerate(U_vals): + + # Read arrival times + CHID = f'LS_ellipse_{U}ms_{slope:02d}deg' + devc_file = os.path.join(outdir, f'{CHID}_devc.csv') + if not os.path.exists(devc_file): + print(f'Error: File {devc_file} does not exist. Skipping case.') + sys.exit() + + DEVC = pd.read_csv(devc_file, skiprows=1) + + # Distance from ignition for each point (along sloped surface) + dist = np.sqrt(4.0 ** 2 + (4.0 * np.tan(np.deg2rad(slope)) * np.cos(np.deg2rad(theta_dev - theta_s))) ** 2) + + # Spread rate from arrival time at each point (use last row of DEVC) + arrival_times = DEVC.iloc[-1, 1:].to_numpy(dtype=float) + r = dist / arrival_times + + # Plot distance traveled in 10 seconds (Cartesian) + x_pts = 10.0 * r * np.sin(np.deg2rad(theta_dev)) + y_pts = 10.0 * r * np.cos(np.deg2rad(theta_dev)) + + # Revision string + git_file = os.path.join(outdir, f'{CHID}_git.txt') + version_string = fdsplotlib.get_version_string(git_file) + + if fig is None: + fig = fdsplotlib.plot_to_fig( + x_data=x_pts, + y_data=y_pts, + marker_style=f'{colors[idx_u]}o', + x_min=-2, + x_max=10, + y_min=-4, + y_max=5, + revision_label=version_string, + plot_title=f'Level set spread rate (LS_ellipse_*ms_{slope:02d}deg)', + x_label='x (m)', + y_label='y (m)', + data_label=f'FDS {U} m/s' + ) + else: + fdsplotlib.plot_to_fig(x_data=x_pts, + y_data=y_pts, + marker_style=f'{colors[idx_u]}o', + data_label=f'FDS {U} m/s', + figure_handle=fig) + + # Theoretical spread + HT = 0.2 # fuel layer height (m) + UMF = U * 1.83 / np.log((20 + 1.18 * HT) / (0.43 * HT)) + + phi_w_x, phi_w_y = wind_phi(UMF, theta_w) + phi_s_x, phi_s_y = slope_phi(np.sin(np.deg2rad(theta_s)) * np.tan(np.deg2rad(slope)), + np.cos(np.deg2rad(theta_s)) * np.tan(np.deg2rad(slope))) + + # combine slope and wind factors for total head spread rate + phi_x = phi_w_x + phi_s_x + phi_y = phi_w_y + phi_s_y + R = R0 * (1.0 + np.sqrt(phi_x ** 2 + phi_y ** 2)) + + # get virtual wind vector and apply to elliptical model + u_v, v_v = virtual_wind(phi_s_x, phi_s_y) + u_v = UMF * np.sin(np.deg2rad(theta_w)) + u_v + v_v = UMF * np.cos(np.deg2rad(theta_w)) + v_v + UMF_v = np.sqrt(u_v ** 2 + v_v ** 2) + theta_w_v = 90.0 - np.degrees(np.arctan2(v_v, u_v)) + + + LB = 0.936 * np.exp(0.2566 * UMF_v) + 0.461 * np.exp(-0.1548 * UMF_v) - 0.397 + LB = float(np.clip(LB, 1.0, 8.0)) + HB = (LB + np.sqrt(LB ** 2 - 1.0)) / (LB - np.sqrt(LB ** 2 - 1.0)) + b = 0.5 * (R + R / HB) + a = b / LB + c = b - R / HB + + ang = np.arange(0, 360) + x_s = np.cos(np.deg2rad(ang)) + y_s = np.sin(np.deg2rad(ang)) + + twv = np.deg2rad(theta_w_v) + D = (a ** 2 * (x_s * np.sin(twv) + y_s * np.cos(twv)) ** 2 + + b ** 2 * (x_s * np.cos(twv) - y_s * np.sin(twv)) ** 2) ** -0.5 + R_x = D * (a ** 2 * np.cos(twv) * (x_s * np.sin(twv) + y_s * np.cos(twv)) - + b ** 2 * np.sin(twv) * (x_s * np.cos(twv) - y_s * np.sin(twv))) + c * np.sin(twv) + R_y = D * (-a ** 2 * np.sin(twv) * (x_s * np.sin(twv) + y_s * np.cos(twv)) - + b ** 2 * np.cos(twv) * (x_s * np.cos(twv) - y_s * np.sin(twv))) + c * np.cos(twv) + + # theoretical spread distance after 10 s + x_th = 10.0 * R_x + y_th = 10.0 * R_y + + fdsplotlib.plot_to_fig(x_data=x_th, + y_data=y_th, + marker_style=f'{colors[idx_u]}-', + data_label=f'Expected {U} m/s', + figure_handle=fig) + + # Error computation for device angles + R_target = np.sqrt(R_x ** 2 + R_y ** 2) + theta_target = 90.0 - np.degrees(np.arctan2(R_y, R_x)) + theta_target = np.where(theta_target < 0, 360.0 + theta_target, theta_target) + sort_idx = np.argsort(theta_target) + theta_sorted = theta_target[sort_idx] + R_sorted = R_target[sort_idx] + R_interp = np.interp(theta_dev, theta_sorted, R_sorted, left=None, right=None) + err_vals = np.abs(r - R_interp) / R_interp + + col_name = fr'{U} m/s; {slope:d}$^\circ$' + if error_table is None: + error_table = pd.DataFrame({'angle': theta_dev, col_name: err_vals}) + else: + error_table[col_name] = err_vals + + # Plot ignition point + ax = plt.gca() + ax.plot(0.0, 0.0, 'rx', label='_nolegend_') + + # Add wind annotation arrow + ax.annotate('wind', xytext=(2.0, -3.5), xy=(4.0, -3.5), xycoords='data', + ha='center', va='center', + arrowprops=dict(arrowstyle='->', color='k', lw=1.0)) + # Add slope annotation arrow (only if slope > 0) + if slope > 0: + dx = 2.0 * np.cos(np.deg2rad(theta_s)) + dy = 2.0 * np.sin(np.deg2rad(theta_s)) + ax.annotate('slope', xytext=(2.0, -2.75), xy=(2.0 + dx, -2.75 + dy), + ha='center', va='center', + arrowprops=dict(arrowstyle='->', color='k', lw=1.0)) + + # Save per-slope figure + fig.savefig(os.path.join(pltdir, f'level_set_ellipse_{slope:02d}deg.pdf'), format='pdf') + plt.close(fig) + + +# Tolerance check +if error_table is not None: + max_err = float(np.max(error_table.drop(columns=['angle']).to_numpy())) + if max_err > 0.2: + print(f'Python Warning: LS_ellipse is out of tolerance. Max error = {max_err:.3f}') + + # Error table plot + cols = [c for c in error_table.columns if c != 'angle'] + # Initialize figure with first series + fig_err = fdsplotlib.plot_to_fig(x_data=error_table['angle'].to_numpy(), + y_data=error_table[cols[0]].to_numpy(), + marker_style=f'{colors[0]}-', + revision_label=version_string, + plot_title='Level set spread error', + x_label=r'compass angle ($^\circ$)', + y_label='relative error (-)', + y_min=0, + y_max=0.3, + data_label=cols[0]) + + for i, c in enumerate(cols[1:], start=1): + fdsplotlib.plot_to_fig(x_data=error_table['angle'].to_numpy(), + y_data=error_table[c].to_numpy(), + marker_style=f'{colors[i % len(colors)]}-', + data_label=c, + figure_handle=fig_err) + + + + fig_err.savefig(os.path.join(pltdir, 'level_set_ellipse_error.pdf'), format='pdf') + plt.close(fig_err) + + diff --git a/Utilities/Python/scripts/mass_balance.py b/Utilities/Python/scripts/mass_balance.py new file mode 100644 index 00000000000..ca316a41217 --- /dev/null +++ b/Utilities/Python/scripts/mass_balance.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +""" +mass_balance.py +Validates mass conservation comparing time derivative of species mass with inlet/outlet flow rates. +Original MATLAB script by McDermott (05 Dec 2017) +""" +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import fdsplotlib +import os + +def plot_mass_balance(chid, title_text): + + plot_style = fdsplotlib.get_plot_style('fds') + ddir = '../../Verification/Species/' + pltdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/' + + mass_file = os.path.join(ddir, f'{chid}_mass.csv') + + try: + M = pd.read_csv(mass_file, skiprows=1) # Skip units row, use column names as header + except FileNotFoundError: + print(f'Error: File {mass_file} does not exist. Skipping case.') + return 0 + + t = M.iloc[:, 0].values + m = M['WATER VAPOR'].values + + # Compute dm/dt using numerical differentiation + dmdt = np.zeros(len(t)) + for i in range(1, len(t)): + dmdt[i] = (m[i] - m[i-1]) / (t[i] - t[i-1]) + + devc_file = os.path.join(ddir, f'{chid}_devc.csv') + + F = pd.read_csv(devc_file, skiprows=1) # Skip units row, use column names as header + mdot_in = F['H2O in'].values + mdot_out = F['H2O out'].values + + # Residual: dm/dt - mdot_in - mdot_out (should be ~0) + bal = dmdt - mdot_in - mdot_out + + # Get version string if git file exists + git_file = os.path.join(ddir, f'{chid}_git.txt') + version_string = fdsplotlib.get_version_string(git_file) if os.path.exists(git_file) else '' + + # Plot zero reference line first (black solid line, no label) + fig = fdsplotlib.plot_to_fig(x_data=t, y_data=np.zeros_like(t), marker_style='k-',revision_label=version_string,legend_location='upper right', + x_label='time (s)', y_label='mass flow (kg/s)',x_min=0, x_max=2000, y_min=-0.005, y_max=0.015) + fdsplotlib.plot_to_fig(x_data=t, y_data=mdot_in, figure_handle=fig, marker_style='r-', data_label='Inlet H2O') + fdsplotlib.plot_to_fig(x_data=t, y_data=-mdot_out, figure_handle=fig, marker_style='m-', data_label='Outlet H2O') + fdsplotlib.plot_to_fig(x_data=t, y_data=bal, figure_handle=fig, marker_style='b-', data_label='dm/dt+out-in') + + ax = plt.gca() + lines = ax.get_lines() + lines[2].set_color('#EDB120') # Orange for outlet (second data line) + ax.locator_params(axis='x', nbins=6) # ~6 ticks on x-axis + ax.locator_params(axis='y', nbins=5) # ~5 ticks on y-axis + fdsplotlib.apply_global_exponent(ax, axis='y') + ax.text(100, 18e-3, title_text,fontsize=plot_style['Title_Font_Size'],fontname=plot_style['Font_Name']) + + # Compute mean error for t > 1000 s + mask = t > 1000 + if np.any(mask): + mass_error = np.abs(np.mean(bal[mask])) + if mass_error > 1e-5: + print(f'Python Warning: mass error = {mass_error:.6e} in {chid}') + else: + mass_error = np.nan + print(f'Warning: No data points with t > 1000 s in {chid}') + + # Save figure + os.makedirs(pltdir, exist_ok=True) + output_file = os.path.join(pltdir, f'{chid}_mass_balance.pdf') + plt.savefig(output_file, format='pdf') + plt.close(fig) + + return mass_error + +if __name__ == '__main__': + """Main execution block""" + + print("Running mass balance verification plots...") + error1 = plot_mass_balance('mass_flux_wall_yindex','Primitive Species Mass Balance') + error2 = plot_mass_balance('mass_flux_wall_zindex','Lumped Species Mass Balance') + print("Mass balance verification completed successfully!") \ No newline at end of file diff --git a/Utilities/Python/scripts/mesh_transformation.py b/Utilities/Python/scripts/mesh_transformation.py new file mode 100644 index 00000000000..a674a7d2834 --- /dev/null +++ b/Utilities/Python/scripts/mesh_transformation.py @@ -0,0 +1,108 @@ + +# Postprocessing script to extract transformation mapping from SMV and create figures for User's Guide + +import numpy as np +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +outdir = '../../Verification/Miscellaneous/' +pltdir = '../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/' + +fid = open(outdir + 'mesh_transformation.smv', 'r') + +I = 50 +J = 50 +LX = 1.5 +LY = 1.5 +dx = LX / I +dy = LY / J + +cx = np.zeros(I + 1) +x = np.zeros(I + 1) +cy = np.zeros(J + 1) +y = np.zeros(J + 1) + +while True: + tline = fid.readline() + if not tline: # End of file + break + tline = tline.strip() + if tline == 'TRNX': + # Skip next 3 lines + for i in range(3): + skip = fid.readline() + # Read I+1 lines of transformation data + for i in range(I + 1): + tline = fid.readline() + values = [float(val) for val in tline.split()] + cx[i] = values[0] * dx + x[i] = values[1] + if tline == 'TRNY': + # Skip next 3 lines + for j in range(3): + skip = fid.readline() + # Read J+1 lines of transformation data + for j in range(J + 1): + tline = fid.readline() + values = [float(val) for val in tline.split()] + cy[j] = values[0] * dy + y[j] = values[1] + +fid.close() + +# From the mesh_transformation.fds input file: +CC = [0.3, 1.2] +PC = [0.5, 1.0] + +XMinorTick = np.arange(0.1, 1.5, 0.1) + +# First figure - piece-wise linear transformation + +fig = fdsplotlib.plot_to_fig(x_data=cx, y_data=x, marker_style='k-', + x_min=0, x_max=1.5, y_min=0, y_max=1.5, + figure_size=(plot_style['Scat_Paper_Width'],plot_style['Scat_Paper_Height']), + plot_size=(plot_style['Scat_Plot_Width'],plot_style['Scat_Plot_Height']), + plot_origin=(plot_style['Scat_Plot_X'],plot_style['Scat_Plot_Y']), + x_label=r'$\xi$', y_label=r'$x$') + +for i in range(len(XMinorTick)): + if XMinorTick[i] < CC[0]: + YMinorTick = (PC[0] / CC[0]) * XMinorTick[i] + elif XMinorTick[i] < CC[1]: + YMinorTick = PC[0] + (PC[1] - PC[0]) / (CC[1] - CC[0]) * (XMinorTick[i] - CC[0]) + elif XMinorTick[i] <= LX: + YMinorTick = PC[1] + (LX - PC[1]) / (LX - CC[1]) * (XMinorTick[i] - CC[1]) + + fdsplotlib.plot_to_fig(x_data=[XMinorTick[i],XMinorTick[i]], y_data=[0,YMinorTick], marker_style='k-', figure_handle=fig) + fdsplotlib.plot_to_fig(x_data=[0, XMinorTick[i]], y_data=[YMinorTick,YMinorTick], marker_style='k-', figure_handle=fig) + +ax = plt.gca() +ax.set_xticks(np.arange(0, 1.5, 0.3)) +ax.set_yticks(np.arange(0, 1.5, 0.3)) + +plt.savefig(pltdir + 'piece_wise_linear_trnx.pdf', format='pdf') +plt.close() + +# Second figure - polynomial transformation + +fig = fdsplotlib.plot_to_fig(x_data=cy, y_data=y, marker_style='k-', + x_min=0, x_max=1.5, y_min=0, y_max=1.5, + figure_size=(plot_style['Scat_Paper_Width'],plot_style['Scat_Paper_Height']), + plot_size=(plot_style['Scat_Plot_Width'],plot_style['Scat_Plot_Height']), + plot_origin=(plot_style['Scat_Plot_X'],plot_style['Scat_Plot_Y']), + x_label=r'$\xi$', y_label=r'$x$') + +for i in range(len(XMinorTick)): + YMinorTick = 2 * XMinorTick[i] - 2 * XMinorTick[i]**2 + 0.8889 * XMinorTick[i]**3 + fdsplotlib.plot_to_fig(x_data=[XMinorTick[i],XMinorTick[i]], y_data=[0,YMinorTick], marker_style='k-', figure_handle=fig) + fdsplotlib.plot_to_fig(x_data=[0, XMinorTick[i]], y_data=[YMinorTick,YMinorTick], marker_style='k-', figure_handle=fig) + +ax = plt.gca() +ax.set_xticks(np.arange(0, 1.5, 0.3)) +ax.set_yticks(np.arange(0, 1.5, 0.3)) + +plt.savefig(pltdir + 'polynomial_trnx.pdf', format='pdf') +plt.close() + diff --git a/Utilities/Python/scripts/ns2d.py b/Utilities/Python/scripts/ns2d.py new file mode 100644 index 00000000000..3d394f630b3 --- /dev/null +++ b/Utilities/Python/scripts/ns2d.py @@ -0,0 +1,87 @@ +# Roger Wang +# 6-28-11 +# ns2d.py +# Process the output of the ns2d verification cases +# +# Converted by Floyd +# 10/17/2025 + +import numpy as np +import pandas as pd +import os +import math + + +datadir = '../../Verification/NS_Analytical_Solution/' +infile = [['ns2d_8_devc.csv','ns2d_8_nupt1_devc.csv'], + ['ns2d_16_devc.csv','ns2d_16_nupt1_devc.csv'], + ['ns2d_32_devc.csv','ns2d_32_nupt1_devc.csv'], + ['ns2d_64_devc.csv','ns2d_64_nupt1_devc.csv']] + +outfile = [['ns2d_8_exact.csv','ns2d_8_nupt1_exact.csv'], + ['ns2d_16_exact.csv','ns2d_16_nupt1_exact.csv'], + ['ns2d_32_exact.csv','ns2d_32_nupt1_exact.csv'], + ['ns2d_64_exact.csv','ns2d_64_nupt1_exact.csv']] + +skip_case = False + +for i in range(len(infile)): + for j in range(len(infile[i])): + name = datadir+infile[i][j] + if not os.path.exists(name): + skip_case = True + print('Error: File ', infile[i][j], ' does not exist. Skipping case.') + +if skip_case: quit() + +nu = [0.0, 0.1] +pi = math.pi +x = pi +y = pi +dx = [2.0 * pi / 8.0, 2.0 * pi / 16.0, 2.0 * pi / 32.0, 2.0 * pi / 64.0] + +rms = np.zeros((4, 2)) +cnt = np.zeros((4, 2)) + +# k iterates over viscosity (0: nu=0.0, 1: nu=0.1) +for k in range(2): + # j iterates over resolution (0: 8 cells, 3: 64 cells) + for j in range(4): + M_10 = pd.read_csv(datadir+infile[j][k], skiprows=2, header=None).values + + with open(datadir+outfile[j][k], 'w') as M_11: + M_11.write("Time, u-vel\n") + + squared_error_sum = 0.0 + num_points = 0.0 + + for i in range(len(M_10)): + t = M_10[i, 0] + u_fds = M_10[i, 1] + + u_exact = 1.0 - 2.0 * math.cos(x - t) * math.sin(y - 0.5 * dx[j] - t) * math.exp(-2.0 * nu[k] * t) + + M_11.write(f"{t:8.3f}, {u_exact:9.5f}\n") + + squared_error_sum += (u_fds - u_exact)**2 + + num_points += 1.0 + + if num_points > 0: + rms[j, k] = math.sqrt(squared_error_sum / num_points) + else: + rms[j, k] = 0.0 + +# Case 1: nu=0.0 (k=0) +with open(datadir+'ns2d_error.csv', 'w') as fid11: + fid11.write('dx,dx^2,rms error\n') + for j in range(4): + fid11.write(f"{dx[j]:8.3f}, {dx[j]**2:8.3f}, {rms[j, 0]:8.4f}\n") + +# Case 2: nu=0.1 (k=1) +with open(datadir+'ns2d_nupt1_error.csv', 'w') as fid12: + fid12.write('dx,dx^2,rms error\n') + for j in range(4): + fid12.write(f"{dx[j]:8.3f}, {dx[j]**2:8.3f}, {rms[j, 1]:8.4f}\n") + +print("Processing complete. Exact solution files and RMS error summary files created.") \ No newline at end of file diff --git a/Utilities/Python/scripts/openmp_timing_benchmarks.py b/Utilities/Python/scripts/openmp_timing_benchmarks.py new file mode 100644 index 00000000000..c277a416686 --- /dev/null +++ b/Utilities/Python/scripts/openmp_timing_benchmarks.py @@ -0,0 +1,54 @@ + +# Show efficiency of OpenMP timing cases + +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +outdir = '../../../out/OMP_Scaling_Tests/' +pltdir = '../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/' + +git_file = outdir + 'openmp_test64a_git.txt' +version_string = fdsplotlib.get_version_string(git_file) + +ncores = [1, 2, 3, 4, 5, 6, 7, 8] +a = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] + +time64 = np.zeros(len(a)) +time128 = np.zeros(len(a)) + +# Read data for 64 cube cases +for i in range(len(a)): + M = pd.read_csv(outdir + f'openmp_test64{a[i]}_devc.csv', skiprows=1) + M.columns = M.columns.str.strip() + j = M.columns.get_loc('clock time') + time64[i] = M.iloc[-1, j] +time64 = time64 / time64[0] * 100 + +for i in range(len(a)): + M = pd.read_csv(outdir + f'openmp_test128{a[i]}_devc.csv', skiprows=1) + M.columns = M.columns.str.strip() + j = M.columns.get_loc('clock time') + time128[i] = M.iloc[-1, j] +time128 = time128 / time128[0] * 100 + +fig = fdsplotlib.plot_to_fig(x_data=ncores, y_data=time64, marker_style='b^-', data_label='$64^3$', + x_min=1, x_max=8, y_min=0, y_max=100, + revision_label=version_string, + x_label='Number of OpenMP Threads', + y_label=r'Relative Clock Time (%)') + +fdsplotlib.plot_to_fig(x_data=ncores, y_data=time128, marker_style='rsq-', data_label='$128^3$', figure_handle=fig) + +plt.savefig(pltdir + 'openmp_timing_benchmarks.pdf', format='pdf') +plt.close() + +if time64[3] > 80.: + print(f'Matlab Warning: Timing for openmp_test64 out of tolerance. {time64[3]}') + +if time128[3] > 80.: + print(f'Matlab Warning: Timing for openmp_test128 out of tolerance. {time128[3]}') + diff --git a/Utilities/Python/scripts/particle_size_distribution.py b/Utilities/Python/scripts/particle_size_distribution.py new file mode 100644 index 00000000000..aebf47d6425 --- /dev/null +++ b/Utilities/Python/scripts/particle_size_distribution.py @@ -0,0 +1,65 @@ + +# Generate the Rosin-Rammler / log-normal particle size distribution plot in the FDS Tech Guide + +import numpy as np +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style("fds") + +pltdir = '../../Manuals/FDS_Technical_Reference_Guide/SCRIPT_FIGURES/' + +D_v50 = 1 +gamma = 2.4 +sigma = 1.15/gamma +N = 100 +D = np.linspace(0, 3, N) +dD = D[1] - D[0] + +F1 = np.zeros(N) +F2 = np.zeros(N) +Fv = np.zeros(N) +fv = np.zeros(N) +Fn = np.zeros(N) + +for i in range(N): + + if i == 0: + F1[i] = 0 + else: + DP = 0.5 * (D[i-1] + D[i]) + F1[i] = F1[i-1] + np.exp(-np.log(DP/D_v50)**2/(2*sigma**2)) * dD / (np.sqrt(2*np.pi)*sigma*DP) + + F2[i] = 1 - np.exp(-0.693*(D[i]/D_v50)**gamma) + + if D[i] < D_v50: + Fv[i] = F1[i] + else: + Fv[i] = F2[i] + + # probability density function (derivative of CDF) + if i == 0: + fv[i] = 0 + else: + fv[i] = (Fv[i] - Fv[i-1]) / (D[i] - D[i-1]) + + if i == 0: + Fn[i] = 0 + else: + DP = 0.5 * (D[i-1] + D[i]) + Fn[i] = Fn[i-1] + fv[i]/DP**3 * dD + +Fn = Fn / Fn[-1] + +fig = fdsplotlib.plot_to_fig(x_data=[D_v50, D_v50], y_data=[0, 1], marker_style='k:', data_label=r'$D_{\rm v,0.5}$', + x_min=0, x_max=3, y_min=0, y_max=1, + x_label='Droplet Diameter (mm)') + +fdsplotlib.plot_to_fig(x_data=D, y_data=F1, marker_style='r-.', data_label=r'$F_{\rm v}$ Log-Normal', figure_handle=fig) +fdsplotlib.plot_to_fig(x_data=D, y_data=F2, marker_style='c-.', data_label=r'$F_{\rm v}$ Rosin-Rammler', figure_handle=fig) +fdsplotlib.plot_to_fig(x_data=D, y_data=Fv, marker_style='k-', data_label=r'$F_{\rm v}$ Combined (FDS)', figure_handle=fig) +fdsplotlib.plot_to_fig(x_data=D, y_data=Fn, marker_style='b-', data_label=r'$F_{\rm n}$ Cumulative Number Fraction', figure_handle=fig) + +plt.savefig(pltdir + 'particle_size_distribution.pdf', format='pdf') +plt.close() + diff --git a/Utilities/Python/scripts/radiating_polygon.py b/Utilities/Python/scripts/radiating_polygon.py new file mode 100644 index 00000000000..158120f0d10 --- /dev/null +++ b/Utilities/Python/scripts/radiating_polygon.py @@ -0,0 +1,77 @@ +# McGrattan +# 2-16-15 +# radiating_polygon.m +# +# Converted by Floyd +# 10/16/2025 + +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +import os +import fdsplotlib + +datadir = '../../Verification/Radiation/' +plotdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/' +filename = ['radiating_polygon_square_20_line.csv','radiating_polygon_square_40_line.csv','radiating_polygon_square_80_line.csv'] + +skip_case = False + +for i in range(len(filename)): + name = datadir+filename[i] + if not os.path.exists(name): + skip_case = True + print('Error: File ', filename[i], ' does not exist. Skipping case.') + +if skip_case: quit() + +flux_20 = pd.read_csv(datadir+filename[0],skiprows=2,header=None) +flux_40 = pd.read_csv(datadir+filename[1],skiprows=2,header=None) +flux_80 = pd.read_csv(datadir+filename[2],skiprows=2,header=None) + +n = 4 +pi = np.pi + +z_max = 1 +z_min = 1 - 0.001 * (1000 - 1) # z(1000) = 1 - 0.001 * 999 = 0.001 + +z = np.linspace(z_max, z_min, 1000) + +R = 0.5 * np.sqrt(2) / z +H = 0.5 / z + +# flux(j)=5.67e-11*1273.15^4*n*H/(pi*sqrt(1+H^2))*atan(sqrt((R^2-H^2)/(1+H^2))); +T_hot = 1273.15 +sigma = 5.67e-11 + +term1 = sigma * (T_hot**4) * n +term2 = H / (pi * np.sqrt(1 + H**2)) +term3 = np.arctan(np.sqrt((R**2 - H**2) / (1 + H**2))) + +flux = term1 * term2 * term3 + +git_file = datadir+'radiating_polygon_square_20_git.txt' +version_string = fdsplotlib.get_version_string(git_file) + +fig = fdsplotlib.plot_to_fig(x_data=z, y_data=flux, marker_style='k-', + revision_label=version_string,x_min=0,x_max=1,y_min=20,y_max=160, + plot_title = 'Radiative Flux from a Hot Square Plate', + data_label='Exact', + y_label='Radiative Heat Flux (kW/m$^2$)', + x_label='Distance from Plate (m)') + +fdsplotlib.plot_to_fig(x_data=1-flux_20[0], y_data=flux_20[1], marker_style='r-', + figure_handle=fig, + data_label='5 cm, 100 angles') + +fdsplotlib.plot_to_fig(x_data=1-flux_40[0], y_data=flux_40[1], marker_style='g-', + figure_handle=fig, + data_label='2.5 cm, 400 angles') + +fdsplotlib.plot_to_fig(x_data=1-flux_80[0], y_data=flux_80[1], marker_style='b-', + figure_handle=fig, + data_label='1.25 cm, 1000 angles') + +plotname = plotdir + 'radiating_polygon_square.pdf' +plt.savefig(plotname, format='pdf') +plt.close() diff --git a/Utilities/Python/scripts/radiation_box.py b/Utilities/Python/scripts/radiation_box.py new file mode 100644 index 00000000000..4fb2ef634a2 --- /dev/null +++ b/Utilities/Python/scripts/radiation_box.py @@ -0,0 +1,58 @@ +# radiation_box.py Collect heat fluxes from radiation box cases to a single csv file in Verification/Radiation folder + +import os +import numpy as np +import pandas as pd + +# Define positions +x = np.array([ + 2.50E-02, 7.50E-02, 1.25E-01, 1.75E-01, 2.25E-01, + 2.75E-01, 3.25E-01, 3.75E-01, 4.25E-01, 4.75E-01, + 5.25E-01, 5.75E-01, 6.25E-01, 6.75E-01, 7.25E-01, + 7.75E-01, 8.25E-01, 8.75E-01, 9.25E-01, 9.75E-01 +]) + +# Directory +dir = '../../Verification/Radiation/' + +# Input files +infile = [ + f'{dir}radiation_box__20___50_devc.csv', + f'{dir}radiation_box__20__100_devc.csv', + f'{dir}radiation_box__20__300_devc.csv', + f'{dir}radiation_box__20_1000_devc.csv', + f'{dir}radiation_box__20_2000_devc.csv', + f'{dir}radiation_box_100___50_devc.csv', + f'{dir}radiation_box_100__100_devc.csv', + f'{dir}radiation_box_100__300_devc.csv', + f'{dir}radiation_box_100_1000_devc.csv', + f'{dir}radiation_box_100_2000_devc.csv' +] + +# Corresponding labels +label = [ + 'Flux_20_50', 'Flux_20_100', 'Flux_20_300', 'Flux_20_1000', 'Flux_20_2000', + 'Flux_100_50', 'Flux_100_100', 'Flux_100_300', 'Flux_100_1000', 'Flux_100_2000' +] + +# Initialize matrix for flux data +flux = np.zeros((20, 10)) + +# Read data and populate flux +for n in range(10): + if not os.path.exists(infile[n]): + print(f'Error: File {infile[n]} does not exist. Skipping case.') + else: + # Read CSV file starting from the 4th row + data = pd.read_csv(infile[n], skiprows=3, header=None) + t = data.iloc[0, 0] + flux[:, n] = data.iloc[0, 1:21].values + +# Output file +filename = f'{dir}radiation_box_devc.csv' + +# Write to CSV +with open(filename, 'w') as fid: + fid.write('Position, ' + ', '.join(label) + '\n') + for i in range(20): + fid.write(f'{x[i]:.6f}, ' + ', '.join(f'{flux[i, j]:.6f}' for j in range(10)) + '\n') diff --git a/Utilities/Python/scripts/radiation_plane_layer.py b/Utilities/Python/scripts/radiation_plane_layer.py new file mode 100644 index 00000000000..dece6706d24 --- /dev/null +++ b/Utilities/Python/scripts/radiation_plane_layer.py @@ -0,0 +1,40 @@ +# radiation_plane_layer +import os +import pandas as pd + +dir = '../../Verification/Radiation/' + +infile = [['radiation_plane_layer_{}_{}_devc.csv'.format(i, j) for j in range(1, 6)] for i in range(1, 7)] + +kappa = ['0.01', '0.1', '0.5', '1.0', '10', r'$\infty$'] + +exact = [2.8970, 24.9403, 82.9457, 116.2891, 148.9698, 148.9709] + +flux = pd.DataFrame(index=range(6), columns=range(5)) + +for j in range(5): + for i in range(6): + filepath = os.path.join(dir, infile[i][j]) + if not os.path.exists(filepath): + print(f'Error: File {filepath} does not exist. Skipping case.') + continue + df = pd.read_csv(filepath, skiprows=3, header=None) + t = df.iloc[0, 0] + flux.iloc[i, j] = df.iloc[0, 1] + +filename = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/radiation_plane_layer.tex' +with open(filename, 'wt') as fid: + fid.write('\\begin{center}\n') + fid.write('\\begin{tabular}{|c|c|c|c|c|c|c|} \\hline\n') + fid.write('$\\tau$ & $S(\\tau)$ & \\multicolumn{2}{|c|}{FDS (I=20,J=20)} &\n') + fid.write('\\multicolumn{2}{|c|}{FDS (I=20,J=1)} & FDS (I=150) \\\\ \\cline{3-7}\n') + fid.write(' & (kW/m$^2$) & 1 band & 6 bands & 1 band & 6 bands & 1 band \\\\ \\hline\\hline\n') + + for i in range(6): + fid.write(f'{kappa[i]} & {exact[i]:9.4f} & ') + fid.write(' & '.join(f'{f:9.4f}' for f in flux.iloc[i, :5])) + fid.write(' \\\\\n') + + fid.write('\\hline\n') + fid.write('\\end{tabular}\n') + fid.write('\\end{center}\n') diff --git a/Utilities/Python/scripts/random_walk_soln.py b/Utilities/Python/scripts/random_walk_soln.py new file mode 100644 index 00000000000..eb058da8cd6 --- /dev/null +++ b/Utilities/Python/scripts/random_walk_soln.py @@ -0,0 +1,84 @@ + +# This script must be run prior to dataplot both to generate the expected results +# and to normalize the PDPA results from the FDS line file. + +import numpy as np +import pandas as pd +import os + +outdir = '../../Verification/WUI/' + +z0 = 5 +nz = 80 +L = 10 +dz = L/nz +z = np.linspace(dz/2, L-dz/2, nz) +zp = z - z0 +RHO = 1.199 # kg/m3 +D_1 = 0.1/RHO # 0.0834 m2/s +D_2 = 0.01/RHO # 0.00834 m2/s +t = 15 # s + +f_1 = 1/(4*np.pi*D_1*np.sqrt(t))*np.exp(-zp**2/(4*D_1*t)) +f_1 = f_1/np.sum(f_1*dz) # normalize + +f_2 = 1/(4*np.pi*D_2*np.sqrt(t))*np.exp(-zp**2/(4*D_2*t)) +f_2 = f_2/np.sum(f_2*dz) # normalize + +# print expected results to data directory + +fid = open(outdir + 'random_walk.csv', 'wt') +fid.write('{}, {}, {}\n'.format('z', 'f_1', 'f_2')) +for i in range(len(z)): + fid.write('{:f}, {:f}, {:f}\n'.format(z[i], f_1[i], f_2[i])) +fid.close() + +# pdpa_radius = 0.5; % m +# pdpa_volume = 4/3*pi*pdpa_radius^3; % m^3 + +# normalize and overwrite the FDS results for random_walk_1 + +filename = outdir + 'random_walk_1_line.csv' + +if not os.path.exists(filename): # skip_case_if + + print('Error: File ' + filename + ' does not exist. Skipping case.') + +else: + + M = pd.read_csv(outdir + 'random_walk_1_line.csv', skiprows=1) + npv_z = M['npv-z'].values + dz = (np.max(npv_z) - np.min(npv_z))/(len(npv_z) - 1) + npv = M['npv'].values + nt = np.sum(npv) + + fid = open(outdir + 'random_walk_1.csv', 'wt') + fid.write('{}, {}\n'.format('m', ' ')) + fid.write('{}, {}\n'.format('npv-z', 'npv')) + for i in range(len(npv_z)): + fid.write('{:f}, {:f}\n'.format(npv_z[i], npv[i]/nt/dz)) + fid.close() + +# normalize and overwrite the FDS results for random_walk_2 + +filename = outdir + 'random_walk_2_line.csv' + +if not os.path.exists(filename): # skip_case_if + + print('Error: File ' + filename + ' does not exist. Skipping case.') + +else: + + M = pd.read_csv(outdir + 'random_walk_2_line.csv', skiprows=1) + npv_z = M['npv-z'].values + dz = (np.max(npv_z) - np.min(npv_z))/(len(npv_z) - 1) + npv = M['npv'].values + nt = np.sum(npv) + + fid = open(outdir + 'random_walk_2.csv', 'wt') + fid.write('{}, {}\n'.format('m', ' ')) + fid.write('{}, {}\n'.format('npv-z', 'npv')) + for i in range(len(npv_z)): + fid.write('{:f}, {:f}\n'.format(npv_z[i], npv[i]/nt/dz)) + fid.close() + diff --git a/Utilities/Python/scripts/rms_cov_corr.py b/Utilities/Python/scripts/rms_cov_corr.py new file mode 100644 index 00000000000..8adea333deb --- /dev/null +++ b/Utilities/Python/scripts/rms_cov_corr.py @@ -0,0 +1,74 @@ +# Floyd +# 5-23-2014 +# rms_cov_corr.m +# +# Converted by Floyd +# 10/16/2025 + +import pandas as pd +import numpy as np +import matplotlib.pyplot as plt +import fdsplotlib +import os + + +datadir = '../../Verification/Controls/' +plotdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/' +filename = datadir + 'rms_cov_corr_devc.csv' + +skip_case = False + +if not os.path.exists(filename): + skip_case = True + print('Error: File ', filename, ' does not exist. Skipping case.') + +if skip_case: quit() + +df = pd.read_csv(filename, skiprows=2, header=None) + +start_index = int(500 / 0.02) +end_index = df.index[-1] + +data_slice = df.iloc[start_index:end_index + 1] +u = data_slice[1].values +w = data_slice[2].values + +umean = np.mean(u) +wmean = np.mean(w) + +udiff = u - umean +wdiff = w - wmean + +# Calculate RMS, Covariance, and Correlation +urms = np.sqrt(np.mean(udiff**2)) +wrms = np.sqrt(np.mean(wdiff**2)) + +uwcov = np.mean(udiff * wdiff) + +uwcorr = uwcov / (urms * wrms) + +urms_fds = df.iloc[end_index, 3] +uwcov_fds = df.iloc[end_index, 4] +uwcorr_fds = df.iloc[end_index, 5] + +header='Time,urms,uwcov,uwcorr' +outdata=np.zeros((2,4)) +outdata[0,0]=0 +outdata[1,0]=1000 +outdata[:,1] = urms +outdata[:,2] = uwcov +outdata[:,3] = uwcorr + +print(header) +print(outdata) + +with open(datadir+'rms_cov_corr.csv','w') as fid: + fid.write(f"{header}\n") + string_with_separator = np.array2string(outdata[0,:], separator=', ')[1:-1] # [1:-1] removes brackets + print(string_with_separator) + fid.write(f"{string_with_separator}\n") + string_with_separator = np.array2string(outdata[1,:], separator=', ')[1:-1] # [1:-1] removes brackets + print(string_with_separator) + fid.write(f"{string_with_separator}\n") + + diff --git a/Utilities/Python/scripts/saad_mms_temporal_error.py b/Utilities/Python/scripts/saad_mms_temporal_error.py index eff82dfa5d1..aff4e43135b 100644 --- a/Utilities/Python/scripts/saad_mms_temporal_error.py +++ b/Utilities/Python/scripts/saad_mms_temporal_error.py @@ -173,6 +173,16 @@ datadir = '../../Verification/Complex_Geometry/' filename = ['saad_CC_explicit_512_cfl_p25_mms.csv','saad_CC_explicit_512_cfl_p125_mms.csv','saad_CC_explicit_512_cfl_p0625_mms.csv'] +skip_case = False + +for i in range(len(filename)): + name = datadir+filename[i] + if not os.path.exists(name): + skip_case = True + print('Error: File ', filename[i], ' does not exist. Skipping case.') + +if skip_case: quit() + M1 = pd.read_csv(datadir+filename[0],skiprows=2,header=None) M2 = pd.read_csv(datadir+filename[1],skiprows=2,header=None) M3 = pd.read_csv(datadir+filename[2],skiprows=2,header=None) @@ -238,7 +248,7 @@ x_label='$x$ (m)', y_label='$p$ order density') -plotname = plotdir + 'saad_CC_temporal_order_rho.pdf' +plotname = plotdir + 'saad_CC_explicit_temporal_order_rho.pdf' plt.savefig(plotname, format='pdf') plt.close() @@ -247,7 +257,7 @@ x_label='$x$ (m)', y_label='$p$ order mixture fraction') -plotname = plotdir + 'saad_CC_temporal_order_Z.pdf' +plotname = plotdir + 'saad_CC_explicit_temporal_order_Z.pdf' plt.savefig(plotname, format='pdf') plt.close() @@ -261,7 +271,7 @@ figure_handle=fig, data_label='Final field') -plotname = plotdir + 'saad_CC_rho.pdf' +plotname = plotdir + 'saad_CC_explicit_rho.pdf' plt.savefig(plotname, format='pdf') plt.close() @@ -275,7 +285,7 @@ figure_handle=fig, data_label='Final field') -plotname = plotdir + 'saad_CC_Z.pdf' +plotname = plotdir + 'saad_CC_explicit_Z.pdf' plt.savefig(plotname, format='pdf') plt.close() @@ -289,6 +299,6 @@ figure_handle=fig, data_label = '$\\rho_2$ - $\\rho_1$') -plotname = plotdir + 'saad_CC_rho_diff.pdf' +plotname = plotdir + 'saad_CC_explicit_rho_diff.pdf' plt.savefig(plotname, format='pdf') plt.close() \ No newline at end of file diff --git a/Utilities/Python/scripts/scaling_tests.py b/Utilities/Python/scripts/scaling_tests.py new file mode 100644 index 00000000000..73ae993a780 --- /dev/null +++ b/Utilities/Python/scripts/scaling_tests.py @@ -0,0 +1,109 @@ + +# Read _cpu.csv files for the MPI weak and strong scaling test cases + +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +outdir = '../../../out/MPI_Scaling_Tests/' +pltdir = '../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/' + +git_file = outdir + 'strong_scaling_test_001_git.txt' +version_string = fdsplotlib.get_version_string(git_file) + + +M = [] +M.append(pd.read_csv(outdir + 'strong_scaling_test_001_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'strong_scaling_test_008_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'strong_scaling_test_032_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'strong_scaling_test_064_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'strong_scaling_test_096_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'strong_scaling_test_192_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'strong_scaling_test_288_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'strong_scaling_test_432_cpu.csv', skiprows=1, header=None)) + +r = np.array([1, 8, 32, 64, 96, 192, 288, 432]) +r2 = np.array([0.1, 8, 32, 64, 96, 192, 432, 1000]) + +n_rows, n_cols = M[0].shape + +# Initialize t and t2 arrays +t = np.zeros((8, n_cols)) +t2 = np.zeros(8) + +# Calculate normalized times +for j in range(n_cols): + for i in range(8): + t[i, j] = M[i].iloc[0, j] / M[0].iloc[0, n_cols - 1] + t2[i] = 1.0 / r2[i] + +# Check if strong scaling test is within tolerance +if t[7, n_cols - 1] > 4 / r[7] or t[7, n_cols - 1] < 1 / r[7]: + print('Error: strong scaling test out of tolerance') + +fig = fdsplotlib.plot_to_fig(x_data=[1e-10,1e-10], y_data=[1e-10,1e-10], + x_min=1, x_max=1000, y_min=0.00001, y_max=1, + plot_type='loglog', + legend_location='outside', + revision_label=version_string, + plot_title='Strong Scaling Test', + x_label='MPI Processes', + y_label='Relative Wall Clock Time') + +for i in range(10): + fdsplotlib.plot_to_fig(x_data=r2, y_data=t2/2**(i-1), figure_handle=fig, marker_style='k:') + +marks = np.array(['k-o','r-o','b-o','m-o','c-o','g-o','y-o','k-s']) +ind = np.array([n_cols-1,2,3,4,5,11,9,1]) +legend = np.array(['Total', 'DIVG', 'MASS', 'VELO', 'PRES', 'COMM', 'RADI', 'MAIN']) + +for i in range(8): + fdsplotlib.plot_to_fig(x_data=r, y_data=t[:,ind[i]], figure_handle=fig, marker_style=marks[i], data_label=legend[i]) + +plt.savefig(pltdir + 'strong_scaling_test.pdf', format='pdf') +plt.close() + +# Import data files for weak scaling test + +M = [] +M.append(pd.read_csv(outdir + 'weak_scaling_test_001_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'weak_scaling_test_002_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'weak_scaling_test_004_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'weak_scaling_test_008_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'weak_scaling_test_016_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'weak_scaling_test_032_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'weak_scaling_test_064_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'weak_scaling_test_128_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'weak_scaling_test_192_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'weak_scaling_test_288_cpu.csv', skiprows=1, header=None)) +M.append(pd.read_csv(outdir + 'weak_scaling_test_432_cpu.csv', skiprows=1, header=None)) + +r = np.array([1, 2, 4, 8, 16, 32, 64, 128, 192, 288, 432]) + +n_rows, n_cols = M[0].shape + +t = np.zeros(11) +t2 = np.ones(11) + +for i in range(11): + t[i] = M[0].iloc[0, n_cols - 1] / M[i].iloc[0, n_cols - 1] + +if t[10] > 1.0 or t[10] < 0.4: + print('Error: weak scaling test out of tolerance') + +fig = fdsplotlib.plot_to_fig(x_data=r, y_data=t, data_label='FDS', marker_style='ko', + x_min=1, x_max=1000, y_min=0, y_max=1.2, + plot_type='semilogx', + revision_label=version_string, + plot_title='Weak Scaling Test', + x_label='MPI Processes', + y_label='Efficiency') + +fdsplotlib.plot_to_fig(x_data=r, y_data=t2, data_label='Ideal', marker_style='k--', figure_handle=fig) + +plt.savefig(pltdir + 'weak_scaling_test.pdf', format='pdf') +plt.close() + diff --git a/Utilities/Python/scripts/shunn_mms.py b/Utilities/Python/scripts/shunn_mms.py index 13eb440eecc..c9f1f830cb2 100644 --- a/Utilities/Python/scripts/shunn_mms.py +++ b/Utilities/Python/scripts/shunn_mms.py @@ -79,7 +79,7 @@ L2_rho = np.linalg.norm(p_rho,ord=2)/nx; if L2_rho<1.99: - disp(['Matlab Warning: L2_rho = ',L2_rho,' in Shunn 3 MMS temporal order']) + disp(['Python Warning: L2_rho = ',L2_rho,' in Shunn 3 MMS temporal order']) L2_Z = np.linalg.norm(p_Z,ord=2)/nx; if L2_Z<1.99: @@ -139,11 +139,10 @@ # McDermott # 9-4-2013 -# shunn_mms_favreZr.m +# shunn_mms_favreZ.m # # Converted by Floyd # 10-14-2025 -# shunn_mms_favre_error.py r0 = 5. r1 = 1. @@ -244,8 +243,310 @@ def vd2d_mms_rho(x, y, t): FavreZ_error_64 = np.abs(FavreZ[len(FavreZ)-1]-FavreZ_mms)/FavreZ_mms; if FavreZ_error_64 > 0.01: - print('Matlab Warning: FavreZ in shunn3_FavreZ_64 is out of tolerance. Error = ',FavreZ_error_64) + print('Python Warning: FavreZ in shunn3_FavreZ_64 is out of tolerance. Error = ',FavreZ_error_64) +#McDermott +#09-04-2013 +# shunn_mms_error.m +# +# Converted by Floyd +# 10-15-2025 + +r0 = 5. +r1 = 1. +uf = 0.5 +vf = 0.5 +k = 2. +w = 2. +mu = 0.001 +D = 0.001 + +# analytical solutions +def vd2d_mms_z (x,y,t) : + numerator = ( 1. + math.sin(math.pi*k*(x-uf*t))*math.sin(math.pi*k*(y-vf*t))*math.cos(math.pi*w*t) ) + denominator = ( (1+r0/r1) + (1-r0/r1)*math.sin(math.pi*k*(x-uf*t))*math.sin(math.pi*k*(y-vf*t))*math.cos(math.pi*w*t) ) + return numerator/denominator + +def vd2d_mms_rho(x,y,t): + value=1./( vd2d_mms_z(x,y,t)/r1 + (1-vd2d_mms_z(x,y,t))/r0 ) + return value + +def vd2d_mms_u(x,y,t): + value = uf + (r1-r0)/vd2d_mms_rho(x,y,t)*(-w/(4.*k))*math.cos(math.pi*k*(x-uf*t))*math.sin(math.pi*k*(y-vf*t))*math.sin(math.pi*w*t) + return value + +def vd2d_mms_v(x,y,t): + value = vf + (r1-r0)/vd2d_mms_rho(x,y,t)*(-w/(4.*k))*math.sin(math.pi*k*(x-uf*t))*math.cos(math.pi*k*(y-vf*t))*math.sin(math.pi*w*t) + return value + +def vd2d_mms_H(x,y,t): + value = 0.5*(vd2d_mms_u(x,y,t)-uf)*(vd2d_mms_v(x,y,t)-vf) + return value + +def vd2d_mms_p(x,y,t) : + vd2d_mms_rho(x,y,t)*(vd2d_mms_H(x,y,t) - 0.5*(vd2d_mms_u(x,y,t)**2 + vd2d_mms_v(x,y,t)**2)) + return value + +L = 2 +nx = np.array([32,64,128,256,512]) +dx = L/nx + +datadir = '../../Verification/Scalar_Analytical_Solution/'; +filename = ['shunn3_32_mms.csv','shunn3_64_mms.csv','shunn3_128_mms.csv','shunn3_256_mms.csv','shunn3_512_mms.csv'] + +skip_case = False + +for i in range(len(filename)): + name = datadir+filename[i] + if not os.path.exists(name): + skip_case = True + print('Error: File ', filename[i], ' does not exist. Skipping case.') + +if skip_case: quit() + +e_r = np.zeros(len(filename)) +e_z = np.zeros(len(filename)) +e_u = np.zeros(len(filename)) +e_H = np.zeros(len(filename)) + +for n in range(len(filename)): + N = nx[n]**2 + + + #print(filename[n]) + M = pd.read_csv(datadir+filename[n],skiprows=1,header=None,names=['1','2','3','4','5','6']) + + T = M.iloc[0,0] + + M = pd.read_csv(datadir+filename[n],skiprows=2,header=None) + + x = np.linspace(-L/2, L/2, nx[n] + 1) + xc = x[:nx[n]]+0.5*dx[n] + yc = xc + + #inialize error arrays + rho_error = np.zeros((nx[n],nx[n])) + + e_r_vec = np.zeros(N) + + z_error = np.zeros((nx[n],nx[n])) + e_z_vec = np.zeros(N) + + u_error = np.zeros((nx[n],nx[n])) + e_u_vec = np.zeros(N) + + H_error = np.zeros((nx[n],nx[n])) + e_H_vec = np.zeros(N) + + p = 0; + for j in range(nx[n]): + for i in range(nx[n]): + rho = M.iloc[p,0] + rho_mms = vd2d_mms_rho(xc[i],yc[j],T) + rho_error[i,j] = rho - rho_mms + e_r_vec[p] = rho_error[i,j] + + z = M.iloc[p,1] + z_mms = vd2d_mms_z(xc[i],yc[j],T) + z_error[i,j] = z - z_mms + e_z_vec[p] = z_error[i,j] + + u = M.iloc[p,2] + u_mms = vd2d_mms_u(x[i+1],yc[j],T) + u_error[i,j] = u - u_mms + e_u_vec[p] = u_error[i,j] + + H = M.iloc[p,4] + H_mms = vd2d_mms_H(xc[i],yc[j],T) + H_error[i,j] = H - H_mms + e_H_vec[p] = H_error[i,j] + + p = p+1 + + e_r[n] = np.linalg.norm(e_r_vec,ord=2)/nx[n] + e_z[n] = np.linalg.norm(e_z_vec,ord=2)/nx[n] + e_u[n] = np.linalg.norm(e_u_vec,ord=2)/nx[n] + e_H[n] = np.linalg.norm(e_H_vec,ord=2)/nx[n] + +# add Git version if file is available +git_file = datadir+'shunn3_256_git.txt' +version_string = fdsplotlib.get_version_string(git_file) + +datalabel=['FDS $\\rho$','FDS $Z$','FDS $u$','FDS $H$','$O$($\\Delta x$)','$O$($\\Delta x^2$)'] + +fig = fdsplotlib.plot_to_fig(x_data=dx, y_data=e_r, marker_style='ro-',plot_type='loglog', + revision_label=version_string,x_min=0.001,x_max=0.1,y_min=1E-6,y_max=0.1, + data_label=datalabel[0], + x_label='$\\Delta x$ (m)', + y_label='$L_2$ Error') + +fdsplotlib.plot_to_fig(x_data=dx, y_data=e_z, marker_style='gs-', + figure_handle=fig, + data_label=datalabel[1]) + +fdsplotlib.plot_to_fig(x_data=dx, y_data=e_u, marker_style='b>-', + figure_handle=fig, + data_label=datalabel[2]) + +fdsplotlib.plot_to_fig(x_data=dx, y_data=e_H, marker_style='c+-', + figure_handle=fig, + data_label=datalabel[3]) + +fdsplotlib.plot_to_fig(x_data=dx, y_data=dx, marker_style='k--', + figure_handle=fig, + data_label=datalabel[4]) + +fdsplotlib.plot_to_fig(x_data=dx, y_data=dx**2, marker_style='k-', + figure_handle=fig, + data_label=datalabel[5]) + +plotname = plotdir + 'shunn_mms_convergence.pdf' +plt.savefig(plotname, format='pdf') +plt.close() + +# check errors +if e_r[len(e_r)-1] > 2e-4: + print('Python Warning: Density in shunn3 is out of tolerance. e_r = ',e_r[len(e_r)-1] ) +if e_z[len(e_z)-1] > 1e-4: + print('Python Warning: Mixture fraction in shunn3 is out of tolerance. e_z = ',e_z[len(e_Z)-1] ) +if e_u[len(e_u)-1] > 3e-5: + print('Python Warning: Velocity in shunn3 is out of tolerance. e_u = ',e_u[len(e_u)-1] ) +if e_H[len(e_H)-1] > 2e-3: + print('Python Warning: Pressure in shunn3 is out of tolerance. e_H = ',e_H[len(e_H)-1] ) + +#Vanella from McDermott +#03-09-2018 +# shunn_CC_mms_error.m +# +# Converted by Floyd +# 10-15-2025 + +nx = np.array([32,64,128,256,320]) +dx = L/nx +ymax=[0.1,1] + +datadir = '../../Verification/Complex_Geometry/' +filename = [['shunn3_32_cc_exp_chm_mms.csv','shunn3_64_cc_exp_chm_mms.csv','shunn3_128_cc_exp_chm_mms.csv', + 'shunn3_256_cc_exp_chm_mms.csv','shunn3_320_cc_exp_chm_mms.csv'], + ['shunn3_32_cc_exp_gdv_mms.csv','shunn3_64_cc_exp_gdv_mms.csv','shunn3_128_cc_exp_gdv_mms.csv','shunn3_256_cc_exp_gdv_mms.csv', + 'shunn3_320_cc_exp_gdv_mms.csv']] +gitname = ['shunn3_256_cc_exp_chm_git.txt','shunn3_256_cc_exp_gdv_git.txt'] +plotname=[ 'shunn_cc_exp_chm_mms_convergence.pdf', 'shunn_cc_exp_gdv_mms_convergence.pdf'] + +skip_case = False + +for i in range(2): + for j in range(len(filename[i])): + name = datadir+filename[i][j] + if not os.path.exists(name): + skip_case = True + print('Error: File ', filename[i][j], ' does not exist. Skipping case.') + +if skip_case: quit() + +for kk in range(2): + for n in range(len(filename[kk])): + N = nx[n]**2 + + #print(filename[n]) + M = pd.read_csv(datadir+filename[kk][n],skiprows=1,header=None,names=['1','2','3','4','5','6']) + + T = M.iloc[0,0] + + M = pd.read_csv(datadir+filename[kk][n],skiprows=2,header=None) + + x = np.linspace(-L/2, L/2, nx[n] + 1) + xc = x[:nx[n]]+0.5*dx[n] + yc = xc + + #inialize error arrays + rho_error = np.zeros((nx[n],nx[n])) + + e_r_vec = np.zeros(N) + + z_error = np.zeros((nx[n],nx[n])) + e_z_vec = np.zeros(N) + + u_error = np.zeros((nx[n],nx[n])) + e_u_vec = np.zeros(N) + + H_error = np.zeros((nx[n],nx[n])) + e_H_vec = np.zeros(N) + + p = 0; + for j in range(nx[n]): + for i in range(nx[n]): + rho = M.iloc[p,0] + rho_mms = vd2d_mms_rho(xc[i],yc[j],T) + rho_error[i,j] = rho - rho_mms + e_r_vec[p] = rho_error[i,j] + + z = M.iloc[p,1] + z_mms = vd2d_mms_z(xc[i],yc[j],T) + z_error[i,j] = z - z_mms + e_z_vec[p] = z_error[i,j] + + u = M.iloc[p,2] + u_mms = vd2d_mms_u(x[i+1],yc[j],T) + u_error[i,j] = u - u_mms + e_u_vec[p] = u_error[i,j] + + H = M.iloc[p,4] + H_mms = vd2d_mms_H(xc[i],yc[j],T) + H_error[i,j] = H - H_mms + e_H_vec[p] = H_error[i,j] + + p = p+1 + + e_r[n] = np.linalg.norm(e_r_vec,ord=2)/nx[n] + e_z[n] = np.linalg.norm(e_z_vec,ord=2)/nx[n] + e_u[n] = np.linalg.norm(e_u_vec,ord=2)/nx[n] + e_H[n] = np.linalg.norm(e_H_vec,ord=2)/nx[n] + + # add Git version if file is available + git_file = datadir+gitname[kk] + version_string = fdsplotlib.get_version_string(git_file) + + datalabel=['FDS $\\rho$','FDS $Z$','FDS $u$','FDS $H$','$O$($\\Delta x$)','$O$($\\Delta x^2$)'] + + fig = fdsplotlib.plot_to_fig(x_data=dx, y_data=e_r, marker_style='ro-',plot_type='loglog', + revision_label=version_string,x_min=0.001,x_max=0.1,y_min=1E-5,y_max=ymax[kk], + data_label=datalabel[0], + x_label='$\\Delta x$ (m)', + y_label='$L_2$ Error') + + fdsplotlib.plot_to_fig(x_data=dx, y_data=e_z, marker_style='gs-', + figure_handle=fig, + data_label=datalabel[1]) + + fdsplotlib.plot_to_fig(x_data=dx, y_data=e_u, marker_style='b>-', + figure_handle=fig, + data_label=datalabel[2]) + + fdsplotlib.plot_to_fig(x_data=dx, y_data=e_H, marker_style='c+-', + figure_handle=fig, + data_label=datalabel[3]) + + fdsplotlib.plot_to_fig(x_data=dx, y_data=dx, marker_style='k--', + figure_handle=fig, + data_label=datalabel[4]) + + fdsplotlib.plot_to_fig(x_data=dx, y_data=dx**2, marker_style='k-', + figure_handle=fig, + data_label=datalabel[5]) + plotfile = plotdir + plotname[kk] + plt.savefig(plotfile, format='pdf') + plt.close() + if(kk==0): + # check errors + if e_r[len(e_r)-1] > 2e-4: + print('Python Warning: Density in shunn3 CC is out of tolerance. e_r = ',e_r[len(e_r)-1] ) + if e_z[len(e_z)-1] > 1e-4: + print('Python Warning: Mixture fraction in shunn3 CC is out of tolerance. e_z = ',e_z[len(e_z)-1] ) + if e_u[len(e_u)-1] > 3e-5: + print('Python Warning: Velocity in shunn3 CC is out of tolerance. e_u = ',e_u[len(e_u)-1] ) + if e_H[len(e_H)-1] > 2e-3: + print('Python Warning: Pressure in shunn3 CC is out of tolerance. e_H = ',e_H[len(e_H)-1] ) \ No newline at end of file diff --git a/Utilities/Python/scripts/spray_pattern.py b/Utilities/Python/scripts/spray_pattern.py new file mode 100644 index 00000000000..b97fef75dab --- /dev/null +++ b/Utilities/Python/scripts/spray_pattern.py @@ -0,0 +1,39 @@ + +# Spray pattern plots are saved to fds/Manuals/FDS_User_Guide/FIGURES/spray_pattern_mu...pdf + +import numpy as np +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +pltdir = '../../Manuals/FDS_User_Guide/FIGURES/' + +b = [0, 5, 10, 100, 1000] +mu = np.array([0, 10, 20]) * np.pi / 180 +mu_str = ['0', '10', '20'] + +phi_min = 0 +phi_max = np.array([22.5, 45, 90]) * np.pi / 180 +phi_str = ['22p5', '45', '90'] +mark = ['k-','r-','g-','m-','c-'] + +for k in range(len(phi_max)): + phi = np.linspace(phi_min, phi_max[k], 1000) + for j in range(len(mu)): + fig = fdsplotlib.plot_to_fig(x_data=[-1,-1], y_data=[-1,-1], + x_min=0, x_max=90, y_min=0, y_max=1.1, + x_label=r'$\phi$ (degrees)', + y_label=r'$f(\phi)$') + + for i in range(len(b)): + f = np.exp(-b[i] * ((phi - mu[j]) / (phi_max[k] - phi_min)) ** 2) + fdsplotlib.plot_to_fig(x_data=phi*180/np.pi, y_data=f, marker_style=mark[i], data_label=r'$\beta=$' + str(b[i]), figure_handle=fig) + + ax = plt.gca() + ax.invert_yaxis() + ax.text(45, 0.1, r'$\mu=$' + str(mu[j]*180/np.pi) + r', $\phi_{\rm max}=$' + str(phi_max[k]*180/np.pi) + ' degrees', fontsize=plot_style['Key_Font_Size']) + + plt.savefig(pltdir + 'spray_pattern_mu_' + mu_str[j] + '_phimax_' + phi_str[k] + '.pdf', format='pdf') + plt.close() + diff --git a/Utilities/Python/scripts/synthetic_eddy_method.py b/Utilities/Python/scripts/synthetic_eddy_method.py new file mode 100644 index 00000000000..2816ccbdc2e --- /dev/null +++ b/Utilities/Python/scripts/synthetic_eddy_method.py @@ -0,0 +1,244 @@ + +# Synthetic Eddy Method + +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +outdir = '../../Verification/Turbulence/' +pltdir = '../../Manuals/FDS_User_Guide/SCRIPT_FIGURES/' + +git_file = outdir + 'sem_flat_leddy_p2_git.txt' +version_string = fdsplotlib.get_version_string(git_file) + + +error_tolerance = 0.01 + +# Flat profile + +M = pd.read_csv(outdir + 'sem_flat_leddy_p2_line.csv', header=1) + +k = M.columns.get_loc('umean') +z = M.iloc[:, k-1].values +umean = M.iloc[:, k].values + +u0 = 1 +uprof = u0 * np.ones(len(z)) + +fig = fdsplotlib.plot_to_fig(x_data=uprof, y_data=z, marker_style='k-', data_label='Prescribed mean', + revision_label=version_string, + x_label='$u$ (m/s)', y_label='$z$ (m)', + x_min=0.4, x_max=1.2, y_min=0, y_max=1) + +fdsplotlib.plot_to_fig(x_data=1.1*uprof, y_data=z, figure_handle=fig, marker_style='k--', data_label='Prescribed rms') +fdsplotlib.plot_to_fig(x_data=0.9*uprof, y_data=z, figure_handle=fig, marker_style='k--', data_label=None) +fdsplotlib.plot_to_fig(x_data=umean, y_data=z, figure_handle=fig, marker_style='b>-', data_label='FDS mean') + +k = M.columns.get_loc('urms') +z = M.iloc[:, k-1].values +urms = M.iloc[:, k].values + +fdsplotlib.plot_to_fig(x_data=umean+urms, y_data=z, figure_handle=fig, marker_style='r--', data_label='FDS rms') +fdsplotlib.plot_to_fig(x_data=umean-urms, y_data=z, figure_handle=fig, marker_style='r--', data_label=None) + +plt.savefig(pltdir + 'sem_flat_leddy_p2.pdf', format='pdf') +plt.close() + +umean_error = np.linalg.norm(umean - uprof) / u0 / len(umean) +if umean_error > error_tolerance: + print(f'Matlab Warning: sem_flat_leddy_p2.fds umean_error = {umean_error}') + +urms_error = np.linalg.norm(umean + urms - 1.1*uprof) / u0 / len(umean) +if urms_error > error_tolerance: + print(f'Matlab Warning: sem_flat_leddy_p2.fds urms_error = {urms_error}') + + +# Parabolic profile + +M = pd.read_csv(outdir + 'sem_par_leddy_p2_line.csv', header=1) + +k = M.columns.get_loc('umean') +z = M.iloc[:, k-1].values +umean = M.iloc[:, k].values + +umax = 1 +h = 0.5 +a = umax / h**2 +uprof = umax - a * (z - h)**2 + +fig = fdsplotlib.plot_to_fig(x_data=uprof, y_data=z, marker_style='k-', data_label='Prescribed mean', + revision_label=version_string, + x_label='$u$ (m/s)', y_label='$z$ (m)', + x_min=0, x_max=1.2, y_min=0, y_max=1) + +fdsplotlib.plot_to_fig(x_data=1.1*uprof, y_data=z, figure_handle=fig, marker_style='k--', data_label='Prescribed rms') +fdsplotlib.plot_to_fig(x_data=0.9*uprof, y_data=z, figure_handle=fig, marker_style='k--', data_label=None) +fdsplotlib.plot_to_fig(x_data=umean, y_data=z, figure_handle=fig, marker_style='b>-', data_label='FDS mean') + +k = M.columns.get_loc('urms') +z = M.iloc[:, k-1].values +urms = M.iloc[:, k].values + +fdsplotlib.plot_to_fig(x_data=umean+urms, y_data=z, figure_handle=fig, marker_style='r--', data_label='FDS rms') +fdsplotlib.plot_to_fig(x_data=umean-urms, y_data=z, figure_handle=fig, marker_style='r--', data_label=None) + +plt.savefig(pltdir + 'sem_par_leddy_p2.pdf', format='pdf') +plt.close() + +umean_error = np.linalg.norm(umean - uprof) / umax / len(umean) +if umean_error > error_tolerance: + print(f'Matlab Warning: sem_par_leddy_p2.fds umean_error = {umean_error}') + +urms_error = np.linalg.norm(umean + urms - 1.1*uprof) / umax / len(umean) +if urms_error > error_tolerance: + print(f'Matlab Warning: sem_par_leddy_p2.fds urms_error = {urms_error}') + +# Atmospheric profile + +M = pd.read_csv(outdir + 'sem_atm_leddy_p2_line.csv', header=1) + +k = M.columns.get_loc('umean') +z = M.iloc[:, k-1].values +umean = M.iloc[:, k].values + +u0 = 1 +z0 = 0.5 +p = 0.3 +uprof = u0 * (z / z0)**p + +fig = fdsplotlib.plot_to_fig(x_data=uprof, y_data=z, marker_style='k-', data_label='Prescribed mean', + revision_label=version_string, + x_label='$u$ (m/s)', y_label='$z$ (m)', + x_min=0, x_max=1.4, y_min=0, y_max=1) + +fdsplotlib.plot_to_fig(x_data=1.1*uprof, y_data=z, figure_handle=fig, marker_style='k--', data_label='Prescribed rms') +fdsplotlib.plot_to_fig(x_data=0.9*uprof, y_data=z, figure_handle=fig, marker_style='k--', data_label=None) +fdsplotlib.plot_to_fig(x_data=umean, y_data=z, figure_handle=fig, marker_style='b>-', data_label='FDS mean') + +k = M.columns.get_loc('urms') +z = M.iloc[:, k-1].values +urms = M.iloc[:, k].values + +fdsplotlib.plot_to_fig(x_data=umean+urms, y_data=z, figure_handle=fig, marker_style='r--', data_label='FDS rms') +fdsplotlib.plot_to_fig(x_data=umean-urms, y_data=z, figure_handle=fig, marker_style='r--', data_label=None) + +plt.savefig(pltdir + 'sem_atm_leddy_p2.pdf', format='pdf') +plt.close() + +umean_error = np.linalg.norm(umean - uprof) / u0 / len(umean) +if umean_error > error_tolerance: + print(f'Matlab Warning: sem_atm_leddy_p2.fds umean_error = {umean_error}') + +urms_error = np.linalg.norm(umean + urms - 1.1*uprof) / u0 / len(umean) +if urms_error > error_tolerance: + print(f'Matlab Warning: sem_atm_leddy_p2.fds urms_error = {urms_error}') + +# RAMP profile + +M = pd.read_csv(outdir + 'sem_ramp_leddy_p2_line.csv', header=1) + +k = M.columns.get_loc('umean') +z = M.iloc[:, k-1].values +umean = M.iloc[:, k].values + +u0 = 1 +uprof = np.zeros(len(z)) +for i in range(len(z)): + if z[i] < 0.5: + uprof[i] = z[i] * 2 * u0 + else: + uprof[i] = (1 - z[i]) * 2 * u0 + +fig = fdsplotlib.plot_to_fig(x_data=uprof, y_data=z, marker_style='k-', data_label='Prescribed mean', + revision_label=version_string, + x_label='$u$ (m/s)', y_label='$z$ (m)', + x_min=0, x_max=1.2, y_min=0, y_max=1) + +fdsplotlib.plot_to_fig(x_data=1.1*uprof, y_data=z, figure_handle=fig, marker_style='k--', data_label='Prescribed rms') +fdsplotlib.plot_to_fig(x_data=0.9*uprof, y_data=z, figure_handle=fig, marker_style='k--', data_label=None) +fdsplotlib.plot_to_fig(x_data=umean, y_data=z, figure_handle=fig, marker_style='b>-', data_label='FDS mean') + +k = M.columns.get_loc('urms') +z = M.iloc[:, k-1].values +urms = M.iloc[:, k].values + +fdsplotlib.plot_to_fig(x_data=umean+urms, y_data=z, figure_handle=fig, marker_style='r--', data_label='FDS rms') +fdsplotlib.plot_to_fig(x_data=umean-urms, y_data=z, figure_handle=fig, marker_style='r--', data_label=None) + +plt.savefig(pltdir + 'sem_ramp_leddy_p2.pdf', format='pdf') +plt.close() + +umean_error = np.linalg.norm(umean - uprof) / u0 / len(umean) +if umean_error > error_tolerance: + print(f'Matlab Warning: sem_ramp_leddy_p2.fds umean_error = {umean_error}') + +urms_error = np.linalg.norm(umean + urms - 1.1*uprof) / u0 / len(umean) +if urms_error > error_tolerance: + print(f'Matlab Warning: sem_ramp_leddy_p2.fds urms_error = {urms_error}') + +# Monin-Obukhov profile at OPEN inflow boundary VELOCITY + +# Expected values +E = pd.read_csv(outdir + 'sem_open_wind_MO_profile.csv', header=0) +z_exp = E['z'].values +u_exp = E['u'].values +T_exp = E['T'].values + +M = pd.read_csv(outdir + 'sem_open_wind_line.csv', header=1) + +z_fds = M['UMEAN-z'].values +u_fds = M['UMEAN'].values +u_fds_rms = M['URMS'].values +T_fds = M['TMEAN'].values +T_fds_rms = M['TRMS'].values + +I = 0.1 # turbulence intensity (I), VEL_RMS=1 m/s, U_REF = 10 m/s from input file + +fig = fdsplotlib.plot_to_fig(x_data=u_exp, y_data=z_exp, marker_style='k>', data_label='Monin-Obukhov profile', + revision_label=version_string, + x_label='$u$ (m/s)', y_label='$z$ (m)', + x_min=0, x_max=12, y_min=0, y_max=10) + +fdsplotlib.plot_to_fig(x_data=(1+I)*u_exp, y_data=z_exp, figure_handle=fig, marker_style='k:', data_label='Prescribed rms') +fdsplotlib.plot_to_fig(x_data=(1-I)*u_exp, y_data=z_exp, figure_handle=fig, marker_style='k:', data_label=None) +fdsplotlib.plot_to_fig(x_data=u_fds, y_data=z_fds, figure_handle=fig, marker_style='b-', data_label='FDS mean') +fdsplotlib.plot_to_fig(x_data=u_fds+u_fds_rms, y_data=z_fds, figure_handle=fig, marker_style='b--', data_label='FDS rms') +fdsplotlib.plot_to_fig(x_data=u_fds-u_fds_rms, y_data=z_fds, figure_handle=fig, marker_style='b--', data_label=None) + +plt.savefig(pltdir + 'sem_open_wind_u_prof.pdf', format='pdf') +plt.close() + +u_ref = 10 +kk = np.where((z_exp < np.max(z_fds)) & (z_exp > np.min(z_fds)))[0] +u_fds_int = np.interp(z_exp[kk], z_fds, u_fds) +umean_error = np.linalg.norm(u_exp[kk] - u_fds_int) / u_ref / len(u_fds_int) +if umean_error > error_tolerance: + print(f'Matlab Warning: sem_open_wind.fds umean_error = {umean_error}') + +u_fds_rms_int = np.interp(z_exp[kk], z_fds, u_fds_rms) +urms_error = np.linalg.norm(u_fds_int + u_fds_rms_int - (1+I)*u_exp[kk]) / u_ref / len(u_fds_rms_int) +if urms_error > error_tolerance: + print(f'Matlab Warning: sem_open_wind.fds urms_error = {urms_error}') + +# Monin-Obukhov profile at OPEN inflow boundary TEMPERATURE + +fig = fdsplotlib.plot_to_fig(x_data=T_exp, y_data=z_exp, marker_style='ko', data_label='Monin-Obukhov profile', + revision_label=version_string, + x_min=19, x_max=20, y_min=0, y_max=10, + x_label=r'$T$ ($^\circ$C)', y_label='$z$ (m)') + +fdsplotlib.plot_to_fig(x_data=T_fds, y_data=z_fds, figure_handle=fig, marker_style='r-', data_label='FDS mean') + +plt.savefig(pltdir + 'sem_open_wind_T_prof.pdf', format='pdf') +plt.close() + +T_ref = 20 + 273 +kk = np.where((z_exp < np.max(z_fds)) & (z_exp > np.min(z_fds)))[0] +T_fds_int = np.interp(z_exp[kk], z_fds, T_fds) +Tmean_error = np.linalg.norm(T_exp[kk] - T_fds_int) / T_ref / len(T_fds_int) +if Tmean_error > error_tolerance: + print(f'Matlab Warning: sem_open_wind.fds Tmean_error = {Tmean_error}') + diff --git a/Utilities/Python/scripts/tree_shapes.py b/Utilities/Python/scripts/tree_shapes.py index 541e740ce50..1cdba0347e7 100644 --- a/Utilities/Python/scripts/tree_shapes.py +++ b/Utilities/Python/scripts/tree_shapes.py @@ -56,6 +56,7 @@ y_max=0.8, data_label='ideal', revision_label=version_string, + plot_title='Initialized bulk density (tree_shapes)', x_label=r'Input volume (m$^3$)', y_label='Tree crown mass (kg)' ) diff --git a/Utilities/Python/scripts/vegetation_absorb.py b/Utilities/Python/scripts/vegetation_absorb.py new file mode 100644 index 00000000000..69f788ab215 --- /dev/null +++ b/Utilities/Python/scripts/vegetation_absorb.py @@ -0,0 +1,15 @@ + +# Convert last row of devc file for WUI/vegetation_absorb into a column to be read by dataplot + +import pandas as pd + +outdir = '../../Verification/WUI/' + +M = pd.read_csv(outdir + 'vegetation_absorb_devc.csv', skiprows=2) + +with open(outdir + 'vegetation_absorb_FDS.csv', 'w', newline='') as fid: + fid.write('mpuv,rad\n') + mpuv = [0.0, 0.1, 0.2, 0.4, 0.8, 1.6] + for i in range(6): + fid.write(f'{mpuv[i]:5.1f},{M.iloc[-1, i+1]:5.2f}\n') + diff --git a/Utilities/Python/scripts/vort2d.py b/Utilities/Python/scripts/vort2d.py new file mode 100644 index 00000000000..32b13fc6fd0 --- /dev/null +++ b/Utilities/Python/scripts/vort2d.py @@ -0,0 +1,160 @@ + +# Generate all plots for the 2D Vortex section of the FDS Verification Guide + +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import fdsplotlib + +plot_style = fdsplotlib.get_plot_style('fds') + +outdir = '../../Verification/NS_Analytical_Solution/' +pltdir = '../../Manuals/FDS_Verification_Guide/SCRIPT_FIGURES/' + +git_file = outdir + 'vort2d_40_git.txt' +version_string = fdsplotlib.get_version_string(git_file) + + +L = 0.3112 +U0 = 35.0 +Rc = 0.01556 +BigGamma = 0.0359157 + +meshsize = [40, 80, 160, 320] +meshname = ['40', '80', '160', '320'] +markers = ['k-','r-','c-','m-'] +DT = 1.1114 * 10**(-4) +FLOWTIME = int(0.3112 / (U0 * DT)) +TIMESTEPS = 4 + +DEVCNUM = np.zeros(4, dtype=int) +STEPSIZE = np.zeros(4) +COUNT = np.zeros((4, TIMESTEPS)) +ERROR = np.zeros((4, TIMESTEPS)) +M = {} + +# Loop over four grid resolutions +for m in range(4): + + DEVCNUM[m] = meshsize[m] // 5 + STEPSIZE[m] = 0.311200 / meshsize[m] + + M[m] = pd.read_csv(outdir + f'vort2d_{meshname[m]}_devc.csv', skiprows=2, header=None) + + # Plot u-velocity at x=0 Data for a Range of Times + + Z0 = STEPSIZE[m] / 2 + Z = np.arange(-2*Rc + Z0, 2*Rc - Z0 + STEPSIZE[m]/2, STEPSIZE[m]) + + fig = fdsplotlib.plot_to_fig(x_data=U0-BigGamma*Z*np.exp(-Z**2/(2*Rc**2))/Rc**2, y_data=Z, marker_style='k-', data_label='Analytical', + x_min=33.5, x_max=36.5, y_min=-0.03, y_max=0.03, + revision_label=version_string, + y_label='$z$ (m)', x_label='$u$ (m/s)') + + # Plot FDS simulation values with + for t in range(TIMESTEPS): + + TIME = FLOWTIME * t + COUNT[m, t] = 0.0 + ERROR[m, t] = 0.0 + UArray = np.zeros(DEVCNUM[m]) + + for k in range(DEVCNUM[m]): + UArray[k] = M[m].iloc[TIME, k+1] + ZVAL = -2*Rc + Z0 + k*STEPSIZE[m] + # Calculate analytical u-velocity values + AxisExact = U0 - BigGamma * ZVAL * np.exp(-ZVAL**2/(2*Rc**2)) / Rc**2 + # Calculate initial error values + ERROR[m, t] = ERROR[m, t] + ((UArray[k] - AxisExact))**2 + COUNT[m, t] = COUNT[m, t] + 1.0 + + ERROR[m, t] = np.sqrt(ERROR[m, t] / COUNT[m, t]) + + # Create plot of u-velocity along a line at x=0 + if t>0: fdsplotlib.plot_to_fig(x_data=UArray, y_data=Z, marker_style=markers[t], data_label=f'Pass {t}', figure_handle=fig) + + plt.savefig(pltdir + f'vort2d_{meshname[m]}_uzgraph.pdf', format='pdf') + plt.close() + + # Plot u-Velocity at a point as a function of time + + T = np.arange(0.0, DT * (FLOWTIME * TIMESTEPS + 1) + DT, DT) + XP = 0.0 + ZP = -2*Rc + Z0 + + # Plot analytical solution (periodic to 6 loops) + PointPlotExact = U0 - BigGamma * ZP * ( + np.exp(-(XP**2 + ZP**2 + (U0**2)*(T**2) - + 2.*U0*XP*T) / (2.*Rc**2)) + + np.exp(-((XP + 1*L)**2 + ZP**2 + (U0**2)*(T**2) - + 2.*U0*(XP + 1*L)*T) / (2*Rc**2)) + + np.exp(-((XP + 2*L)**2 + ZP**2 + (U0**2)*(T**2) - + 2.*U0*(XP + 2*L)*T) / (2*Rc**2)) + + np.exp(-((XP + 3*L)**2 + ZP**2 + (U0**2)*(T**2) - + 2.*U0*(XP + 3*L)*T) / (2*Rc**2)) + + np.exp(-((XP + 4*L)**2 + ZP**2 + (U0**2)*(T**2) - + 2.*U0*(XP + 4*L)*T) / (2*Rc**2)) + + np.exp(-((XP + 5*L)**2 + ZP**2 + (U0**2)*(T**2) - + 2.*U0*(XP + 5*L)*T) / (2*Rc**2)) + + np.exp(-((XP + 6*L)**2 + ZP**2 + (U0**2)*(T**2) - + 2.*U0*(XP + 6*L)*T) / (2*Rc**2))) / Rc**2 + + fig = fdsplotlib.plot_to_fig(x_data=T, y_data=PointPlotExact, marker_style='k-', data_label='Analytical', + x_min=0, x_max=0.037, y_min=34.6, y_max=36, + revision_label=version_string, + x_label='Time (s)', y_label='$u$ (m/s)') + + T_fds = M[m].iloc[:, 0].values + fdsplotlib.plot_to_fig(x_data=T_fds, y_data=M[m].iloc[:,1].values, figure_handle=fig, marker_style='r--', data_label='FDS') + + plt.savefig(pltdir + f'vort2d_{meshname[m]}_upgraph.pdf', format='pdf') + plt.close() + + +# Generate Flow Diagram + +U0 = 0.7 +Min = -0.05 +Max = 0.05 +Step = 0.005 + +X, Z = np.meshgrid(np.arange(Min, Max + Step, Step), np.arange(Min, Max + Step, Step)) +Psi = BigGamma * np.exp(-(X**2 + Z**2) / (2.0 * Rc**2)) +DZ, DX = np.gradient(Psi, Step, Step) +U = U0 + DZ +W = -DX + +fig = fdsplotlib.plot_to_fig(x_data=[-1,-1], y_data=[-1,-1], x_min=Min, x_max=Max, y_min=Min, y_max=Max, + figure_size=(plot_style['Scat_Paper_Width'],plot_style['Scat_Paper_Height']), + plot_size=(plot_style['Scat_Plot_Width'],plot_style['Scat_Plot_Height']), + plot_origin=(plot_style['Scat_Plot_X'],plot_style['Scat_Plot_Y']), + x_label='$x$ (m)', y_label='$z$ (m)', + revision_label=version_string) + +ax = plt.gca() +ax.quiver(X, Z, U, W, scale=20, headwidth=5, headlength=7, headaxislength=6.5) + +plt.savefig(pltdir + 'vort2d_diagram.pdf', format='pdf') +plt.close() + + +# Create convergence plot + +dx = np.array([0.0077800, 0.0038900, 0.0019450, 0.0009725]) +dx2 = np.array([0.0000605, 0.0000151, 0.0000038, 0.0000009]) + +fig = fdsplotlib.plot_to_fig(x_data=dx, y_data=120*dx, marker_style='k--', data_label=r'$O(\delta x)$', + x_min=0.0009, x_max=0.009, y_min=1e-3, y_max=1, + plot_type='loglog', + revision_label=version_string, + x_label='Grid Spacing (m)', + y_label='Error (m/s)') + +fdsplotlib.plot_to_fig(x_data=dx, y_data=4500*dx2, marker_style='k-', data_label=r'$O(\delta x^2)$', figure_handle=fig) +fdsplotlib.plot_to_fig(x_data=dx, y_data=ERROR[0:4,1], marker_style='go-', data_label=r'FDS ($t=0.0089$ s)', figure_handle=fig) +fdsplotlib.plot_to_fig(x_data=dx, y_data=ERROR[0:4,2], marker_style='cv-', data_label=r'FDS ($t=0.0178$ s)', figure_handle=fig) +fdsplotlib.plot_to_fig(x_data=dx, y_data=ERROR[0:4,3], marker_style='r^-', data_label=r'FDS ($t=0.0267$ s)', figure_handle=fig) + +plt.savefig(pltdir + 'vort2d_error.pdf', format='pdf') +plt.close() + diff --git a/Utilities/Python/scripts/water_evap_1_const_gamma.py b/Utilities/Python/scripts/water_evap_1_const_gamma.py new file mode 100644 index 00000000000..62fe3b1879d --- /dev/null +++ b/Utilities/Python/scripts/water_evap_1_const_gamma.py @@ -0,0 +1,129 @@ +# McDermott +# 11-1-2016 +# water_evap_1_const_gamma.py +# +# Convert to python by Floyd +# 10/15/2025 +# +# Calculation of expected values for water_evap_1_const_gamma.fds verification case. +# See fds/Verification/Sprinklers_and_Sprays/water_evap_1_const_gamma.csv + +import os + +# --- Constants --- +H_L = -1.9757398E+004 # J/kg (Latent Heat of Vaporization from problem setup) +R = 8314.472 # Pa * m^3 / (kmol * K) (Universal Gas Constant) +gam = 1.4 # Specific heat ratio (gamma) +P_1 = 101325 # Pa (Initial Pressure) +V = 1 # m^3 (Volume) +T_1 = 200 + 273.15 # K (Initial Gas Temperature) +T_w = 20 + 273.15 # K (Water/Evaporation Temperature - Note: T_w is not used in the final calculation, but is included for completeness) +M_w = 0.01 # kg (Mass of Water evaporated) + +W_a = 28.84834 # kg/kmol (Molecular Weight of Air) +W_w = 18.01528 # kg/kmol (Molecular Weight of Water) + +# --- Ideal Gas Specific Heats (J/(kg*K)) --- +# cv = R/W * 1/(gam-1) +cv_a = R/W_a * 1 / (gam - 1) +cv_w = R/W_w * 1 / (gam - 1) + +# cp = R/W * gam/(gam-1) +cp_a = R/W_a * gam / (gam - 1) +cp_w = R/W_w * gam / (gam - 1) + +# --- Compute Initial State --- +# Ideal gas law: RHO = P * W / (R * T) +RHO_1 = P_1 * W_a / (R * T_1) +# Mass = RHO * V +M_a = RHO_1 * V # Initial mass of air + +# --- Final State Calculation --- + +# Determine final mass fraction of water vapor in gas +Y_w = M_w / (M_a + M_w) +Y_a = 1 - Y_w + +# Compute new mixture molecular weight +# W_mix = 1 / (Y_w/W_w + Y_a/W_a) +W = 1 / (Y_w / W_w + Y_a / W_a) + +# Compute final density +RHO_2 = (M_w + M_a) / V + +# Determine final temperature (T_2) from energy balance (Internal energy is conserved) +# M_a*cv_a*T_1 = M_a*cv_a*T_2 + M_w*cv_w*T_2 - H_L (where H_L is negative) +# T_2 = ( M_a*cv_a*T_1 + H_L ) / (M_a*cv_a + M_w*cv_w) +T_2 = (M_a * cv_a * T_1 + H_L) / (M_a * cv_a + M_w * cv_w) + +# Determine final pressure (P_2) from ideal gas law for the mixture +# P = RHO * R * T / W_mix +P_2 = RHO_2 * R * T_2 / W + +# --- Changes in Properties --- + +# Change in pressure, Pa +dP = P_2 - P_1 + +# Change in gas enthalpy, J (dH = M_mix * cp_mix * T_2 - M_a * cp_a * T_1) +# Since $c_{p,mix} = Y_a c_{p,a} + Y_w c_{p,w}$ and $M_{mix} = M_a + M_w$, this is: +# $dH = (M_a c_{p,a} + M_w c_{p,w}) T_2 - M_a c_{p,a} T_1$ +# NOTE: The formula in the original MATLAB code seems to assume that the water vapor +# is not present in the initial state and contributes to the final enthalpy. +# This assumes the water enters the gas phase at $T_2$. +dH = (M_a * cp_a + M_w * cp_w) * T_2 - M_a * cp_a * T_1 + +# --- Output Results to CSV --- + +# Define output directory path +# This assumes the script is run from a location where the relative path works +# In a real-world scenario, you might want a more robust path handling (e.g., using pathlib) +ddir = '../../Verification/Sprinklers_and_Sprays/' +output_filename = ddir+'water_evap_1_const_gamma.csv' + +# Ensure the directory exists (optional, but good practice) +os.makedirs(os.path.dirname(output_filename), exist_ok=True) + +# Open and write to the file +with open(output_filename, 'w') as fid: + # Header row + header = ['Time', 'Rel. Hum', 'h_gas', 'h_water', 'dens', 'temp', 'pres', 'vapor'] + fid.write(','.join(header) + '\n') + + # Data for time 8 and 10 + # Note: MATLAB's fprintf formatting is used for precision matching + # dH and H_L are converted to kJ (divided by 1000) + # T_2 is converted to Celsius (T_2 - 273.15) + # RHO_2 is delta RHO (RHO_2 - RHO_1) + # M_w is M_w + + # Format strings match: %i, %11.9f, %14.7e, %14.7e, %6.4f, %10.7f, %14.7e, %6.4f + data_format = "{:d},{:11.9f},{:14.7e},{:14.7e},{:6.4f},{:10.7f},{:14.7e},{:6.4f}\n" + + # Line 1: Time = 8 + line_8 = data_format.format( + 8, + 2.109675497, + dH / 1000, + -H_L / 1000, + RHO_2 - RHO_1, + T_2 - 273.15, + dP, + M_w + ) + fid.write(line_8) + + # Line 2: Time = 10 + line_10 = data_format.format( + 10, + 2.109675497, + dH / 1000, + -H_L / 1000, + RHO_2 - RHO_1, + T_2 - 273.15, + dP, + M_w + ) + fid.write(line_10) + +print(f"Calculation complete. Results written to: {output_filename}") \ No newline at end of file diff --git a/Utilities/Python/setup_spyder_env.bat b/Utilities/Python/setup_spyder_env.bat new file mode 100644 index 00000000000..a95aa483a08 --- /dev/null +++ b/Utilities/Python/setup_spyder_env.bat @@ -0,0 +1,113 @@ +@echo off +REM Configure spyder IDE for FDS (WINDOWS) +REM Usage (WINDOWS): +REM 1. Install Python 3.11 or below and add its "python.exe" folder to the PATH +REM 2. Open normal Windows Command prompt +REM 3. call ./setup_spyder_env.bat +REM 4. spyder + + + +setlocal enabledelayedexpansion + +REM === Check for python === +where python >nul 2>nul +if errorlevel 1 ( + set ERROR_MSG=python is not installed or not in PATH + call :ERROR_EXIT +) + +REM === Ensure it's Python 3 === +for /f "delims=" %%v in ('python -c "import sys; print(sys.version_info[0])"') do ( + if not %%v==3 ( + set ERROR_MSG=Python 3 is required but not found + call :ERROR_EXIT + ) +) + +REM === Save current directory and move to .github folder=== +set CURDIR=%cd% +cd /d "%~dp0..\..\.." +if errorlevel 1 ( + set ERROR_MSG=Failed to navigate to repo root + call :ERROR_EXIT +) +set REPOROOT=%cd% +cd /d "%REPOROOT%\fds\.github" +if errorlevel 1 ( + set ERROR_MSG=Directory not found: %REPOROOT%\fds\.github + call :ERROR_EXIT +) + +REM === Create venv if not exists and activate it== +set VENV_DIR=fds_python_env +if not exist "%VENV_DIR%" ( + python -m venv "%VENV_DIR%" + if errorlevel 1 ( + set ERROR_MSG=Failed to create virtual environment + call :ERROR_EXIT + ) +) +if not exist "%VENV_DIR%\Scripts\activate.bat" ( + set ERROR_MSG=Virtual environment activation script not found + call :ERROR_EXIT +) +call "%VENV_DIR%\Scripts\activate.bat" +if errorlevel 1 ( + set ERROR_MSG=Failed to activate virtual environment + call :ERROR_EXIT +) + +REM === Upgrade pip and install requirements === +python -m pip install --upgrade pip +if errorlevel 1 ( + set ERROR_MSG=Failed to upgrade pip + call :ERROR_EXIT +) + +if exist requirements.txt ( + python -m pip install -r requirements.txt + if errorlevel 1 ( + set ERROR_MSG=Failed to install requirements + call :ERROR_EXIT + ) +) + +REM === Install Spyder IDE === +python -m pip install spyder +if errorlevel 1 ( + set ERROR_MSG=Failed to install Spyder + call :ERROR_EXIT +) + +set PYTHONPATH=%REPOROOT%\fds\Utilities\Python;%PYTHONPATH% + +REM === Run test script === +cd /d "%REPOROOT%\fds\Utilities\Python" +if not exist hello_world.py ( + set ERROR_MSG=hello_world.py not found + call :ERROR_EXIT +) + +python hello_world.py +if errorlevel 1 ( + set ERROR_MSG=hello_world.py failed + call :ERROR_EXIT +) + +cd /d "%CURDIR%" + +echo. +echo Python environment setup complete. + +REM === Function-like error handler using variable === +:ERROR_EXIT +if "%ERROR_MSG%"=="" ( + echo +) else ( + echo ***Error: %ERROR_MSG% +) +exit /b 1 + + +endlocal diff --git a/Utilities/Python/setup_spyder_env.sh b/Utilities/Python/setup_spyder_env.sh new file mode 100755 index 00000000000..174e0ca2067 --- /dev/null +++ b/Utilities/Python/setup_spyder_env.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# Configure spyder IDE for FDS +# Usage (Linux and MacOS): +# 1. source ./setup_spyder_env.sh +# 2. spyder + +function error_exit { + echo "***Error: $1" + return 1 +} + +# Check for python3 +if ! command -v python3 >/dev/null 2>&1; then + error_exit "python3 is not installed" +fi + +curdir=$(pwd) +cd "$(dirname "${BASH_SOURCE[0]}")/../../.." || error_exit "Failed to locate repo root" +reporoot=$(pwd) + +# Create and activate virtual environment +cd "$reporoot/fds/.github" || error_exit "Directory not found: $reporoot/fds/.github" +VENV_DIR="fds_python_env" +VENV_BIN="$VENV_DIR/bin" +if [ ! -d "$VENV_DIR" ]; then + python3 -m venv "$VENV_DIR" || error_exit "Failed to create virtual environment" +fi +source "$VENV_BIN/activate" + +# Install requirements +pip install --upgrade pip +pip install -r requirements.txt || error_exit "Failed to install requirements" +pip install spyder + +# Set PYTHONPATH +export PYTHONPATH="$reporoot/fds/Utilities/Python:$PYTHONPATH" + +# Run test script +cd "$reporoot/fds/Utilities/Python" || error_exit "Failed to find script directory" +python hello_world.py || error_exit "hello_world.py failed" + +# Return to original directory +cd "$curdir" + +echo "Python environment setup complete." + diff --git a/Utilities/Scripts/validation_git_stats.py b/Utilities/Scripts/validation_git_stats.py new file mode 100644 index 00000000000..550cf74d67f --- /dev/null +++ b/Utilities/Scripts/validation_git_stats.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python3 + +import os +import sys +import subprocess +import re +import tempfile +from pathlib import Path +import argparse + +def MAKEGITENTRY(DIR, FIREMODELS_ROOT, TEMPDIR): + """ + This function outputs a LaTeX table entry with git information for a validation set. + """ + gitrevisions = os.path.join(TEMPDIR, f'gitrevisions.{os.getpid()}') + + # Collect all git.txt files and sort uniquely + git_txt_pattern = os.path.join(FIREMODELS_ROOT, 'out', DIR, '*git.txt') + + # Use shell to expand glob and collect content + try: + cmd = f'cat {git_txt_pattern} 2> /dev/null | sort -u' + result = subprocess.run(cmd, shell=True, capture_output=True, text=True) + with open(gitrevisions, 'w') as f: + f.write(result.stdout) + except Exception: + # If no files found, create empty file + with open(gitrevisions, 'w') as f: + f.write('') + + # Read first line + gitrev = '' + try: + with open(gitrevisions, 'r') as f: + gitrev = f.readline().strip() + except Exception: + gitrev = '' + + output = '' + if gitrev != '': + # Extract git revision short hash + # awk -F - '{print $(NF-1)}' | sed 's/^g//' + parts = gitrev.split('-') + if len(parts) >= 2: + gitrevshort = parts[-2] + gitrevshort = gitrevshort[1:] if gitrevshort.startswith('g') else gitrevshort + else: + gitrevshort = gitrev + + # Get git date + gitdate = '' + gitdate2 = '' + try: + result = subprocess.run( + ['git', 'show', '-s', '--format=%aD', gitrevshort], + capture_output=True, + text=True, + stderr=subprocess.DEVNULL + ) + if result.returncode == 0 and result.stdout.strip(): + # Parse date: awk '{print $3,$2",",$4}' + date_parts = result.stdout.strip().split() + if len(date_parts) >= 5: + gitdate = f"{date_parts[2]} {date_parts[1]}, {date_parts[3]}" + except Exception: + gitdate = '' + + if gitdate == '': + gitdate = 'undefined' + gitdate2 = '2000000000' + + # Check if ~/FDS-SMV exists + fds_smv_path = os.path.expanduser('~/FDS-SMV') + if os.path.exists(fds_smv_path): + CUR_DIR = os.getcwd() + os.chdir(fds_smv_path) + + # Extract different part of gitrev: awk -F - '{print $4}' | sed 's/^.\{1\}//' + parts = gitrev.split('-') + if len(parts) >= 4: + gitrevshort = parts[3] + gitrevshort = gitrevshort[1:] if len(gitrevshort) > 0 else gitrevshort + + gitdateold = '' + try: + result = subprocess.run( + ['git', 'show', '-s', '--format=%aD', gitrevshort], + capture_output=True, + text=True, + stderr=subprocess.DEVNULL + ) + if result.returncode == 0 and result.stdout.strip(): + date_parts = result.stdout.strip().split() + if len(date_parts) >= 5: + gitdateold = f"{date_parts[2]} {date_parts[1]}, {date_parts[3]}" + except Exception: + gitdateold = '' + + if gitdateold != '': + gitdate = gitdateold + try: + result = subprocess.run( + ['git', 'show', '-s', '--format=%at', gitrevshort], + capture_output=True, + text=True + ) + if result.returncode == 0 and result.stdout.strip(): + gitdate2 = result.stdout.strip().split()[0] + except Exception: + pass + + os.chdir(CUR_DIR) + else: + # Get Unix timestamp + try: + result = subprocess.run( + ['git', 'show', '-s', '--format=%at', gitrevshort], + capture_output=True, + text=True + ) + if result.returncode == 0 and result.stdout.strip(): + gitdate2 = result.stdout.strip().split()[0] + except Exception: + gitdate2 = '' + + # Escape underscores for LaTeX + dir_escaped = DIR.replace('_', '\\_') + output = f"{dir_escaped} & {gitdate} & {gitrev} & {gitdate2} \\\\ \\hline\n" + + # Remove temporary file + try: + os.remove(gitrevisions) + except Exception: + pass + + return output + + +def main(): + """ + Main function that generates the LaTeX table with validation git statistics. + """ + CURRENT_DIR = os.getcwd() + + # Determine repo root + SCRIPTDIR = os.path.dirname(os.path.realpath(__file__)) + os.chdir(os.path.join(SCRIPTDIR, '../../..')) + FIREMODELS_ROOT = os.getcwd() + + # Set up temp directory + TEMPDIR = os.path.join(os.path.expanduser('~'), 'temp') + if not os.path.exists(TEMPDIR): + os.makedirs(TEMPDIR) + + # Set environment variable + os.environ['FIREMODELS_ROOT'] = FIREMODELS_ROOT + + # Parse command line options (kept for backwards compatibility) + parser = argparse.ArgumentParser() + parser.add_argument('-r', dest='IGNORE', help='Ignored parameter for backwards compatibility') + args = parser.parse_args() + + # Change to scripts directory + os.chdir(os.path.join(FIREMODELS_ROOT, 'fds/Utilities/Scripts')) + + # Name and location of output .tex file with validation GIT statistics + OUTPUT_TEX_FILE = os.path.join( + FIREMODELS_ROOT, + 'fds/Manuals/FDS_Validation_Guide/SCRIPT_FIGURES/ScatterPlots/validation_git_stats.tex' + ) + + # Table header + with open(OUTPUT_TEX_FILE, 'w') as f: + f.write("\\begin{longtable}[c]{|l|c|c|}\n") + f.write("\\caption[Validation Git Statistics]{Validation Git statistics for all data sets}\n") + f.write("\\label{validation_git_stats}\n") + f.write("\\\\ \\hline\n") + f.write("Dataset & FDS Revision Date & FDS Revision String\\\\ \\hline \\hline\n") + f.write("\\endfirsthead\n") + f.write("\\hline\n") + f.write("Dataset & FDS Revision Date & FDS Revision String\\\\ \\hline \\hline\n") + f.write("\\endhead\n") + + # Table body + maketable = os.path.join(FIREMODELS_ROOT, 'fds/Validation/Process_All_Output.sh') + CASELIST = os.path.join(TEMPDIR, f'temp.out.{os.getpid()}') + TABLE_ENTRIES = os.path.join(TEMPDIR, f'temp2.out.{os.getpid()}') + + # Extract case list from Process_All_Output.sh + # grep PROCESS $maketable | awk 'BEGIN { FS = " " } ; { print $2 }' | awk '{if(NR>1)print}' + try: + with open(maketable, 'r') as f: + lines = f.readlines() + + cases = [] + line_num = 0 + for line in lines: + if 'PROCESS' in line: + parts = line.strip().split() + if len(parts) >= 2: + line_num += 1 + if line_num > 1: # Skip first match + cases.append(parts[1]) + + with open(CASELIST, 'w') as f: + for case in cases: + f.write(f"{case}\n") + except Exception as e: + # If file doesn't exist or error, create empty caselist + with open(CASELIST, 'w') as f: + f.write('') + + # Process each case and generate table entries + with open(TABLE_ENTRIES, 'w') as outf: + try: + with open(CASELIST, 'r') as inf: + for line in inf: + p = line.strip() + if p: + entry = MAKEGITENTRY(p, FIREMODELS_ROOT, TEMPDIR) + if entry: + outf.write(entry) + except Exception: + pass + + # Sort table entries and append to output file + # cat $TABLE_ENTRIES | sort -n -t '&' -k 4 | awk -F "&" '{ print $1 "&" $2 "&" $3 "\\\\ \\hline"}' + try: + with open(TABLE_ENTRIES, 'r') as f: + entries = f.readlines() + + # Sort by 4th field (numeric, using & as delimiter) + def sort_key(line): + parts = line.split('&') + if len(parts) >= 4: + # Extract numeric value from 4th field + try: + return int(parts[3].strip().split()[0]) + except: + return 0 + return 0 + + sorted_entries = sorted(entries, key=sort_key) + + with open(OUTPUT_TEX_FILE, 'a') as f: + for entry in sorted_entries: + parts = entry.split('&') + if len(parts) >= 4: + # Reconstruct line with first 3 fields + output_line = f"{parts[0]}&{parts[1]}&{parts[2]}\\\\ \\hline\n" + f.write(output_line) + except Exception: + pass + + # Clean up temporary files + try: + os.remove(CASELIST) + except Exception: + pass + try: + os.remove(TABLE_ENTRIES) + except Exception: + pass + + # Table footer + with open(OUTPUT_TEX_FILE, 'a') as f: + f.write("\\end{longtable}\n") + + # Return to original directory + os.chdir(CURRENT_DIR) + + +if __name__ == '__main__': + main() +