diff-grok - v1.2.0
    Preparing search index...

    diff-grok - v1.2.0

    Diff Grok

    DOI Docs-stable License: MIT Build Status Run tests

    A lightweight TypeScript library for solving initial value problem (IVP) for ordinary differential equations (ODEs) using numerical methods. The primary solvers are LSODA — a variable-order method that automatically detects stiffness and switches between Adams (non-stiff) and BDF (stiff) formulations — and CVODE — a variable-order, variable-step solver from the SUNDIALS suite supporting both Adams and BDF methods.

    • Solving both stiff and non-stiff equations
    • Fast computations
    • Automatic stiffness-detecting method:
      • LSODA - variable-order Nordsieck-based solver with automatic switching between Adams (non-stiff) and BDF (stiff) methods (Petzold, 1983; Hindmarsh, 1983). Ported to TypeScript from the C library liblsoda
    • Variable-order multistep method:
    • Implicit methods (for stiff ODEs) - Rosenbrock–Wanner type:
    • Explicit methods (for non-stiff ODEs):
      • Runge-Kutta type:
        • The Bogacki-Shampine 3(2) method (RK3)
        • The Runge-Kutta-Fehlberg method (RK4)
        • The Dormand-Prince 5(4) method (RKDP)
      • Adams-Bashforth type:
        • The predictor-corrector method of order 4 (AB4)
        • The predictor-corrector method of order 5 (AB5)
    • Scripting:
      • declarative specification of models
      • auto-generated JavaScript code
    • Integration with the Datagrok platform
    • Zero dependencies

    To install via npm:

    npm install diff-grok
    

    Minimal "Hello World" example:

    // example.ts

    import {ODEs, cvode} from 'diff-grok';

    const task: ODEs = {
    name: 'Example',
    arg: {name: 't', start: 0, finish: 1, step: 0.1},
    initial: [1],
    func: (t: number, y: Float64Array, output: Float64Array) => {
    output[0] = y[0] - t;
    },
    tolerance: 1e-7,
    solutionColNames: ['y(t)'],
    };

    const solution = cvode(task);

    console.log('t:', solution[0]);
    console.log('y(t):', solution[1]);

    To find numerical solution of a problem:

    $$\frac{dy}{dt} = f(t, y)$$ $$y(t_{0}) = y_0$$

    on the segment $[t_0, t_1]$ with the step $h$:

    1. Import ODEs and a desired numerical method:

      Automatic method:

      • lsoda - LSODA variable-order solver with automatic switching between Adams (non-stiff) and BDF (stiff)

      Variable-order multistep method:

      • cvode - CVODE variable-order BDF solver from the SUNDIALS suite

      Implicit methods (for stiff ODEs):

      Explicit methods (for non-stiff ODEs) — Runge-Kutta type:

      • rk3 - the Bogacki-Shampine 3(2) method
      • rk4 - the Runge-Kutta-Fehlberg 4(5) method
      • rkdp - the Dormand-Prince 5(4) method

      Explicit methods (for non-stiff ODEs) — Adams-Bashforth type:

      • ab4 - the predictor-corrector method of order 4
      • ab5 - the predictor-corrector method of order 5
    2. Specify ODEs object that defines a problem:

      • name - name of a model

      • arg - independent variable specification. This is in object with fields:

        • name - name of the argument, $t$
        • start - initial value of the argument, $t_0$
        • finish - final value of the argument, $t_1$
        • step - solution grid step, $h$
      • initial - initial values, $y_0$

      • func - right-hand side of the system, $f(t, y)$. This is a function (t: number, y: Float64Array, output: Float64Array) => void:

        • t - value of independent variable $t$
        • y - values of $y$
        • output - output values of $f(t, y)$
      • tolerance - numerical tolerance

      • solutionColNames - names of solutions, i.e. names of the vector $y$ elements

    3. Call numerical method. It returns Float64Array-arrays with values of an argument and approximate solutions.

    Diff Grok is designed to provide fast computations. Check performance for the details.

    Consider the following problem:

    $$\begin{cases} \frac{dx}{dt} = x + y - t \ \frac{dy}{dt} = x y + t \ x(0) = 1 \ y(0) = -1 \end{cases}$$

    To solve it on the segment $[0, 2]$ with the step $0.01$ using LSODA with the tolerance $10^{-7}$, we start with imports:

    import {ODEs, lsoda} from 'diff-grok';
    

    Next, we create

    const task: ODEs = {
    name: 'Example', // name of your model
    arg: {
    name: 't', // name of the argument
    start: 0, // initial value of the argument
    finish: 2, // final value of the argument
    step: 0.01, // solution grid step
    },
    initial: [1, -1], // initial values
    func: (t: number, y: Float64Array, output: Float64Array) => { // right-hand side of the system
    output[0] = y[0] + y[1] - t; // 1-st equation
    output[1] = y[0] * y[1] + t; // 2-nd equation
    },
    tolerance: 1e-7, // tolerance
    solutionColNames: ['x', 'y'], // names of solution functions
    };

    Finally, we call the specified numerical method to solve task:

    const solution = lsoda(task);
    

    Currently, solution contains:

    • solution[0] - values of $t$, i.e. the range $0..2$ with the step $0.01$
    • solution[1] - values of $x(t)$ at the points of this range
    • solution[2] - values of $y(t)$ at the points of the same range

    Find this example in basic-use.ts.

    The following classic problems are used to evaluate efficiency of Diff Grok methods:

    • Rober
      • a stiff system of 3 nonlinear ODEs
      • describes the kinetics of an autocatalytic reaction given by Robertson
      • robertson.ts
    • HIRES
      • a stiff system of 8 non-linear equations
      • explains the `High Irradiance Responses' (HIRES) of photomorphogenesis on the basis of phytochrome, by means of a chemical reaction involving eight reactants
      • hires.ts
    • VDPOL
      • a system of 2 ODEs proposed by B. van der Pol
      • describes the behaviour of nonlinear vacuum tube circuits
      • vdpol.ts
    • OREGO
      • a stiff system of 3 non-linear equations
      • simulates Belousov-Zhabotinskii reaction
      • orego.ts
    • E5
      • a stiff system of 4 non-linear ODEs
      • represents a chemical pyrolysis model
      • e5.ts
    • Pollution
      • a stiff system of 20 non-linear equations
      • describes a chemical reaction part of the air pollution model designed at The Dutch National Institute of Public Health and Environmental Protection
      • pollution.ts

    The LSODA, CVODE, MRT, ROS3PRw and ROS34PRw methods demonstrate the following time performance (AMD Ryzen 5 5600H 3.30 GHz CPU):

    Problem Segment Points Tolerance LSODA, ms CVODE, ms MRT, ms ROS3PRw, ms ROS34PRw, ms
    Rober [0, 10E+11] 40K 1E-7 67 85 175 446 285
    HIRES [0, 321.8122] 32K 1E-10 125 142 122 362 215
    VDPOL [0, 2000] 20K 1E-12 268 352 492 1576 760
    OREGO [0, 360] 36K 1E-8 76 98 205 483 199
    E5 [0, 10E+13] 40K 1E-6 7 * 6 17 8
    Pollution [0, 60] 30K 1E-6 12 15 18 50 23

    * E5 is skipped for CVODE: the extremely stiff rate constants (spanning 20 orders of magnitude) cause convergence failures with the dense direct linear solver.

    Maximum absolute deviations (MADs) from the reference solutions obtained using SciPy (Radau) are summarized in the table below:

    Problem LSODA CVODE MRT ROS3PRw ROS34PRw
    Rober 1.87e-8 1.87e-8 1.87e-8 1.88e-8 1.88e-8
    HIRES 1.51e-11 2.10e-11 4.80e-11 1.05e-14 2.87e-14
    VDPOL 5.12e-4 5.12e-4 5.12e-4 5.12e-4 5.12e-4
    OREGO 3.84e-6 5.20e-6 3.05e-5 3.45e-7 2.31e-6
    E5 3.02e-19 * 1.12e-19 1.33e-19 3.40e-17
    Pollution 1.23e-10 2.15e-10 4.06e-10 9.16e-12 1.58e-10

    Run check-methods.ts to reproduce these results (see here how to run scripts standalone).

    The following charts compare the Diff Grok and Radau solutions for the van der Pol system:

    VDPOL

    The following graphs present a comparison of the Diff Grok and Radau solutions for the Pollution model, highlighting a portion of the functions:

    Pollution

    Gallery

    VDPOL

    VDPOL

    HIRES

    HIRES

    E5

    E5

    POLL

    POLL

    OREGO

    OREGO

    Rober

    ROBER

    Run benchmarks

    Run benchmark models and find the reference solutions via the following links to the Datagrok platform:

    Problem Diff Grok Radau
    Rober ROBER.ivp ROBER.csv
    HIRES HIRES.ivp HIRES.csv
    VDPOL VDPOL.ivp VDPOL.csv
    OREGO OREGO.ivp OREGO.csv
    E5 E5.ivp E5.csv
    Pollution POLL.ivp POLL.csv

    In the file print-benchmark.ts, you can find standalone functions that print the solutions of these problems to the console, as well as Python scripts for computing the solutions using SciPy.

    The library provides tools for declarative specifying models defined by IVPs. This feature enables a development of "no-code" modeling tools seamlessly integrated with the Datagrok platform.

    Each model has a simple declarative syntax.

    These blocks define the basic mathematical model and are required for any model:

    1. #name: Add a model identifier

      #name: Problem
      
    2. #equations: Define the system of ODEs to solve. Diff Grok supports any number of equations with single or multi-letter variable names

      #equations:
        dx/dt = x + y + exp(t)
        dy/dt = x - y - cos(t)
      
    3. #argument: Defines

      • independent variable
      • its initial value (initial)
      • final value (final), and
      • grid step (step)

      The solver calculates values at each step interval across the specified [initial,final] range.

      #argument: t
        initial = 0
        final = 1
        step = 0.01
      
    4. #inits: Defines initial values for functions being solved

      #inits:
        x = 2
        y = 5
      
    • #comment: Write a comment in any place of your model

      #comment:
        You can provide any text here. The lib ignores it.
      
    • Place comments right in formulas using //

      #equations:
        dx/dt = x + y + exp(t) // 1-st equation
        dy/dt = x - y - cos(t) // 2-nd equation
      

    These blocks define values used in equations. Choose type based on intended use:

    • #parameters: Generate UI controls for model exploration

      #parameters:
        P1 = 1
        P2 = -1
      
      
    • #constants: Use for fixed values in equations that don't require UI controls

      #constants:
        C1 = 1
        C2 = 3
      

    This block defines mathematical functions using #parameters, #constants, #argument, and other functions. These are direct calculations (no ODEs involved). Use them to break down complex calculations and simplify your equations.

    • #expressions

      #expressions:
        E1 = C1 * t + P1
        E2 = C2 * cos(2 * t) + P2
      

    To transform any model to JavaScript code with an appropriate specification of ODEs object, follow the steps:

    1. Import the parsing and code generating tools:
    import {getIVP, getJScode} from 'diff-grok';
    
    1. Define a string with a model specification, use a simple model syntax:
    const model = `
    #name: Example
    #equations:
    dx/dt = x + y - cos(t)
    dy/dt = x - y + sin(t)
    ...
    `;
    1. Parse formulas:
    const ivp = getIVP(model);
    

    The method getIVP parses formulas and returns IVP object specifying a model.

    1. Generate JS-code:
    const lines = getJScode(ivp);
    

    The method getJScode transforms IVP object to JavaScript code. It returns an array of strings with this code.

    Find this example in scripting.ts.

    Diff Grok pipeline is a powerful feature for complex process simulation and model analysis in webworkers. It wraps the main solver with a set of actions that perform pre- and post-processing of a model inputs & outputs. In addition, they provide an output customization.

    1. Start with imports:
    import * as DGL from 'diff-grok';
    
    1. Define your model:
    const model = `#name: My model
    #equations:
    dx/dt = ...
    dy/dt = ...
    ...

    #inits:
    x = 2
    y = 3
    ...
    1. Generate IVP-objects:
    • for the main thread computations:
    const ivp = DGL.getIVP(model);
    
    • for computations in workers:
    const ivpWW = DGL.getIvp2WebWorker(ivp);
    
    1. Set model inputs:
    const inputs = {
    x: 2,
    y: 30,
    ...
    };
    1. Create typed input array:
    const inputVector = DGL.getInputVector(inputs, ivp);
    
    1. Get a pipeline:
    const creator = DGL.getPipelineCreator(ivp);
    const pipeline = creator.getPipeline(inputVector);

    You can pass pipeline, ivpWW, and inputVector to webworkers.

    1. Apply pipeline to perform computations:
    const solution = DGL.applyPipeline(pipeline, ivpWW, inputVector);
    

    Find complete examples in these files:

    Datagrok is a platform enabling powerful scientific computing capabilities. It provides next-generation environment for leveraging interactive visualizations, data access, machine learning, and enterprise features to enable developing, publishing, discovering, and using scientific applications.

    The library is seamlessly integrated to Datagrok via the Diff Studio package. It provides

    • Numerical solving IVPs directly in the browser
    • "No-code" models development
    • Solving both stiff and non-stiff systems of ODEs
    • Automatic generation of user interfaces
    • Interactive visualization and model exploration
    • Sensitivity analysis and parameters optimization
    • Sharing models and computational results

    Run the Diff Studio app and check interactive modeling:

    DiffStudio

    Learn more

    • Node.js ≥ 19.3.0 (required for development and building the library)
    • npm or yarn package manager
    • Node.js ≥ 16.0.0 (for server-side usage)
      • Requires support for ES modules
      • Float64Array and typed arrays support (available since Node.js 0.10+)
    • Windows (x64, ARM64)
    • macOS (Intel & Apple Silicon)
    • Linux (most common distributions)

    The library runs in all modern browsers with ES2015+ support. Key requirements:

    • ES Modules (native import/export)
    • Typed Arrays (Float64Array, Uint8Array)
    • WebWorkers (for pipeline computations)
    • ArrayBuffer support
    Browser Minimum Version Supported? Notes
    Chrome 63+ ✔️ Yes Full ES2015+ and WebWorker support
    Firefox 60+ ✔️ Yes Full ES2015+ and WebWorker support
    Safari (macOS/iOS) 11.1+ ✔️ Yes Native ES module and WebWorker support
    Edge (Chromium) 79+ ✔️ Yes Same support level as Chrome
    Opera 50+ ✔️ Yes Chromium-based, full support
    Legacy Browsers - ❌ No IE 11, pre-Chromium Edge, old Android browsers

    Browser Feature Requirements:

    • ES2015 (ES6) JavaScript support
    • Native ES modules (<script type="module">)
    • Float64Array and other typed arrays
    • WebWorker API (for parallel computations)
    • Promise support
    • Math object with standard functions (exp, sin, cos, etc.)

    Notes:

    • For older browsers, consider using a transpiler (Babel) and bundler (Webpack/Rollup)
    • TypeScript compilation target should be ES2015 or higher
    • WebWorker support is required for pipeline computations; without it, computations run on the main thread

    When bundling for browsers, ensure:

    • ES module output format is preserved or properly transformed
    • TypedArray polyfills are not included (not needed for target browsers)
    • WebWorker files are properly handled by your bundler

    No polyfills required for target environments. All required features are natively supported in the minimum browser versions listed above.

    Diff Grok contains a set of examples located in the folder src/examples:

    File Features
    basic-use.ts Minimal "Hello World" example. Illustrates the use of the MRT method.
    check-methods.ts Checks the performance of numerical methods.
    corr-probs.ts Solves a set of problems with exact solutions and evaluate the deviation.
    cyclic-model.ts Considers pharmacokinetic-pharmacodynamic (PK-PD) simulation and shows how to apply pipelines and cyclic models.
    model-updates.ts Considers gluconic acid (GA) production by Aspergillus niger modeling and shows how to apply pipelines and models with updates.
    pipeline-use.ts Considers modeling queues and shows shows how to apply pipelines and models with customized outputs.
    scripting.ts Shows how to generate JS-script from Diff Grok model.
    Run examples

    To run examples standalone:

    1. Install TypeScript locally. If your project does not already include TypeScript:
    npm install --save-dev typescript
    
    1. Create a tsconfig.json. If you do not have one yet:
    npx tsc --init
    

    Recommended configuration:

    {
    "compilerOptions": {
    "target": "es6",
    "lib": ["ES2022", "dom"],
    "sourceMap": true,
    "strict": true,
    "moduleResolution": "node",
    "types": ["jest", "node"],
    "esModuleInterop": true,
    "skipLibCheck": true,
    }
    }
    1. Compile the TypeScript file:
    tsc src/examples/basic-use.ts
    
    1. Run:
    node src/examples/basic-use.js
    
    • L. Petzold, "Automatic Selection of Methods for Solving Stiff and Nonstiff Systems of Ordinary Differential Equations," SIAM J. Sci. Stat. Comput., 4(1), 136–148, 1983. doi:10.1137/0904010
    • A. C. Hindmarsh, "ODEPACK, A Systematized Collection of ODE Solvers," Scientific Computing, R. S. Stepleman et al. (eds.), North-Holland, Amsterdam, pp. 55–64, 1983. link
    • The LSODA solver is ported to TypeScript from the C library liblsoda
    • A. C. Hindmarsh et al., "SUNDIALS: Suite of Nonlinear and Differential/Algebraic Equation Solvers," ACM Trans. Math. Softw., 31(3), 363–396, 2005. doi:10.1145/1089014.1089020
    • S. D. Cohen and A. C. Hindmarsh, "CVODE, a Stiff/Nonstiff ODE Solver in C," Computers in Physics, 10(2), 138–143, 1996. doi:10.1063/1.4822377
    • The CVODE solver is ported to TypeScript from SUNDIALS CVODE v7.5.0
    • T. Rang and L. Angermann, "New Rosenbrock W-Methods of Order 3 for Partial Differential Algebraic Equations of Index 1," BIT Numer. Math., 45, 761–787, 2005. doi:10.1007/s10543-005-0035-y
    • E. Hairer and G. Wanner, Solving Ordinary Differential Equations II: Stiff and Differential-Algebraic Problems, Springer, 1996. doi:10.1137/S1064827594276424

    We welcome contributions of all kinds - bug reports, feature requests, documentation updates, and pull requests.

    Before contributing, please read our Contributing Guidelines.

    This project is licensed under the MIT License.

    The LSODA solver is a TypeScript port of liblsoda. The CVODE solver is a TypeScript port of SUNDIALS CVODE. See THIRD_PARTY_LICENSES for details on third-party code provenance.