Skip to content

Commit

Permalink
Revisions to align with new hydraulics package release
Browse files Browse the repository at this point in the history
  • Loading branch information
EdM44 committed Mar 6, 2024
1 parent 6f5b034 commit bdfe2b6
Show file tree
Hide file tree
Showing 27 changed files with 1,357 additions and 14,920 deletions.
2 changes: 1 addition & 1 deletion 01-units.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ $${1*10^{-6}~m^2/s}*\frac{1 ~ft^2/s}{0.0929~m^2/s}=1.076*10^{-5} ~ft^2/s$$

Another example converts between two quantities in the US system: 100 gallons per minute to cfs:
$${100 ~gpm}*\frac{1 ~cfs}{448.8 ~gpm}=0.223 ~cfs$$
The _units_ package in R can do these conversions and more, and also checks that conversions are permissible (producing an error if incompatible units are used).
The [units](https://cran.r-project.org/package=units) package in R can do these conversions and more, and also checks that conversions are permissible (producing an error if incompatible units are used).

```{r units-ex1, echo=TRUE, collapse=TRUE}
units::units_options(set_units_mode = "symbols")
Expand Down
40 changes: 37 additions & 3 deletions 02-water-properties.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ knitr::opts_chunk$set(
)
```

Fundamental properties of water allow the description of the forces it exerts and how it behaves while in motion. Many were listed in Chapter .
Fundamental properties of water allow the description of the forces it exerts and how it behaves while in motion. A table of these properties can be generated with the [hydraulics](https://cran.r-project.org/package=hydraulics) package using a command like `water_table(units = "SI")`.

A summary of basic water properties, which vary with temperature, is shown in Table \@ref(tab:water-props-SI) for SI units and Table \@ref(tab:water-props-Eng) for US (or Eng) units.

Expand All @@ -16,7 +16,25 @@ suppressWarnings(suppressMessages(library(dplyr)))
tbl <- hydraulics::water_table(units = "SI")
unitlist <- sapply(unname(tbl),units::deparse_unit)
colnames <- names(tbl)
tbl <- docxtools::format_engr(units::drop_units(tbl), sigdig = c(0, 4, 4, 4, 4, 4, 3, 3))
tbl <- units::drop_units(tbl)
# Format as integer
cols_we_want = c("Temp")
tbl[, cols_we_want] <- lapply(tbl[, cols_we_want], function (x) {formatdown::format_decimal(x, digits = 0)}
)
# Format with one decimal
cols_we_want = c("Density")
tbl[, cols_we_want] <- lapply(tbl[, cols_we_want], function (x) {formatdown::format_decimal(x, digits = 1)}
)
# Format to 4 digits, omit power of ten notation
#tbl$Density <- formatdown::format_power(tbl$Density, digits = 4, omit_power = c(0, 3))
# Format using power-of-ten notation to 4 significant digits
cols_we_want = c("Spec_Weight", "Viscosity", "Kinem_Visc", "Sat_VP")
tbl[, cols_we_want] <- lapply(tbl[, cols_we_want], function (x) {formatdown::format_power(x, digits = 4, format = "sci", omit_power = c(-1, 4))}
)
# Format using power-of-ten notation to 3 significant digits
cols_we_want = c("Surf_Tens", "Bulk_Mod")
tbl[, cols_we_want] <- lapply(tbl[, cols_we_want], function (x) {formatdown::format_power(x, digits = 3, format = "sci", omit_power = c(-1, 4))}
)
knitr::kable(tbl, col.names = unitlist, align = "c", format = "html",
booktabs = TRUE, caption = "Water properties in SI units") %>%
kableExtra::add_header_above(header = colnames, line = F, align = "c") %>%
Expand All @@ -27,7 +45,23 @@ knitr::kable(tbl, col.names = unitlist, align = "c", format = "html",
tbl <- hydraulics::water_table(units = "Eng")
unitlist <- sapply(unname(tbl),units::deparse_unit)
colnames <- names(tbl)
tbl <- docxtools::format_engr(units::drop_units(tbl), sigdig = c(0, 4, 4, 4, 4, 4, 3, 3))
tbl <- units::drop_units(tbl)
# Format as integer
cols_we_want = c("Temp")
tbl[, cols_we_want] <- lapply(tbl[, cols_we_want], function (x) {formatdown::format_decimal(x, digits = 0)}
)
# Format with one decimal
cols_we_want = c("Density")
tbl[, cols_we_want] <- lapply(tbl[, cols_we_want], function (x) {formatdown::format_decimal(x, digits = 1)}
)
# Format using power-of-ten notation to 4 significant digits
cols_we_want = c("Spec_Weight", "Viscosity", "Kinem_Visc", "Sat_VP")
tbl[, cols_we_want] <- lapply(tbl[, cols_we_want], function (x) {formatdown::format_power(x, digits = 4, format = "sci", omit_power = c(-1, 4))}
)
# Format using power-of-ten notation to 3 significant digits
cols_we_want = c("Surf_Tens", "Bulk_Mod")
tbl[, cols_we_want] <- lapply(tbl[, cols_we_want], function (x) {formatdown::format_power(x, digits = 3, format = "sci", omit_power = c(-1, 4))}
)
knitr::kable(tbl, col.names = unitlist, align = "c", format = "html",
booktabs = TRUE, caption = "Water properties in US units") %>%
kableExtra::add_header_above(header = colnames, line = F, align = "c") %>%
Expand Down
14 changes: 11 additions & 3 deletions 04-pipeflow.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ hydraulics::moody()
Because of the form of the equations, they can sometimes be a challenge to solve, especially by hand. It can help to classify the types of problems based on what variable is unknown. These are summarized in Table \@ref(tab:prob-types).

```{r prob-types, echo=FALSE}
knitr::kable(data.frame(Type=c("1","2","3"), Known=c("Q (or V), D, ks, L","hL, D, ks, L","hL, Q (or V), ks, L"), Unknown=c("hL","Q (or V)","D")), format="pipe", padding=0, escape = F, booktabs = TRUE, caption = "Types of Energy Loss Problems in Pipe Flow")
knitr::kable(data.frame(Type=c("1","2","3"), Known=c("Q (or V), D, ks, L","h~L~, D, k~s~, L","h~L~, Q (or V), ks, L"), Unknown=c("h~L~","Q (or V)","D")), format="pipe", padding=0, escape = F, booktabs = TRUE, caption = "Types of Energy Loss Problems in Pipe Flow")
```

When solving by hand the types in Table \@ref(tab:prob-types) become progressively more difficult, but when using solvers the difference in complexity is subtle.
Expand Down Expand Up @@ -260,17 +260,25 @@ The root is seen to lie very close to D=0.5 m. Repeated trials can home in on th
### Solving for D using an equation solver

An equation solver automatically accomplishes the manual steps of the prior demonstration. The equation from 1.6 can be written as a function that can then be solved for the root, again using _R_ software for the demonstration:
```{r qfcn1, message=FALSE, warning=FALSE}
```{r dfcn1, message=FALSE, warning=FALSE}
q_fcn <- function(D, Q, hf, L, ks, nu, g) {
-2.221 * D^2 * sqrt(( g * D * hf)/L) * log10((ks/D)/3.7 + (1.784 * nu/D) * sqrt(L/(g * D * hf))) - Q
}
```
The _uniroot_ function can solve the equation in R (or use a comparable approach in other software) for a reasonable range of D values
```{r qfcn2, message=FALSE, warning=FALSE}
```{r dfcn2, message=FALSE, warning=FALSE}
ans <- uniroot(q_fcn, interval=c(0.01,4.0),Q=0.416, hf=0.6, L=100, ks=0.000046, nu=1.023053e-06, g=9.81)$root
cat(sprintf("D = %.3f m\n", ans))
```

### Solving for D using an R package

The _hydraulics_ R package implements an equation solving technique like that above to allow the direct solution of Type 3 problems. the prior example is solved using that package as shown beliow.
```{r dfcn3, message=FALSE, warning=FALSE}
ans <- hydraulics::darcyweisbach(Q=0.416, hf=0.6, L=100, ks=0.000046, nu=1.023e-06, ret_units = TRUE, units = c('SI'))
knitr::kable(format(as.data.frame(ans), digits = 3), format = "pipe")
```

## Parallel pipes: solving a system of equations

In the examples above the challenge was often to solve a single implicit equation. The manual iteration approach can work to solve two equations, but as the number of equations increases, especially when using implicit equations, using an equation solver is needed.
Expand Down
28 changes: 16 additions & 12 deletions 05-open_channel.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -269,19 +269,23 @@ where C=20.16 for SI units and C=13.53 for US Customary (English) units.

### Solving the Manning equation for a circular pipe in R

As was demonstrated with pipe flow, a function could be written with Equation \@ref(eq:man-c) and a solver applied to find the value of $\theta$ for the given flow conditions with a known D, S, n and Q. The value for $\theta$ could then be used with Equations \@ref(eq:circg1), \@ref(eq:circg2) and \@ref(eq:circg3) to recover geometric values.
As was demonstrated with pipe flow, a function could be written with Equation \@ref(eq:man-c) and a solver applied to find the value of $\theta$ for the given flow conditions with a known _D_, _S_, _n_ and _Q_. The value for $\theta$ could then be used with Equations \@ref(eq:circg1), \@ref(eq:circg2) and \@ref(eq:circg3) to recover geometric values.

Hydraulic analysis of circular pipes flowing partially full often account for the value of Manning's _n_ varying with depth [@camp_design_1946]; some standards recommend fixed _n_ values, and others require the use of a depth-varying _n_. The _R_ package _hydraulics_ has implemented those routines to enable these calculations, including using a fixed _n_ (the default) or a depth-varing _n_.

The _R_ package _hydraulics_ has implemented those routines to enable these calculations.
For an existing pipe, a common problem is the determination of the depth, _y_ that a given flow _Q_, will have given a pipe diameter _d_, slope _S_ and roughness _n_. Example \@ref(exm:circx1) demonstrates this.

::: {.example #circx1}
Find the uniform (normal) flow depth, y, for a trapezoidal channel with Q=225 ft^3^/s, n=0.016, m=2, b=10 _ft_, S=0.0006.
Find the uniform (normal) flow depth, y, for a trapezoidal channel with Q=225 ft^3^/s, n=0.016, m=2, b=10 _ft_, S=0.0006. Do this assuming both that Manning _n_ is constant with depth and that it varies with depth.
:::
The function _manningc_ from the _hydraulics_ package is used. Any one of the variables in the Manning equation, and related geometric variables, may be treated as an unknown.

```{r manningc-1, message=FALSE, warning=FALSE}
ans <- hydraulics::manningc(Q=0.01, n=0.013, Sf=0.001, d = 0.2, units="SI", ret_units = TRUE)
knitr::kable(format(as.data.frame(ans), digits = 2), format = "pipe", padding=0)
ans2 <- hydraulics::manningc(Q=0.01, n=0.013, Sf=0.001, d = 0.2, n_var = TRUE, units="SI", ret_units = TRUE)
df <- data.frame(Constant_n = unlist(ans), Variable_n = unlist(ans2))
knitr::kable(df, format = "html", digits=3, padding = 0, col.names = c("Constant n","Variable n")) |>
kableExtra::kable_styling(full_width = F)
```

It is also sometimes convenient to see a cross-section diagram.
Expand Down Expand Up @@ -365,9 +369,9 @@ knitr::include_graphics("images/rectangular_channel.png")

A specific energy diagram is very helpful for establishing upstream conditions and estimating $y_2$.

(ref:figopenrect-2) A specific energy diagram for the conditions of Example \@ref(exm:open-rectx).
(ref:figorect-2) A specific energy diagram for the conditions of Example \@ref(exm:open-rectx).

```{r sp_openrect, fig.width = 4, fig.asp = 1.0, fig.align="center", fig.cap='(ref:figopenrect-2)'}
```{r sp-openrect, fig.width = 4, fig.asp = 1.0, fig.align="center", fig.cap='(ref:figorect-2)'}
p1 <- hydraulics::spec_energy_trap( Q = 2.2, b = 0.5, m = 0, y = 2, scale = 2.5, units = "SI" )
p1
```
Expand Down Expand Up @@ -396,16 +400,16 @@ Re(polyroot(c(0.9667, 0, -1.997, 1)))

The negative root is meaningless, the lower positive root is the supercritical depth for $E_2 = 1.997 ~ m$, and the larger positive root is the subcritical depth. Thus the correct solution is $y_2 = 1.64 ~ m$ when the channel bottom rises by 0.25 m.

The specific energy diagram shows that if $\Delta z > E_1 - E_{min}$, the downstream specific energy, $E_2$ would be to the left of the curve, so no feasible solution would exist. At that point damming would occur, raising the upstream depth, $y_1$, and thus increasing $E_1$ until $E_2 = E_{min}$. The largest rise in channel bottom height that will not cause damming is called the critical hump height: $\Delta z_{c} = E_1 - E_{min}$.
A vertical line or other annotation can be added to the specific energy diagram to indicate $E_2$ using _ggplot2_ with a command like `p1 + ggplot2::geom_vline(xintercept = 1.997, linetype=3)`. The _hydraulics_ R package can also add lines to a specific energy diagram for up to two depths:

A vertical can be added to the specific energy diagram to indicate $E_2$:
(ref:figorect-3) A specific energy diagram for the conditions of Example \@ref(exm:open-rectx) with added annotation for when the bottom elecation rises.

```{r spec_energy_diag_2, fig.width = 4, fig.asp = 1.0, fig.align="center", message=FALSE, warning=FALSE}
p1 +
ggplot2::geom_vline(xintercept = 1.997, linetype=3) +
ggplot2::annotate("text", x=1.9, y=2.5, label=expression(E[2]), angle=90)
```{r sp-openrect2, fig.width = 4, fig.asp = 1.0, fig.align="center", fig.cap='(ref:figorect-3)'}
p2 <- hydraulics::spec_energy_trap(Q = 2.2, b = 0.5, m = 0, y = c(2, 1.64), scale = 2.5, units = "SI")
p2
```

The specific energy diagram shows that if $\Delta z > E_1 - E_{min}$, the downstream specific energy, $E_2$ would be to the left of the curve, so no feasible solution would exist. At that point damming would occur, raising the upstream depth, $y_1$, and thus increasing $E_1$ until $E_2 = E_{min}$. The largest rise in channel bottom height that will not cause damming is called the critical hump height: $\Delta z_{c} = E_1 - E_{min}$.

## Gradually varied steady flow {#gvf-section}

Expand Down
Loading

0 comments on commit bdfe2b6

Please sign in to comment.