本ポストはこちらの続きです。

ムーディー線図とは
ムーディー線図(Moody diagram)は、管路の流れについて、管摩擦係数 \(\lambda\) をレイノルズ数 \(Re\) と相対粗度 \(\varepsilon/D_H\) から読み取るための図表です。
使い方は次のとおりです。
- 横軸で \(Re\) の位置を決めます。
- 右側の縦軸の相対粗度 \(\varepsilon/D_H\) に対応する曲線をたどります。
- 曲線上で \(Re\) に対応する点の高さを、左側の縦軸から \(\lambda\) として読みます。
求めた \(\lambda\) は、ダルシー・ワイスバッハの式で管路の損失水頭 \(h_f\) を求める際に利用されます。
\[
\begin{eqnarray}
h_f &=& \lambda\,\frac{L}{D_H}\,\frac{v^2}{2g}
\end{eqnarray}
\tag{1}\]
ここで、各変数の定義は次のとおりです。
- \(h_f\) : 摩擦による損失水頭 [m]
- \(L\) : 管の長さ [m]
- \(v\) : 管内の平均流速 [m/s]
- \(g\) : 重力加速度 [m/s\(^2\)]
\(Re\) は、流体の動粘度 \(\nu\) [m\(^2\)/s] を使って \(Re = v\,D_H/\nu\) と表されます。
ムーディー線図は、流れの状態によって、次の3つの領域に分けて読むことができます。
- 左側の層流域
- 中央の臨界域(灰色の帯)
- 右側の乱流域
層流
\(Re\) が小さい(\(Re \lesssim 2300\))と、流体は管軸に平行な層になって整然と流れます。
この状態を層流といいます。
円管の層流では、\(\lambda\) が次の式で求められます。
\[
\begin{eqnarray}
\lambda &=& \frac{64}{Re}
\end{eqnarray}
\tag{2}\]
式 2 には管壁の粗さ \(\varepsilon\) が含まれていません。
そのため、層流域では相対粗度によらず、1本の直線になります(両対数のグラフでは、傾き \(-1\) の直線です)。
Figure 1 の赤い実線が該当します。
なお、係数の 64 は円管の場合の値で、断面が円でない管では、形状によって別の値になります。
臨界域
層流から乱流へ移り変わる \(2300 \lesssim Re \lesssim 4000\) の範囲を、臨界域といいます(Figure 1 の灰色の帯)。
この範囲では、流れが層流と乱流の間を不規則に行き来するため、\(\lambda\) は一意に決まりません。
コールブルック・ホワイトの式も、この範囲では適用できません。
- 図の赤い破線は、層流の直線 \(\lambda = 64/Re\) を、参考として \(Re = 4000\) まで延ばしたものです。この範囲で実際の \(\lambda\) がこの線に乗るわけではありません。
- 臨界域の境目の値は、正確に決まったものではありません。\(Re = 2300\) は円管で広く使われる目安であり、管の入口の形や外乱の大きさによって、遷移が起こる \(Re\) は変わります。
乱流と滑面管の破線
\(Re \gtrsim 4000\) の乱流域では、相対粗度ごとの曲線が右下がりに描かれ、コールブルック・ホワイトの式で求めた値になります。曲線は、次のように変化します。
- \(Re\) が小さい側
- 管壁のすぐ近くには、粘性が支配する薄い層(粘性底層)ができます。粗さがこの層の中に収まっていれば、粗さの影響は表に出ません。曲線は、後述の滑面管の線に沿って右下がりになります。
- 中間の領域(遷移域)
- \(Re\) が大きくなると粘性底層が薄くなり、粗さの影響が出てきます。曲線は滑面管の線から離れ、\(\lambda\) は \(Re\) にも \(\varepsilon/D_H\) にも依存します。
- \(Re\) が大きい側(完全粗面域)
- 曲線が水平に近づき、\(\lambda\) は \(\varepsilon/D_H\) だけで決まります。粘性の項が無視できるためです。
Figure 1 の黒い破線は滑面管(\(\varepsilon/D_H = 0\)、粗さがない管)の曲線です。コールブルック・ホワイトの式で粗さの項が消えた次の式から求められます。
\[
\begin{eqnarray}
\frac{1}{\sqrt{\lambda}} &=& -2\log_{10}\left(\frac{2.51}{Re\sqrt{\lambda}}\right)
\end{eqnarray}
\tag{3}\]
粗さがある管は、同じ \(Re\) でも滑面管より \(\lambda\) が大きくなります。
そのため、この破線は、すべての曲線の下限になります。
実用的な管でも、\(Re\) が小さい範囲では粗さの影響が小さく、曲線がこの破線にほぼ重なります。
\(4000 < Re < 10^5\) 程度の範囲では、滑面管の \(\lambda\) はブラジウスの式 \[\lambda = 0.3164\,Re^{-1/4} \tag{4}\] で近似できることが知られています。
ムーディー線図の描画
横軸をレイノルズ数 \(Re\)、左側の縦軸を管摩擦係数 \(\lambda\)、右側の縦軸を相対粗度 \(\varepsilon/D_H\) としたムーディー線図を、前回の投稿で定義した colebrook_white() で描きます。
- 乱流域(\(Re \geq 4000\))の曲線は、相対粗度ごとにコールブルック・ホワイトの式から求めます。
- 層流の直線 \(\lambda = 64/Re\) は \(Re = 4000\) まで延ばし、\(Re \leq 2300\) を実線、\(2300 \leq Re \leq 4000\) を破線で描きます。
- 右側の縦軸は、\(Re = 10^8\) における曲線の右端の高さ(\(\lambda\))を、\(\varepsilon/D_H\) に変換して目盛りにしています。そのため、各曲線の右端に、対応する相対粗度の目盛りが並びます。
# コールブルック・ホワイトの式で、4変数のうち未指定の1つを求める関数
# lambda : 管摩擦係数(無次元)
# epsilon: 管の絶対粗度 [m]
# D_H : 管の水力直径 [m]
# Re : レイノルズ数(無次元)
colebrook_white <- function(lambda = NULL, epsilon = NULL, D_H = NULL, Re = NULL) {
# 引数の指定状況を確認する
args <- list(lambda = lambda, epsilon = epsilon, D_H = D_H, Re = Re)
unknown <- names(args)[vapply(args, is.null, logical(1))]
if (length(unknown) != 1L) {
stop("lambda, epsilon, D_H, Re のうち、ちょうど3つを指定してください。")
}
# 指定された値の妥当性を確認する
given <- args[setdiff(names(args), unknown)]
if (!all(vapply(given, is.numeric, logical(1)))) {
stop("すべての引数は数値で指定してください。")
}
if (any(unlist(given) < 0, na.rm = TRUE)) {
stop("負の値は指定できません。")
}
if (any(unlist(given[setdiff(names(given), "epsilon")]) == 0, na.rm = TRUE)) {
stop("lambda, D_H, Re に 0 は指定できません(epsilon のみ 0 を許容します)。")
}
# 管摩擦係数を求める(陰関数のため uniroot で数値的に解く)
# x = 1 / sqrt(lambda) とおき、g(x) = 0 の解を求める
solve_lambda <- function(epsilon, D_H, Re) {
a <- epsilon / (3.71 * D_H) # 相対粗度に由来する項
b <- 2.51 / Re # 粘性に由来する項の係数
if (a >= 1) {
warning("epsilon / D_H が大きすぎるため、解を求められません。")
return(NA_real_)
}
g <- function(x) x + 2 * log10(a + b * x)
x <- uniroot(g, interval = c(1e-6, 1e3), tol = 1e-12)$root
1 / x^2
}
result <- if (identical(unknown, "lambda")) {
# 複数の値を同時に与えた場合も計算できるよう、mapply で要素ごとに解く
mapply(solve_lambda, epsilon, D_H, Re)
} else {
# 陽に解ける3変数は、共通の項 10^(-1/(2*sqrt(lambda))) を使う
s <- sqrt(lambda)
p <- 10^(-1 / (2 * s))
if (identical(unknown, "Re")) {
denom <- s * (p - epsilon / (3.71 * D_H))
invalid <- denom <= 0
value <- 2.51 / denom
} else if (identical(unknown, "epsilon")) {
value <- 3.71 * D_H * (p - 2.51 / (Re * s))
invalid <- value < 0
} else {
# 未指定が D_H の場合
k <- p - 2.51 / (Re * s)
invalid <- k <= 0 | epsilon == 0
value <- epsilon / (3.71 * k)
}
if (any(invalid, na.rm = TRUE)) {
warning(
"与えた3つの値に対して解が存在しない組み合わせがあるため、NA を返します。",
"(lambda が滑面管の値より小さい、または epsilon = 0 のときの D_H など)"
)
value[invalid] <- NA_real_
}
value
}
# 乱流域の外では式の適用範囲を外れるため、注意を促す
re_check <- if (identical(unknown, "Re")) result else Re
if (any(re_check < 4000, na.rm = TRUE)) {
warning("Re が 4000 未満の値を含みます。コールブルック・ホワイトの式は乱流域(Re >= 4000 程度)が対象です。")
}
result
}library(ggplot2)
# 描画の条件
re_max <- 1e8 # 右側の縦軸の基準にするレイノルズ数
rr_values <- c(
1e-5, 2e-5, 5e-5, 1e-4, 2e-4, 2.5e-4, 5e-4, 1e-3, 2e-3, 2.5e-3,
5e-3, 7.5e-3, 1e-2, 1.5e-2, 2e-2, 3e-2, 4e-2, 5e-2
) # 相対粗度 epsilon / D_H
re_turb <- 10^seq(log10(4000), log10(re_max), length.out = 200) # 乱流域のレイノルズ数
re_lam_solid <- 10^seq(log10(600), log10(2300), length.out = 50) # 層流域(実線)のレイノルズ数
re_lam_dash <- 10^seq(log10(2300), log10(4000), length.out = 50) # 臨界域(破線)のレイノルズ数
# 相対粗度ごとの曲線(D_H = 1 とすれば epsilon が相対粗度になる)
curves <- do.call(rbind, lapply(rr_values, function(rr) {
data.frame(
Re = re_turb,
lambda = colebrook_white(epsilon = rr, D_H = 1, Re = re_turb),
rr = rr
)
}))
# 滑面管の曲線(epsilon = 0)と、層流の直線(lambda = 64 / Re)
smooth <- data.frame(Re = re_turb, lambda = colebrook_white(epsilon = 0, D_H = 1, Re = re_turb))
laminar_solid <- data.frame(Re = re_lam_solid, lambda = 64 / re_lam_solid)
laminar_dash <- data.frame(Re = re_lam_dash, lambda = 64 / re_lam_dash)
# 右側の縦軸用の変換: Re = re_max での lambda から epsilon / D_H を求める
lambda_to_rr <- function(lambda) {
suppressWarnings(colebrook_white(lambda = lambda, D_H = 1, Re = re_max))
}
p <- ggplot() +
# 臨界域(層流から乱流への遷移域)
annotate("rect", xmin = 2300, xmax = 4000, ymin = 0.006, ymax = 0.11, fill = "grey80", alpha = 0.5) +
annotate("text", x = sqrt(2300 * 4000), y = 0.0068, label = "臨界域", size = 3.5) +
annotate("text", x = sqrt(2300 * 4000), y = 0.065, label = "Re = 2300〜4000", size = 3, angle = 90) +
# 相対粗度ごとの曲線
geom_line(data = curves, aes(x = Re, y = lambda, group = rr), colour = "steelblue", linewidth = 0.5) +
# 滑面管
geom_line(data = smooth, aes(x = Re, y = lambda), colour = "black", linetype = "dashed", linewidth = 0.6) +
annotate("text", x = 3e6, y = 0.0072, label = "滑面管", size = 3.5, hjust = 0) +
# 層流
geom_line(data = laminar_solid, aes(x = Re, y = lambda), colour = "firebrick", linewidth = 0.8) +
geom_line(data = laminar_dash, aes(x = Re, y = lambda), colour = "firebrick", linewidth = 0.8, linetype = "dashed") +
annotate("text", x = 640, y = 0.02, label = "層流\nλ=64/Re", size = 3.2, hjust = 0, colour = "firebrick") +
scale_x_log10(
breaks = 10^(3:8), # 目盛りの文字は 10^n の位置だけにする
minor_breaks = as.vector(outer(1:9, 10^(2:7))), # 1〜9 x 10^n の位置に補助線を引く
labels = function(x) parse(text = paste0("10^", round(log10(x)))), # 指数表記(10^3, 10^4, ...)
limits = c(600, re_max),
expand = c(0, 0)
) +
scale_y_log10(
breaks = c(0.006, 0.008, 0.01, 0.015, 0.02, 0.03, 0.04, 0.05, 0.06, 0.08, 0.1),
labels = function(x) format(x, scientific = FALSE, trim = TRUE),
limits = c(0.006, 0.11),
oob = scales::oob_keep,
expand = c(0, 0),
sec.axis = sec_axis(
lambda_to_rr,
name = expression(paste("相対粗度 ", epsilon / D[H])), # 数式表記(添え字の H を下付きにする)
breaks = rr_values,
labels = function(x) format(x, scientific = FALSE, trim = TRUE, drop0trailing = TRUE)
)
) +
labs(
title = "ムーディー線図(コールブルック・ホワイトの式)",
x = "レイノルズ数 Re",
y = "管摩擦係数 λ"
) +
theme_bw() +
theme(
panel.grid.minor.x = element_line(linewidth = 0.2, colour = "grey90"),
panel.grid.minor.y = element_blank(),
axis.text.y.right = element_text(size = 8)
)
print(p)計算した管摩擦係数のプロット
colebrook_white() で求めた \(\lambda\) を、ムーディー線図(p)に重ねて描きます。
水が流れる円管を3つ想定し、流速から \(Re\) を求めたうえで、\(\lambda\) を計算します。
- 動粘度は、水(約20℃)の値 \(\nu = 1.0\times10^{-6}\) m\(^2\)/s としています。
- 円管の水力直径 \(D_H\) は、管の内径に等しくなります。
\[
\begin{eqnarray}
Re &=& \frac{v\,D_H}{\nu}
\end{eqnarray}
\]
ここで、\(v\) は管内の平均流速 [m/s]、\(\nu\) は流体の動粘度 [m\(^2\)/s] です。
# 計算する条件(水が流れる円管の例)
cases <- data.frame(
name = c("A: 鋼管", "B: 塩ビ管", "C: コンクリート管"),
epsilon = c(0.045e-3, 0.0015e-3, 1e-3), # 絶対粗度 [m]
D_H = c(0.1, 0.05, 0.5), # 水力直径(満水の円管では内径に等しい) [m]
v = c(2, 1, 3), # 平均流速 [m/s]
nu = 1.0e-6 # 水の動粘度 [m^2/s]
)
# レイノルズ数、相対粗度、管摩擦係数を求める
cases$Re <- cases$v * cases$D_H / cases$nu
cases$rr <- cases$epsilon / cases$D_H
cases$lambda <- colebrook_white(epsilon = cases$epsilon, D_H = cases$D_H, Re = cases$Re)
cases$label <- sprintf(
"%s\nRe = %s\nλ = %.4f",
cases$name, format(cases$Re, big.mark = ",", scientific = FALSE, trim = TRUE), cases$lambda
)
print(cases[, c("name", "epsilon", "D_H", "v", "Re", "rr", "lambda")])
# ラベルの位置(A, B, C の順)。重ならないように、1つずつ指定する
# A, B は曲線の下側の空いている場所に、各点の縦の補助線に沿わせて置く
cases$label_x <- cases$Re * c(1.1, 0.9, 1.2) # ラベルの横位置(Re の 1.1 倍など)
cases$label_y <- c(0.0145, 0.0165, cases$lambda[3] * 1.25) # ラベルの縦位置
cases$label_hjust <- c(0, 1, 0) # 0: ラベルの左端を合わせる、1: 右端を合わせる
# 各条件の相対粗度に対応する曲線(ムーディー線図の曲線の間を補う)
curves_cases <- do.call(rbind, lapply(seq_len(nrow(cases)), function(i) {
data.frame(
Re = re_turb,
lambda = colebrook_white(epsilon = cases$rr[i], D_H = 1, Re = re_turb),
name = cases$name[i]
)
}))
p2 <- p +
# 各条件の曲線
geom_line(data = curves_cases, aes(x = Re, y = lambda, group = name), colour = "darkorange", linewidth = 0.5) +
# 点から左側の縦軸と横軸へ、読み取り用の補助線
geom_segment(
data = cases, aes(x = 600, xend = Re, y = lambda, yend = lambda),
colour = "grey40", linetype = "dotted"
) +
geom_segment(
data = cases, aes(x = Re, xend = Re, y = 0.006, yend = lambda),
colour = "grey40", linetype = "dotted"
) +
# 計算した点とラベル
geom_point(data = cases, aes(x = Re, y = lambda), colour = "red", size = 3) +
geom_label(
data = cases, aes(x = label_x, y = label_y, label = label, hjust = label_hjust),
size = 3, fill = "white"
)
print(p2) name epsilon D_H v Re rr lambda
1 A: 鋼管 4.5e-05 0.10 2 200000 0.00045 0.01855374
2 B: 塩ビ管 1.5e-06 0.05 1 50000 0.00003 0.02099938
3 C: コンクリート管 1.0e-03 0.50 3 1500000 0.00200 0.02352880以上です。


