{"id":13636759,"url":"https://github.com/cpmech/russell","last_synced_at":"2025-04-09T07:05:41.331Z","repository":{"id":38326504,"uuid":"378760572","full_name":"cpmech/russell","owner":"cpmech","description":"Rust Scientific Libary. ODE and DAE (Runge-Kutta) solvers. Special functions (Bessel, Elliptic, Beta, Gamma, Erf). Linear algebra. Sparse solvers (MUMPS, UMFPACK). Probability distributions. Tensor calculus.","archived":false,"fork":false,"pushed_at":"2024-09-29T06:56:23.000Z","size":7568,"stargazers_count":112,"open_issues_count":0,"forks_count":8,"subscribers_count":10,"default_branch":"main","last_synced_at":"2024-10-30T03:43:07.070Z","etag":null,"topics":["bessel-function","differential-equations","eigenvalues","eigenvectors","gamma-function","interpolation","linear-algebra","mathematics","numerical-derivatives","numerical-integration","quadrature","quadrature-integration","rust","scientific-computing","sparse-matrix","special-functions","spectral-methods"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cpmech.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-20T23:46:55.000Z","updated_at":"2024-10-22T16:26:28.000Z","dependencies_parsed_at":"2024-01-08T01:49:32.017Z","dependency_job_id":"0d078d1b-3bd8-4131-8615-b9d01fb6a160","html_url":"https://github.com/cpmech/russell","commit_stats":{"total_commits":2729,"total_committers":1,"mean_commits":2729.0,"dds":0.0,"last_synced_commit":"72356b9df436b01da56f6767682864d5457e6494"},"previous_names":[],"tags_count":134,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cpmech%2Frussell","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cpmech%2Frussell/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cpmech%2Frussell/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cpmech%2Frussell/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cpmech","download_url":"https://codeload.github.com/cpmech/russell/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247994119,"owners_count":21030050,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bessel-function","differential-equations","eigenvalues","eigenvectors","gamma-function","interpolation","linear-algebra","mathematics","numerical-derivatives","numerical-integration","quadrature","quadrature-integration","rust","scientific-computing","sparse-matrix","special-functions","spectral-methods"],"created_at":"2024-08-02T00:01:04.951Z","updated_at":"2025-04-09T07:05:41.304Z","avatar_url":"https://github.com/cpmech.png","language":"Rust","readme":"# Russell - Rust Scientific Library \u003c!-- omit from toc --\u003e \n\n\u003ch1 align=\"center\"\u003e\n  \u003ca href=\"https://github.com/cpmech/russell\"\u003e\u003cimg src=\"logo.svg\" alt=\"Russell\" width=\"368px\"\u003e\u003c/a\u003e\n\u003cbr\u003e\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cb\u003eNumerical mathematics, ordinary differential equations, special math functions, high-performance (sparse) linear algebra\u003c/b\u003e\u003cbr /\u003e\n\u003c/p\u003e\n\n---\n\n[![codecov](https://codecov.io/gh/cpmech/russell/graph/badge.svg?token=PQWSKMZQXT)](https://codecov.io/gh/cpmech/russell)\n[![Track Awesome List](https://www.trackawesomelist.com/badge.svg)](https://www.trackawesomelist.com/rust-unofficial/awesome-rust/)\n\n---\n\n[![Test \u0026 Coverage](https://github.com/cpmech/russell/actions/workflows/test_and_coverage.yml/badge.svg)](https://github.com/cpmech/russell/actions/workflows/test_and_coverage.yml)\n[![Test with local libs](https://github.com/cpmech/russell/actions/workflows/test_with_local_libs.yml/badge.svg)](https://github.com/cpmech/russell/actions/workflows/test_with_local_libs.yml)\n[![Test with Intel MKL](https://github.com/cpmech/russell/actions/workflows/test_with_intel_mkl.yml/badge.svg)](https://github.com/cpmech/russell/actions/workflows/test_with_intel_mkl.yml)\n[![Test on Arch Linux](https://github.com/cpmech/russell/actions/workflows/test_on_arch_linux.yml/badge.svg)](https://github.com/cpmech/russell/actions/workflows/test_on_arch_linux.yml)\n[![Test on Rocky Linux](https://github.com/cpmech/russell/actions/workflows/test_on_rocky_linux.yml/badge.svg)](https://github.com/cpmech/russell/actions/workflows/test_on_rocky_linux.yml)\n[![Test on macOS](https://github.com/cpmech/russell/actions/workflows/test_on_macos.yml/badge.svg)](https://github.com/cpmech/russell/actions/workflows/test_on_macos.yml)\n\n---\n\n[![documentation: lab](https://img.shields.io/badge/russell_lab-documentation-blue)](https://docs.rs/russell_lab)\n[![documentation: ode](https://img.shields.io/badge/russell_ode-documentation-blue)](https://docs.rs/russell_ode)\n[![documentation: sparse](https://img.shields.io/badge/russell_sparse-documentation-blue)](https://docs.rs/russell_sparse)\n[![documentation: stat](https://img.shields.io/badge/russell_stat-documentation-blue)](https://docs.rs/russell_stat)\n[![documentation: tensor](https://img.shields.io/badge/russell_tensor-documentation-blue)](https://docs.rs/russell_tensor)\n\n---\n\n## Contents \u003c!-- omit from toc --\u003e \n\n- [Introduction](#introduction)\n- [Installation](#installation)\n  - [Debian/Ubuntu Linux](#debianubuntu-linux)\n  - [Rocky Linux](#rocky-linux)\n  - [Arch Linux](#arch-linux)\n  - [macOS](#macos)\n  - [Optional feature \"local\\_suitesparse\"](#optional-feature-local_suitesparse)\n  - [Optional feature \"with\\_mumps\"](#optional-feature-with_mumps)\n  - [Optional feature \"intel\\_mkl\"](#optional-feature-intel_mkl)\n  - [Number of threads](#number-of-threads)\n- [🌟 Examples](#-examples)\n  - [(lab) Numerical integration (quadrature)](#lab-numerical-integration-quadrature)\n  - [(lab) Solution of PDEs using spectral collocation](#lab-solution-of-pdes-using-spectral-collocation)\n  - [(lab) Matrix visualization](#lab-matrix-visualization)\n  - [(lab) Singular value decomposition](#lab-singular-value-decomposition)\n  - [(lab) Cholesky factorization](#lab-cholesky-factorization)\n  - [(lab) Solution of a (dense) linear system](#lab-solution-of-a-dense-linear-system)\n  - [(lab) Reading table-formatted data files](#lab-reading-table-formatted-data-files)\n  - [(sparse) Solution of a sparse linear system](#sparse-solution-of-a-sparse-linear-system)\n  - [(ode) Solution of the Brusselator ODE](#ode-solution-of-the-brusselator-ode)\n  - [(ode) Solution of the Brusselator PDE](#ode-solution-of-the-brusselator-pde)\n  - [(stat) Generate the Frechet distribution](#stat-generate-the-frechet-distribution)\n  - [(tensor) Allocate second-order tensors](#tensor-allocate-second-order-tensors)\n- [Roadmap](#roadmap)\n\n\n\n## Introduction\n\n**Russell** (Rust Scientific Library) assists in developing high-performance computations involving linear algebra, sparse linear systems, differential equations, statistics, and continuum mechanics using the Rust programming language. The applications built with Russell revolve around the computational mechanics discipline; however, since Russell deals with fundamental mathematics and numerics, it is also helpful for other disciplines.\n\nRussell aims to deliver efficient, reliable, and easy-to-maintain code. Thus, Russell implements several unit and integration tests and requires test coverage to be over 95%. For the sake of code maintenance, Russell avoids overcomplicated Rust constructions. Nonetheless, Russell considers a good range of Rust concepts, such as generics and traits, and convenient/powerful constructs, such as enums, options, and results. Another goal of Russell is to publish examples of all computations in the documentation to assist the user/developer.\n\nAvailable libraries:\n\n- [![Crates.io](https://img.shields.io/crates/v/russell_lab.svg)](https://crates.io/crates/russell_lab) [russell_lab](https://github.com/cpmech/russell/tree/main/russell_lab) Scientific laboratory with special math functions, linear algebra, interpolation, quadrature, numerical derivation, and more\n- [![Crates.io](https://img.shields.io/crates/v/russell_ode.svg)](https://crates.io/crates/russell_ode) [russell_ode](https://github.com/cpmech/russell/tree/main/russell_ode) Solvers for ordinary differential equations (ODEs) and differential algebraic equations (DAEs) \n- [![Crates.io](https://img.shields.io/crates/v/russell_sparse.svg)](https://crates.io/crates/russell_sparse) [russell_sparse](https://github.com/cpmech/russell/tree/main/russell_sparse) Solvers for large sparse linear systems (wraps MUMPS and UMFPACK)\n- [![Crates.io](https://img.shields.io/crates/v/russell_stat.svg)](https://crates.io/crates/russell_stat) [russell_stat](https://github.com/cpmech/russell/tree/main/russell_stat) Statistics calculations and (engineering) probability distributions\n- [![Crates.io](https://img.shields.io/crates/v/russell_tensor.svg)](https://crates.io/crates/russell_tensor) [russell_tensor](https://github.com/cpmech/russell/tree/main/russell_tensor) Tensor analysis, calculus, and functions for continuum mechanics\n\n👆 Check the crate version and update your Cargo.toml accordingly. Examples:\n\n```toml\n[dependencies]\nrussell_lab = \"*\"\nrussell_sparse = \"*\"\nrussell_ode = \"*\"\nrussell_stat = \"*\"\nrussell_tensor = \"*\"\n```\n\nAll crates have an option to use [Intel MKL](https://www.intel.com/content/www/us/en/developer/tools/oneapi/onemkl.html) instead of the default [OpenBLAS](https://github.com/OpenMathLib/OpenBLAS). For instance, the `features` keyword may be configured as follows:\n\n\n```toml\n[dependencies]\nrussell_lab = { version = \"*\", features = [\"intel_mkl\"] }\nrussell_sparse = { version = \"*\", features = [\"intel_mkl\"] }\nrussell_ode = { version = \"*\", features = [\"intel_mkl\"] }\nrussell_stat = { version = \"*\", features = [\"intel_mkl\"] }\nrussell_tensor = { version = \"*\", features = [\"intel_mkl\"] }\n```\n\nExternal associated and recommended crates:\n\n- [plotpy](https://github.com/cpmech/plotpy) Plotting tools using Python3/Matplotlib as an engine (for quality graphics)\n- [tritet](https://github.com/cpmech/tritet) Triangle and tetrahedron mesh generators (with Triangle and Tetgen)\n- [gemlab](https://github.com/cpmech/gemlab) Geometry, meshes, and numerical integration for finite element analyses\n\n\n\n## Installation\n\nRussell requires some non-Rust libraries (e.g., [OpenBLAS](https://github.com/OpenMathLib/OpenBLAS), [Intel MKL](https://www.intel.com/content/www/us/en/developer/tools/oneapi/onemkl.html), [MUMPS](https://mumps-solver.org), [SuiteSparse](https://github.com/DrTimothyAldenDavis/SuiteSparse)) to achieve the max performance. These libraries can be installed as explained in each subsection next.\n\nAfter installing the dependencies, you may add each crate using:\n\n```bash\ncargo add russell_lab\ncargo add russell_sparse # etc.\n```\n\n### Debian/Ubuntu Linux\n\nRequired libraries:\n\n```bash\n# install libraries for russell\nsudo apt-get install -y --no-install-recommends \\\n    liblapacke-dev \\\n    libopenblas-dev \\\n    libsuitesparse-dev\n```\n\n### Rocky Linux\n\nRequired libraries:\n\n```bash\n# initialize\ndnf update -y\ndnf install epel-release -y\ncrb enable\n\n# install libraries for russell\ndnf install -y \\\n  lapack-devel \\\n  openblas-devel \\\n  suitesparse-devel\n```\n\n### Arch Linux\n\nRequired libraries:\n\n```bash\n# install libraries for russell\nyay -Y --gendb --noconfirm \u0026\u0026 yay -Y --devel --save\nyay -Syu blas-openblas --noconfirm\nyay -Syu suitesparse --noconfirm\n```\n\n### macOS\n\nFirst, install [Homebrew](https://brew.sh/). Then, run:\n\n```bash\n# install libraries for russell\nbrew install lapack openblas suite-sparse\n```\n\n### Optional feature \"local_suitesparse\"\n\n`russell_sparse` allows the use of a locally compiled SuiteSparse, installed in `/usr/local/include/suitesparse` and `/usr/local/lib/suitesparse`. This option is defined by the `local_suitesparse` feature. The [compile-and-install-suitesparse](https://github.com/cpmech/russell/blob/main/zscripts/compile-and-install-suitesparse.bash) script may be used in this case:\n\n```bash\nbash zscripts/compile-and-install-suitesparse.bash\n```\n\n### Optional feature \"with_mumps\"\n\n`russell_sparse` has an optional feature named `with_mumps` which enables the MUMPS solver. To use this feature, MUMPS needs to be locally compiled first. The [compile-and-install-mumps](https://github.com/cpmech/russell/blob/main/zscripts/compile-and-install-mumps.bash) script may be used in this case:\n\n```bash\nbash zscripts/compile-and-install-mumps.bash\n```\n\n### Optional feature \"intel_mkl\"\n\nTo enable Intel MKL (and disable OpenBLAS), the optional `intel_mkl` feature may be used. In this case SuiteSparse (and MUMPS) must be locally compiled (with Intel MKL). This step can be easily accomplished by the [compile-and-install-suitesparse](https://github.com/cpmech/russell/blob/main/zscripts/compile-and-install-suitesparse.bash) and [compile-and-install-mumps](https://github.com/cpmech/russell/blob/main/zscripts/compile-and-install-mumps.bash) scripts, called with the **mkl** argument. For example:\n\n```bash\nbash zscripts/compile-and-install-suitesparse.bash mkl\nbash zscripts/compile-and-install-mumps.bash mkl\n```\n\n**Warning:** We need to further investigate why the nightly Rust version (1.83) fails to link with Intel MKL on Ubuntu 24.04.1 LTS. The stable version (1.81) works just fine.\n\n### Number of threads\n\nBy default, OpenBLAS will use all available threads, including Hyper-Threads that may worsen the performance. Thus, it is recommended to set the following environment variable:\n\n```bash\nexport OPENBLAS_NUM_THREADS=\u003creal-core-number\u003e\n```\n\nSubstitute `\u003creal-core-number\u003e` with the correct value from your system.\n\nFurthermore, if working on a multi-threaded application where the solver should not be multi-threaded on its own (e.g., running parallel calculations in an optimization tool), you may set:\n\n```bash\nexport OPENBLAS_NUM_THREADS=1\n```\n\n\n\n## 🌟 Examples\n\nSee also:\n\n* [russell_lab/examples](https://github.com/cpmech/russell/tree/main/russell_lab/examples)\n* [russell_sparse/examples](https://github.com/cpmech/russell/tree/main/russell_sparse/examples)\n* [russell_ode/examples](https://github.com/cpmech/russell/tree/main/russell_ode/examples)\n* [russell_stat/examples](https://github.com/cpmech/russell/tree/main/russell_stat/examples)\n* [russell_tensor/examples](https://github.com/cpmech/russell/tree/main/russell_tensor/examples)\n\n\n\n### (lab) Numerical integration (quadrature)\n\nThe code below approximates the area of a semicircle of unitary radius.\n\n```rust\nuse russell_lab::math::PI;\nuse russell_lab::{approx_eq, Quadrature, StrError};\n\nfn main() -\u003e Result\u003c(), StrError\u003e {\n    let mut quad = Quadrature::new();\n    let args = \u0026mut 0;\n    let (a, b) = (-1.0, 1.0);\n    let (area, stats) = quad.integrate(a, b, args, |x, _| Ok(f64::sqrt(1.0 - x * x)))?;\n    println!(\"\\narea = {}\", area);\n    println!(\"\\n{}\", stats);\n    approx_eq(area, PI / 2.0, 1e-13);\n    Ok(())\n}\n```\n\n\n\n### (lab) Solution of PDEs using spectral collocation\n\nThis example illustrates the solution of a 1D PDE using the spectral collocation method. It employs the InterpLagrange struct.\n\n```text\nd²u     du          x\n——— - 4 —— + 4 u = e  + C\ndx²     dx\n\n    -4 e\nC = ——————\n    1 + e²\n\nx ∈ [-1, 1]\n```\n\nBoundary conditions:\n\n```text\nu(-1) = 0  and  u(1) = 0\n```\n\nReference solution:\n\n```text\n        x   sinh(1)  2x   C\nu(x) = e  - ——————— e   + —\n            sinh(2)       4\n```\n\n[See the code](https://github.com/cpmech/russell/tree/main/russell_lab/examples/algo_lorene_1d_pde_spectral_collocation.rs)\n\nResults:\n\n![algo_lorene_1d_pde_spectral_collocation](russell_lab/data/figures/algo_lorene_1d_pde_spectral_collocation.svg)\n\n\n\n### (lab) Matrix visualization\n\nWe can use the fantastic tool named [vismatrix](https://github.com/cpmech/vismatrix/) to visualize the pattern of non-zero values of a matrix. With `vismatrix`, we can click on each circle and investigate the numeric values as well.\n\nThe function `mat_write_vismatrix` writes the input data file for `vismatrix`.\n\n[See the code](https://github.com/cpmech/russell/tree/main/russell_lab/examples/matrix_visualization.rs)\n\nAfter generating the \"dot-smat\" file, run the following command:\n\n```bash\nvismatrix /tmp/russell_lab/matrix_visualization.smat\n```\n\nOutput:\n\n![Matrix visualization](russell_lab/data/figures/matrix_vizualization.png)\n\n\n\n### (lab) Singular value decomposition\n\n```rust\nuse russell_lab::{mat_svd, Matrix, Vector, StrError};\n\nfn main() -\u003e Result\u003c(), StrError\u003e {\n    // set matrix\n    let mut a = Matrix::from(\u0026[\n        [2.0, 4.0],\n        [1.0, 3.0],\n        [0.0, 0.0],\n        [0.0, 0.0],\n    ]);\n\n    // allocate output structures\n    let (m, n) = a.dims();\n    let min_mn = if m \u003c n { m } else { n };\n    let mut s = Vector::new(min_mn);\n    let mut u = Matrix::new(m, m);\n    let mut vt = Matrix::new(n, n);\n\n    // perform SVD\n    mat_svd(\u0026mut s, \u0026mut u, \u0026mut vt, \u0026mut a)?;\n\n    // check S\n    let s_correct = \"┌      ┐\\n\\\n                     │ 5.46 │\\n\\\n                     │ 0.37 │\\n\\\n                     └      ┘\";\n    assert_eq!(format!(\"{:.2}\", s), s_correct);\n\n    // check SVD: a == u * s * vt\n    let mut usv = Matrix::new(m, n);\n    for i in 0..m {\n        for j in 0..n {\n            for k in 0..min_mn {\n                usv.add(i, j, u.get(i, k) * s[k] * vt.get(k, j));\n            }\n        }\n    }\n    let usv_correct = \"┌                   ┐\\n\\\n                       │ 2.000000 4.000000 │\\n\\\n                       │ 1.000000 3.000000 │\\n\\\n                       │ 0.000000 0.000000 │\\n\\\n                       │ 0.000000 0.000000 │\\n\\\n                       └                   ┘\";\n    assert_eq!(format!(\"{:.6}\", usv), usv_correct);\n    Ok(())\n}\n```\n\n\n\n### (lab) Cholesky factorization\n\n```rust\nuse russell_lab::*;\n\nfn main() -\u003e Result\u003c(), StrError\u003e {\n    // set matrix (full)\n    #[rustfmt::skip]\n    let a_full = Matrix::from(\u0026[\n        [ 3.0, 0.0,-3.0, 0.0],\n        [ 0.0, 3.0, 1.0, 2.0],\n        [-3.0, 1.0, 4.0, 1.0],\n        [ 0.0, 2.0, 1.0, 3.0],\n    ]);\n\n    // set matrix (lower)\n    #[rustfmt::skip]\n    let mut a_lower = Matrix::from(\u0026[\n        [ 3.0, 0.0, 0.0, 0.0],\n        [ 0.0, 3.0, 0.0, 0.0],\n        [-3.0, 1.0, 4.0, 0.0],\n        [ 0.0, 2.0, 1.0, 3.0],\n    ]);\n\n    // set matrix (upper)\n    #[rustfmt::skip]\n    let mut a_upper = Matrix::from(\u0026[\n        [3.0, 0.0,-3.0, 0.0],\n        [0.0, 3.0, 1.0, 2.0],\n        [0.0, 0.0, 4.0, 1.0],\n        [0.0, 0.0, 0.0, 3.0],\n    ]);\n\n    // perform Cholesky factorization (lower)\n    mat_cholesky(\u0026mut a_lower, false)?;\n    let l = \u0026a_lower;\n\n    // perform Cholesky factorization (upper)\n    mat_cholesky(\u0026mut a_upper, true)?;\n    let u = \u0026a_upper;\n\n    // check:  l ⋅ lᵀ = a\n    let m = a_full.nrow();\n    let mut l_lt = Matrix::new(m, m);\n    for i in 0..m {\n        for j in 0..m {\n            for k in 0..m {\n                l_lt.add(i, j, l.get(i, k) * l.get(j, k));\n            }\n        }\n    }\n    mat_approx_eq(\u0026l_lt, \u0026a_full, 1e-14);\n\n    // check:   uᵀ ⋅ u = a\n    let mut ut_u = Matrix::new(m, m);\n    for i in 0..m {\n        for j in 0..m {\n            for k in 0..m {\n                ut_u.add(i, j, u.get(k, i) * u.get(k, j));\n            }\n        }\n    }\n    mat_approx_eq(\u0026ut_u, \u0026a_full, 1e-14);\n    Ok(())\n}\n```\n\n\n\n### (lab) Solution of a (dense) linear system\n\n```rust\nuse russell_lab::{solve_lin_sys, Matrix, Vector, StrError};\n\nfn main() -\u003e Result\u003c(), StrError\u003e {\n    // set matrix and right-hand side\n    let mut a = Matrix::from(\u0026[\n        [1.0,  3.0, -2.0],\n        [3.0,  5.0,  6.0],\n        [2.0,  4.0,  3.0],\n    ]);\n    let mut b = Vector::from(\u0026[5.0, 7.0, 8.0]);\n\n    // solve linear system b := a⁻¹⋅b\n    solve_lin_sys(\u0026mut b, \u0026mut a)?;\n\n    // check\n    let x_correct = \"┌         ┐\\n\\\n                     │ -15.000 │\\n\\\n                     │   8.000 │\\n\\\n                     │   2.000 │\\n\\\n                     └         ┘\";\n    assert_eq!(format!(\"{:.3}\", b), x_correct);\n    Ok(())\n}\n```\n\n\n\n### (lab) Reading table-formatted data files\n\nThe goal is to read the following file (`clay-data.txt`):\n\n```text\n# Fujinomori clay test results\n\n     sr        ea        er   # header\n1.00000  -6.00000   0.10000   \n2.00000   7.00000   0.20000   \n3.00000   8.00000   0.20000   # \u003c\u003c look at this line\n\n# comments plus new lines are OK\n\n4.00000   9.00000   0.40000   \n5.00000  10.00000   0.50000   \n\n# bye\n```\n\nThe code below illustrates how to do it.\n\nEach column (`sr`, `ea`, `er`) is accessible via the `get` method of the [HashMap].\n\n```rust\nuse russell_lab::{read_data, StrError};\nuse std::env;\nuse std::path::PathBuf;\n\nfn main() -\u003e Result\u003c(), StrError\u003e {\n    // get the asset's full path\n    let root = PathBuf::from(env::var(\"CARGO_MANIFEST_DIR\").unwrap());\n    let full_path = root.join(\"data/tables/clay-data.txt\");\n\n    // read the file\n    let data = read_data(\u0026full_path, \u0026[\"sr\", \"ea\", \"er\"])?;\n\n    // check the columns\n    assert_eq!(data.get(\"sr\").unwrap(), \u0026[1.0, 2.0, 3.0, 4.0, 5.0]);\n    assert_eq!(data.get(\"ea\").unwrap(), \u0026[-6.0, 7.0, 8.0, 9.0, 10.0]);\n    assert_eq!(data.get(\"er\").unwrap(), \u0026[0.1, 0.2, 0.2, 0.4, 0.5]);\n    Ok(())\n}\n```\n\n\n\n### (sparse) Solution of a sparse linear system\n\n```rust\nuse russell_lab::*;\nuse russell_sparse::prelude::*;\nuse russell_sparse::StrError;\n\nfn main() -\u003e Result\u003c(), StrError\u003e {\n    // constants\n    let ndim = 5; // number of rows = number of columns\n    let nnz = 13; // number of non-zero values, including duplicates\n\n    // allocate solver\n    let mut umfpack = SolverUMFPACK::new()?;\n\n    // allocate the coefficient matrix\n    //  2  3  .  .  .\n    //  3  .  4  .  6\n    //  . -1 -3  2  .\n    //  .  .  1  .  .\n    //  .  4  2  .  1\n    let mut coo = SparseMatrix::new_coo(ndim, ndim, nnz, Sym::No)?;\n    coo.put(0, 0, 1.0)?; // \u003c\u003c (0, 0, a00/2) duplicate\n    coo.put(0, 0, 1.0)?; // \u003c\u003c (0, 0, a00/2) duplicate\n    coo.put(1, 0, 3.0)?;\n    coo.put(0, 1, 3.0)?;\n    coo.put(2, 1, -1.0)?;\n    coo.put(4, 1, 4.0)?;\n    coo.put(1, 2, 4.0)?;\n    coo.put(2, 2, -3.0)?;\n    coo.put(3, 2, 1.0)?;\n    coo.put(4, 2, 2.0)?;\n    coo.put(2, 3, 2.0)?;\n    coo.put(1, 4, 6.0)?;\n    coo.put(4, 4, 1.0)?;\n\n    // parameters\n    let mut params = LinSolParams::new();\n    params.verbose = false;\n    params.compute_determinant = true;\n\n    // call factorize\n    umfpack.factorize(\u0026mut coo, Some(params))?;\n\n    // allocate x and rhs\n    let mut x = Vector::new(ndim);\n    let rhs = Vector::from(\u0026[8.0, 45.0, -3.0, 3.0, 19.0]);\n\n    // calculate the solution\n    umfpack.solve(\u0026mut x, \u0026coo, \u0026rhs, false)?;\n    println!(\"x =\\n{}\", x);\n\n    // check the results\n    let correct = vec![1.0, 2.0, 3.0, 4.0, 5.0];\n    vec_approx_eq(\u0026x, \u0026correct, 1e-14);\n\n    // analysis\n    let mut stats = StatsLinSol::new();\n    umfpack.update_stats(\u0026mut stats);\n    let (mx, ex) = (stats.determinant.mantissa_real, stats.determinant.exponent);\n    println!(\"det(a) = {:?}\", mx * f64::powf(10.0, ex));\n    println!(\"rcond  = {:?}\", stats.output.umfpack_rcond_estimate);\n    Ok(())\n}\n```\n\n\n\n### (ode) Solution of the Brusselator ODE\n\nThe system is:\n\n```text\ny0' = 1 - 4 y0 + y0² y1\ny1' = 3 y0 - y0² y1\n\nwith  y0(x=0) = 3/2  and  y1(x=0) = 3\n```\n\nSolving with DoPri8 -- 8(5,3):\n\n```rust\nuse russell_lab::StrError;\nuse russell_ode::prelude::*;\n\nfn main() -\u003e Result\u003c(), StrError\u003e {\n    // get the ODE system\n    let (system, x0, mut y0, mut args, y_ref) = Samples::brusselator_ode();\n\n    // final x\n    let x1 = 20.0;\n\n    // solver\n    let params = Params::new(Method::DoPri8);\n    let mut solver = OdeSolver::new(params, system)?;\n\n    // enable dense output\n    let h_out = 0.01;\n    let selected_y_components = \u0026[0, 1];\n    solver.enable_output().set_dense_recording(true, h_out, selected_y_components)?;\n\n    // solve the problem\n    solver.solve(\u0026mut y0, x0, x1, None, Some(\u0026mut out), \u0026mut args)?;\n\n    // print the results and stats\n    println!(\"y_russell     = {:?}\", y0.as_data());\n    println!(\"y_mathematica = {:?}\", y_ref.as_data());\n    println!(\"{}\", solver.stats());\n    Ok(())\n}\n```\n\nA plot of the (dense) solution is shown below:\n\n![Brusselator results: DoPri8](russell_ode/data/figures/brusselator_dopri8.svg)\n\n\n\n### (ode) Solution of the Brusselator PDE\n\nThis example solves the Brusselator PDE described in (Hairer E, Wanner G (2002) Solving Ordinary Differential Equations II Stiff and Differential-Algebraic Problems. Second Revised Edition. Corrected 2nd printing 2002. Springer Series in Computational Mathematics, 614p).\n\nSee the code [brusselator_pde_radau5_2nd.rs](https://github.com/cpmech/russell/tree/main/russell_ode/examples/brusselator_pde_radau5_2nd.rs).\n\nThe results are shown below for the `U` field:\n\n![brusselator_pde_radau5_2nd_u.jpg](russell_ode/data/figures/brusselator_pde_radau5_2nd_u.jpg)\n\nAnd below for the `V` field:\n\n![brusselator_pde_radau5_2nd_v.jpg](russell_ode/data/figures/brusselator_pde_radau5_2nd_v.jpg)\n\nThe code [brusselator_pde_2nd_comparison.rs](https://github.com/cpmech/russell/tree/main/russell_ode/examples/brusselator_pde_2nd_comparison.rs) compares `russell` results with Mathematica results.\n\nThe figure below shows the `russell` (black dashed lines) and Mathematica (red solid lines) results for the `U` field:\n\n![comparison U](russell_ode/data/figures/brusselator_pde_2nd_comparison_t1_u.svg)\n\nThe figure below shows the `russell` (black dashed lines) and Mathematica (red solid lines) results for the `V` field:\n\n![comparison V](russell_ode/data/figures/brusselator_pde_2nd_comparison_t1_v.svg)\n\n\n\n### (stat) Generate the Frechet distribution\n\nCode:\n\n```rust\nuse russell_stat::*;\n\nfn main() -\u003e Result\u003c(), StrError\u003e {\n    // generate samples\n    let mut rng = get_rng();\n    let dist = DistributionFrechet::new(0.0, 1.0, 1.0)?;\n    let nsamples = 10_000;\n    let mut data = vec![0.0; nsamples];\n    for i in 0..nsamples {\n        data[i] = dist.sample(\u0026mut rng);\n    }\n    println!(\"{}\", statistics(\u0026data));\n\n    // text-plot\n    let stations = (0..20).map(|i| (i as f64) * 0.5).collect::\u003cVec\u003cf64\u003e\u003e();\n    let mut hist = Histogram::new(\u0026stations)?;\n    hist.count(\u0026data);\n    println!(\"{}\", hist);\n    Ok(())\n}\n```\n\nSample output:\n\n```text\nmin = 0.11845731988882305\nmax = 26248.036672205748\nmean = 12.268212841918867\nstd_dev = 312.7131690782321\n\n[  0,0.5) | 1370 🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦\n[0.5,  1) | 2313 🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦\n[  1,1.5) | 1451 🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦\n[1.5,  2) |  971 🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦\n[  2,2.5) |  659 🟦🟦🟦🟦🟦🟦🟦🟦\n[2.5,  3) |  460 🟦🟦🟦🟦🟦\n[  3,3.5) |  345 🟦🟦🟦🟦\n[3.5,  4) |  244 🟦🟦🟦\n[  4,4.5) |  216 🟦🟦\n[4.5,  5) |  184 🟦🟦\n[  5,5.5) |  133 🟦\n[5.5,  6) |  130 🟦\n[  6,6.5) |  115 🟦\n[6.5,  7) |  108 🟦\n[  7,7.5) |   70 \n[7.5,  8) |   75 \n[  8,8.5) |   57 \n[8.5,  9) |   48 \n[  9,9.5) |   59 \n      sum = 9008\n```\n\n\n\n### (tensor) Allocate second-order tensors\n\n```rust\nuse russell_tensor::*;\n\nfn main() -\u003e Result\u003c(), StrError\u003e {\n    // general\n    let a = Tensor2::from_matrix(\n        \u0026[\n            [1.0, SQRT_2 * 2.0, SQRT_2 * 3.0],\n            [SQRT_2 * 4.0, 5.0, SQRT_2 * 6.0],\n            [SQRT_2 * 7.0, SQRT_2 * 8.0, 9.0],\n        ],\n        Mandel::General,\n    )?;\n    assert_eq!(\n        format!(\"{:.1}\", a.vec),\n        \"┌      ┐\\n\\\n         │  1.0 │\\n\\\n         │  5.0 │\\n\\\n         │  9.0 │\\n\\\n         │  6.0 │\\n\\\n         │ 14.0 │\\n\\\n         │ 10.0 │\\n\\\n         │ -2.0 │\\n\\\n         │ -2.0 │\\n\\\n         │ -4.0 │\\n\\\n         └      ┘\"\n    );\n\n    // symmetric-3D\n    let b = Tensor2::from_matrix(\n        \u0026[\n            [1.0, 4.0 / SQRT_2, 6.0 / SQRT_2],\n            [4.0 / SQRT_2, 2.0, 5.0 / SQRT_2],\n            [6.0 / SQRT_2, 5.0 / SQRT_2, 3.0],\n        ],\n        Mandel::Symmetric,\n    )?;\n    assert_eq!(\n        format!(\"{:.1}\", b.vec),\n        \"┌     ┐\\n\\\n         │ 1.0 │\\n\\\n         │ 2.0 │\\n\\\n         │ 3.0 │\\n\\\n         │ 4.0 │\\n\\\n         │ 5.0 │\\n\\\n         │ 6.0 │\\n\\\n         └     ┘\"\n    );\n\n    // symmetric-2D\n    let c = Tensor2::from_matrix(\n        \u0026[[1.0, 4.0 / SQRT_2, 0.0], [4.0 / SQRT_2, 2.0, 0.0], [0.0, 0.0, 3.0]],\n        Mandel::Symmetric2D,\n    )?;\n    assert_eq!(\n        format!(\"{:.1}\", c.vec),\n        \"┌     ┐\\n\\\n         │ 1.0 │\\n\\\n         │ 2.0 │\\n\\\n         │ 3.0 │\\n\\\n         │ 4.0 │\\n\\\n         └     ┘\"\n    );\n    Ok(())\n}\n```\n\n\n\n## Roadmap\n\n- [ ] Improve `russell_lab`\n    - [x] Implement more integration tests for linear algebra\n    - [x] Implement more examples\n    - [ ] Implement more benchmarks\n    - [x] Wrap more BLAS/LAPACK functions\n        - [x] Implement dggev, zggev, zheev, and zgeev\n    - [x] Wrap Intel MKL (option for OpenBLAS)\n    - [x] Add more complex number functions\n    - [x] Add fundamental functions to `russell_lab`\n        - [x] Implement the Bessel functions\n        - [x] Implement the modified Bessel functions\n        - [x] Implement the elliptical integral functions\n        - [x] Implement Beta, Gamma and Erf functions (and associated)\n        - [ ] Implement orthogonal polynomial functions\n    - [ ] Implement some numerical methods in `russell_lab`\n        - [x] Implement Brent's solver\n        - [ ] Implement a solver for the cubic equation\n        - [x] Implement numerical derivation\n        - [x] Implement numerical Jacobian function\n        - [ ] Implement line search\n        - [ ] Implement Newton's method for nonlinear systems\n        - [x] Implement numerical quadrature\n        - [ ] Implement multidimensional data interpolation\n    - [ ] Add interpolation and polynomials to `russell_lab`\n        - [x] Implement Chebyshev polynomials\n        - [x] Implement Chebyshev interpolation\n        - [ ] Implement Orthogonal polynomials\n        - [x] Implement Lagrange interpolation\n        - [ ] Implement Fourier interpolation\n- [x] Improve `russell_sparse`\n    - [x] Wrap the KLU solver (in addition to MUMPS and UMFPACK)\n    - [x] Implement the Compressed Sparse Column format (CSC)\n    - [x] Implement the Compressed Sparse Row format (CSC)\n    - [x] Improve the C-interface to UMFPACK and MUMPS\n    - [x] Write the conversion from COO to CSC in Rust\n- [x] Improve `russell_ode`\n    - [x] Implement explicit Runge-Kutta solvers\n    - [x] Implement Radau5 for DAEs\n    - [ ] Implement extrapolation methods\n    - [ ] Implement multi-step methods\n    - [ ] Implement general linear methods\n- [ ] Improve `russell_stat`\n    - [x] Add probability distribution functions\n    - [x] Implement drawing of ASCII histograms\n    - [ ] Implement FORM (first-order reliability method)\n    - [ ] Add more examples\n- [ ] Improve `russell_tensor`\n    - [x] Implement functions to calculate invariants\n    - [x] Implement first and second-order derivatives of invariants\n    - [x] Implement some high-order derivatives\n    - [ ] Implement standard continuum mechanics tensors\n- [ ] General improvements\n    - [x] Compile on macOS\n    - [ ] Study the possibility to install Russell on Windows\n","funding_links":[],"categories":["Libraries","Scientific Computation"],"sub_categories":["Computation"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcpmech%2Frussell","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcpmech%2Frussell","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcpmech%2Frussell/lists"}