DOI: 10.5281/zenodo.17280141
title: Halton, Hammersley, Sobol, and Korobov Distribution of the Data Points from the Colebrook Flow Friction Relation

description: When the Colebrook equation is used in its original implicitly given form, the unknown pipe flow friction factor can only be obtained through time-consuming and computationally demanding iterative calculation. Empirical Colebrook equation relates the unknown Darcy’s friction factor with the known Reynolds number and the relative roughness of inner pipe surface. It is widely used in engineering practice. To simplify computation, a variety of explicit approximations have been developed, whose accuracy must be carefully evaluated. For such purpose, this Data Descriptor gives a sufficient number of pipe flow friction factor values that are computed using a highly accurate iterative algorithm to solve the implicit Colebrook equation. These values serve as reference datasets, spanning the range relevant to engineering applications, and provide benchmarks for evaluating the accuracy of the approximations. The sampling points within the datasets may be distributed randomly, quasi-randomly, or uniformly, in a way that minimizes gaps in the data. In this study, a Python script is used to generate quasi-random samples, including Halton, Hammersley, Korobov, and Sobol, which produce smaller gaps than purely random samples generated for comparison. Using these quasi-random points, a total of 220=1,048,576 data points have been generated, and the corresponding datasets are provided Materials to this Data here. When a smaller subset of points is needed, the required number of initial points from these large sequences can be used directly.

 

import chaospy

import math

import csv

import matplotlib.pyplot as plt

import os

 

def initial_guess_drop_term(eps):

    arg = eps / 3.71

    if arg <= 0:

        raise ValueError("eps must be > 0")

    inv_sqrt_f0 = -0.8686 * math.log(arg)

    if inv_sqrt_f0 <= 0:

        raise ValueError("Computed 1/sqrt(f0) is non-positive (check eps).")

    f0 = 1.0 / (inv_sqrt_f0 * inv_sqrt_f0)

    return f0

 

def colebrook_refine(Re, eps, tol=1e-9, max_iter=100):

    if Re <= 0:

        raise ValueError("Re must be > 0")

    f = initial_guess_drop_term(eps)

 

    for _ in range(max_iter):

        inv_sqrt_f = 1.0 / math.sqrt(f)

        arg = (2.51 / Re) * inv_sqrt_f + eps / 3.71

        if arg <= 0:

            raise ValueError(f"Non-positive argument to log: {arg}")

        rhs = -0.8686 * math.log(arg)

        f_new = 1.0 / (rhs * rhs)

 

        if abs(f_new - f) < tol:

            return f_new

        f = f_new

 

    raise RuntimeError("Colebrook iteration did not converge")

 

def calc_Re(s1):

    return 10 ** (s1 * (math.log10(10 ** 8) - math.log10(4000)) + math.log10(4000))

 

def calc_eps(s2):

    return 10 ** (-(s2 * (6.5 - math.log10(1/0.05)) + math.log10(1/0.05)))

   

def process_samples(samples, method_name):

   

    os.makedirs(method_name, exist_ok=True)

 

    csv_path = os.path.join(method_name, f"{method_name}_results.csv")

    with open(csv_path, "w", newline="") as csvfile:

        writer = csv.writer(csvfile)

        writer.writerow(["x", "y", "Re", "epsilon", "f0"])

 

        for i in range(samples.shape[1]):

            s1, s2 = samples[:, i]

            Re = calc_Re(s1)

            eps = calc_eps(s2)

            f0 = colebrook_refine(Re, eps)

            writer.writerow([s1, s2, Re, eps, f0])

 

    plt.scatter(*samples, s=3, c="red")

    plt.title(method_name)

    plt.xlabel("s1")

    plt.ylabel("s2")

    plt.xlim(0, 1)

    plt.ylim(0, 1)

    plt.grid(True)

 

    plot_path = os.path.join(method_name, f"{method_name}_plot.png")

    plt.savefig(plot_path, dpi=300)

    plt.close()

   

def main():

    uniform_cube = chaospy.J(chaospy.Uniform(0, 1), chaospy.Uniform(0, 1))

    count = 2 ** 20

 

    samples_dict = {

        "halton": uniform_cube.sample(count, rule="halton"),

        "hammersley": uniform_cube.sample(count, rule="hammersley"),

        "korobov": uniform_cube.sample(count, rule="korobov"),

        "sobol": uniform_cube.sample(count, rule="sobol"),

    }

 

    for method, samples in samples_dict.items():

        process_samples(samples, method)

 

if __name__ == "__main__":

    main()