diff --git a/dev/comparisons/cppfortran/index.html b/dev/comparisons/cppfortran/index.html index 98d4f1e36d3..d8ee2c4c8f3 100644 --- a/dev/comparisons/cppfortran/index.html +++ b/dev/comparisons/cppfortran/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Getting Started with Julia's SciML for the C++/Fortran User

You don't need help if you're a Fortran guru. I'm just kidding, you're not a Lisp developer. If you're coming from C++ or Fortran, you may be familiar with high-performance computing environments similar to SciML, such as PETSc, Trilinos, or Sundials. The following are some points to help the transition.

Why SciML? High-Level Workflow Reasons

If you're coming from “hardcore” C++/Fortran computing environments, some things to check out with Julia's SciML are:

  • Interactivity - use the interactive REPL to easily investigate numerical details.
  • Metaprogramming performance tools - tools like LoopVectorization.jl can be used to generate faster code than even some of the most hand-optimized C++/Fortran code. Current benchmarks show this SIMD-optimized Julia code outperforming OpenBLAS and MKL BLAS implementations in many performance regimes.
  • Symbolic modeling languages - writing models by hand can leave a lot of performance on the table. Using high-level modeling tools like ModelingToolkit can automate symbolic simplifications, which improve the stability and performance of numerical solvers. On complex models, even the best handwritten C++/Fortran code is orders of magnitude behind the code that symbolic tearing algorithms can achieve!
  • Composable Library Components - In C++/Fortran environments, every package feels like a silo. Arrays made for PETSc cannot easily be used in Trilinos, and converting Sundials NVector outputs to DataFrames for post-simulation data processing is a process itself. The Julia SciML environment embraces interoperability. Don't wait for SciML to do it: by using generic coding with JIT compilation, these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • Wrappers to the Libraries You Know and Trust - Moving to SciML does not have to be a quick transition. SciML has extensive wrappers to many widely-used classical solver environments such as SUNDIALS and Hairer's classic Fortran ODE solvers (dopri5, dop853, etc.). Using these wrapped solvers is painless and can be swapped in for the Julia versions with one line of code. This gives you a way to incrementally adopt new features/methods while retaining the older pieces you know and trust.
  • Don't Start from Scratch - SciML builds on the extensive Base library of Julia, and thus grows and improves with every update to the language. With hundreds of monthly contributors to SciML and hundreds of monthly contributors to Julia, SciML is one of the most actively developed open-source scientific computing ecosystems out there!
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, Sundials/Hairer in purple/red represent C++/Fortrans most commonly used solvers:

Why SciML? Some Technical Details

Let's face the facts, in the open benchmarks the pure-Julia solvers tend to outperform the classic “best” C++ and Fortran solvers in almost every example (with a few notable exceptions). But why?

The answer is two-fold: Julia is as fast as C++/Fortran, and the algorithms are what matter.

Julia is as Fast as C++/Fortran

While Julia code looks high level like Python or MATLAB, its performance is on par with C++ and Fortran. At a technical level, when Julia code is type-stable, i.e. that the types that are returned from a function are deducible at compile-time from the types that go into a function, then Julia can optimize it as much as C++ or Fortran by automatically devirtualizing all dynamic behavior and compile-time optimizing the quasi-static code. This is not an empirical statement, it's a provable type-theoretic result. The resulting compiler used on the resulting quasi-static representation is LLVM, the same optimizing compiler used by clang and LFortran.

For more details on how Julia code is optimized and how to optimize your own Julia code, check out this chapter from the SciML Book.

SciML's Julia Algorithms Have Performance Advantages in Many Common Regimes

There are many ways which Julia's algorithms achieve performance advantages. Some facts to highlight include:

Let's Dig Deep Into One Case: Adjoints of ODEs for Solving Inverse Problems

To really highlight how JIT compilation and automatic differentiation integration can change algorithms, let's look at the problem of differentiating an ODE solver. As is derived and discussed in detail at a seminar with the American Statistical Association, there are many ways to implement well-known “adjoint” methods which are required for performance. Each has different stability and performance trade-offs, and Julia's SciML is the only system to systemically offer all of the trade-off options. In many cases, using analytical adjoints of a solver is not advised due to performance reasons, with the trade-off described in detail here. Likewise, even when analytical adjoints are used, it turns out that for general nonlinear equations there is a trick which uses automatic differentiation in the construction of the analytical adjoint to improve its performance. As demonstrated in this publication, this can lead to about 2-3 orders of magnitude performance improvements. These AD-enhanced adjoints are showcased as the seeding methods in this plot:

Unless one directly defines special “vjp” functions, this is how the Julia SciML methods achieve orders of magnitude performance advantages over CVODES's adjoints and PETSC's TS-adjoint.

Moral of the story, even there are many reasons to use automatic differentiation of a solver, and even if an analytical adjoint rule is used for some specific performance reason, that analytical expression can often times be accelerated by orders of magnitude itself by embedding some form of automatic differentiation into it. This is just one algorithm of many which are optimized in this fashion.

+

Getting Started with Julia's SciML for the C++/Fortran User

You don't need help if you're a Fortran guru. I'm just kidding, you're not a Lisp developer. If you're coming from C++ or Fortran, you may be familiar with high-performance computing environments similar to SciML, such as PETSc, Trilinos, or Sundials. The following are some points to help the transition.

Why SciML? High-Level Workflow Reasons

If you're coming from “hardcore” C++/Fortran computing environments, some things to check out with Julia's SciML are:

  • Interactivity - use the interactive REPL to easily investigate numerical details.
  • Metaprogramming performance tools - tools like LoopVectorization.jl can be used to generate faster code than even some of the most hand-optimized C++/Fortran code. Current benchmarks show this SIMD-optimized Julia code outperforming OpenBLAS and MKL BLAS implementations in many performance regimes.
  • Symbolic modeling languages - writing models by hand can leave a lot of performance on the table. Using high-level modeling tools like ModelingToolkit can automate symbolic simplifications, which improve the stability and performance of numerical solvers. On complex models, even the best handwritten C++/Fortran code is orders of magnitude behind the code that symbolic tearing algorithms can achieve!
  • Composable Library Components - In C++/Fortran environments, every package feels like a silo. Arrays made for PETSc cannot easily be used in Trilinos, and converting Sundials NVector outputs to DataFrames for post-simulation data processing is a process itself. The Julia SciML environment embraces interoperability. Don't wait for SciML to do it: by using generic coding with JIT compilation, these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • Wrappers to the Libraries You Know and Trust - Moving to SciML does not have to be a quick transition. SciML has extensive wrappers to many widely-used classical solver environments such as SUNDIALS and Hairer's classic Fortran ODE solvers (dopri5, dop853, etc.). Using these wrapped solvers is painless and can be swapped in for the Julia versions with one line of code. This gives you a way to incrementally adopt new features/methods while retaining the older pieces you know and trust.
  • Don't Start from Scratch - SciML builds on the extensive Base library of Julia, and thus grows and improves with every update to the language. With hundreds of monthly contributors to SciML and hundreds of monthly contributors to Julia, SciML is one of the most actively developed open-source scientific computing ecosystems out there!
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, Sundials/Hairer in purple/red represent C++/Fortrans most commonly used solvers:

Why SciML? Some Technical Details

Let's face the facts, in the open benchmarks the pure-Julia solvers tend to outperform the classic “best” C++ and Fortran solvers in almost every example (with a few notable exceptions). But why?

The answer is two-fold: Julia is as fast as C++/Fortran, and the algorithms are what matter.

Julia is as Fast as C++/Fortran

While Julia code looks high level like Python or MATLAB, its performance is on par with C++ and Fortran. At a technical level, when Julia code is type-stable, i.e. that the types that are returned from a function are deducible at compile-time from the types that go into a function, then Julia can optimize it as much as C++ or Fortran by automatically devirtualizing all dynamic behavior and compile-time optimizing the quasi-static code. This is not an empirical statement, it's a provable type-theoretic result. The resulting compiler used on the resulting quasi-static representation is LLVM, the same optimizing compiler used by clang and LFortran.

For more details on how Julia code is optimized and how to optimize your own Julia code, check out this chapter from the SciML Book.

SciML's Julia Algorithms Have Performance Advantages in Many Common Regimes

There are many ways which Julia's algorithms achieve performance advantages. Some facts to highlight include:

Let's Dig Deep Into One Case: Adjoints of ODEs for Solving Inverse Problems

To really highlight how JIT compilation and automatic differentiation integration can change algorithms, let's look at the problem of differentiating an ODE solver. As is derived and discussed in detail at a seminar with the American Statistical Association, there are many ways to implement well-known “adjoint” methods which are required for performance. Each has different stability and performance trade-offs, and Julia's SciML is the only system to systemically offer all of the trade-off options. In many cases, using analytical adjoints of a solver is not advised due to performance reasons, with the trade-off described in detail here. Likewise, even when analytical adjoints are used, it turns out that for general nonlinear equations there is a trick which uses automatic differentiation in the construction of the analytical adjoint to improve its performance. As demonstrated in this publication, this can lead to about 2-3 orders of magnitude performance improvements. These AD-enhanced adjoints are showcased as the seeding methods in this plot:

Unless one directly defines special “vjp” functions, this is how the Julia SciML methods achieve orders of magnitude performance advantages over CVODES's adjoints and PETSC's TS-adjoint.

Moral of the story, even there are many reasons to use automatic differentiation of a solver, and even if an analytical adjoint rule is used for some specific performance reason, that analytical expression can often times be accelerated by orders of magnitude itself by embedding some form of automatic differentiation into it. This is just one algorithm of many which are optimized in this fashion.

diff --git a/dev/comparisons/matlab/index.html b/dev/comparisons/matlab/index.html index 10a7cd0450d..f571d2a7530 100644 --- a/dev/comparisons/matlab/index.html +++ b/dev/comparisons/matlab/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Getting Started with Julia's SciML for the MATLAB User

If you're a MATLAB user who has looked into Julia for some performance improvements, you may have noticed that the standard library does not have all of the “batteries” included with a base MATLAB installation. Where's the ODE solver? Where's fmincon and fsolve? Those scientific computing functionalities are the pieces provided by the Julia SciML ecosystem!

Why SciML? High-Level Workflow Reasons

  • Performance - The key reason people are moving from MATLAB to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.
  • Julia is quick to learn from MATLAB - Most ODE codes can be translated in a few minutes. If you need help, check out the QuantEcon MATLAB-Python-Julia Cheat Sheet.
  • Package Management and Versioning - Julia's package manager takes care of dependency management, testing, and continuous delivery in order to make the installation and maintenance process smoother. For package users, this means it's easier to get packages with complex functionality in your hands.
  • Free and Open Source - If you want to know how things are being computed, just look at our GitHub organization. Lots of individuals use Julia's SciML to research how the algorithms actually work because of how accessible and tweakable the ecosystem is!
  • Composable Library Components - In MATLAB environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, MATLAB in orange represents MATLAB's most commonly used solvers:

Need a case study?

Check out this talk from NASA Scientists getting a 15,000x acceleration by switching from Simulink to Julia's ModelingToolkit!

Need Help Translating from MATLAB to Julia?

The following resources can be particularly helpful when adopting Julia for SciML for the first time:

MATLAB to Julia SciML Functionality Translations

The following chart will help you get quickly acquainted with Julia's SciML Tools:

MATLAB FunctionSciML-Supported Julia packages
plotPlots, Makie
sparseSparseArrays
interp1DataInterpolations
\, gmres, cgLinearSolve
fsolveNonlinearSolve
quadIntegrals
fminconOptimization
odeXXDifferentialEquations
ode45Tsit5
ode113VCABM
ode23sRosenbrock23
ode15sQNDF or FBDF
ode15iIDA
bvp4c and bvp5cDifferentialEquations
Simulink, SimscapeModelingToolkit
fftFFTW
chebfunApproxFun
+

Getting Started with Julia's SciML for the MATLAB User

If you're a MATLAB user who has looked into Julia for some performance improvements, you may have noticed that the standard library does not have all of the “batteries” included with a base MATLAB installation. Where's the ODE solver? Where's fmincon and fsolve? Those scientific computing functionalities are the pieces provided by the Julia SciML ecosystem!

Why SciML? High-Level Workflow Reasons

  • Performance - The key reason people are moving from MATLAB to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.
  • Julia is quick to learn from MATLAB - Most ODE codes can be translated in a few minutes. If you need help, check out the QuantEcon MATLAB-Python-Julia Cheat Sheet.
  • Package Management and Versioning - Julia's package manager takes care of dependency management, testing, and continuous delivery in order to make the installation and maintenance process smoother. For package users, this means it's easier to get packages with complex functionality in your hands.
  • Free and Open Source - If you want to know how things are being computed, just look at our GitHub organization. Lots of individuals use Julia's SciML to research how the algorithms actually work because of how accessible and tweakable the ecosystem is!
  • Composable Library Components - In MATLAB environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, MATLAB in orange represents MATLAB's most commonly used solvers:

Need a case study?

Check out this talk from NASA Scientists getting a 15,000x acceleration by switching from Simulink to Julia's ModelingToolkit!

Need Help Translating from MATLAB to Julia?

The following resources can be particularly helpful when adopting Julia for SciML for the first time:

MATLAB to Julia SciML Functionality Translations

The following chart will help you get quickly acquainted with Julia's SciML Tools:

MATLAB FunctionSciML-Supported Julia packages
plotPlots, Makie
sparseSparseArrays
interp1DataInterpolations
\, gmres, cgLinearSolve
fsolveNonlinearSolve
quadIntegrals
fminconOptimization
odeXXDifferentialEquations
ode45Tsit5
ode113VCABM
ode23sRosenbrock23
ode15sQNDF or FBDF
ode15iIDA
bvp4c and bvp5cDifferentialEquations
Simulink, SimscapeModelingToolkit
fftFFTW
chebfunApproxFun
diff --git a/dev/comparisons/python/index.html b/dev/comparisons/python/index.html index b1aea87d673..3689bdfcd19 100644 --- a/dev/comparisons/python/index.html +++ b/dev/comparisons/python/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Getting Started with Julia's SciML for the Python User

If you're a Python user who has looked into Julia, you're probably wondering what is the equivalent to SciPy is. And you found it: it's the SciML ecosystem! To a Python developer, SciML is SciPy, but with the high-performance GPU, capabilities of PyTorch, and neural network capabilities, all baked right in. With SciML, there is no “separate world” of machine learning sublanguages: there is just one cohesive package ecosystem.

Why SciML? High-Level Workflow Reasons

  • Performance - The key reason people are moving from SciPy to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.
  • Package Management and Versioning - Julia's package manager takes care of dependency management, testing, and continuous delivery in order to make the installation and maintenance process smoother. For package users, this means it's easier to get packages with complex functionality in your hands.
  • Composable Library Components - In Python environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, SciPy in yellow represents Python's most commonly used solvers:

Need Help Translating from Python to Julia?

The following resources can be particularly helpful when adopting Julia for SciML for the first time:

Python to Julia SciML Functionality Translations

The following chart will help you get quickly acquainted with Julia's SciML Tools:

Workflow ElementSciML-Supported Julia packages
MatplotlibPlots, Makie
scipy.specialSpecialFunctions
scipy.linalg.solveLinearSolve
scipy.integrateIntegrals
scipy.optimizeOptimization
scipy.optimize.fsolveNonlinearSolve
scipy.interpolateDataInterpolations
scipy.fftFFTW
scipy.linalgJulia's Built-In Linear Algebra
scipy.sparseSparseArrays, ARPACK
odeint/solve_ivpDifferentialEquations
scipy.integrate.solve_bvpBoundary-value problem
PyTorchFlux, Lux
gillespy2Catalyst, JumpProcesses
scipy.optimize.approx_fprimeFiniteDiff
autogradForwardDiff*, Enzyme*, DiffEqSensitivity
StanTuring
sympySymbolics

Why is Differentiable Programming Important for Scientific Computing?

Check out this blog post that goes into detail on how training neural networks in tandem with simulation improves performance by orders of magnitude. But can't you use analytical adjoint definitions? You can, but there are tricks to mix automatic differentiation into the adjoint definitions for a few orders of magnitude improvement too, as explained in this blog post.

These facts, along with many others, compose to algorithmic improvements with the implementation improvements, which leads to orders of magnitude improvements!

+

Getting Started with Julia's SciML for the Python User

If you're a Python user who has looked into Julia, you're probably wondering what is the equivalent to SciPy is. And you found it: it's the SciML ecosystem! To a Python developer, SciML is SciPy, but with the high-performance GPU, capabilities of PyTorch, and neural network capabilities, all baked right in. With SciML, there is no “separate world” of machine learning sublanguages: there is just one cohesive package ecosystem.

Why SciML? High-Level Workflow Reasons

  • Performance - The key reason people are moving from SciPy to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.
  • Package Management and Versioning - Julia's package manager takes care of dependency management, testing, and continuous delivery in order to make the installation and maintenance process smoother. For package users, this means it's easier to get packages with complex functionality in your hands.
  • Composable Library Components - In Python environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, SciPy in yellow represents Python's most commonly used solvers:

Need Help Translating from Python to Julia?

The following resources can be particularly helpful when adopting Julia for SciML for the first time:

Python to Julia SciML Functionality Translations

The following chart will help you get quickly acquainted with Julia's SciML Tools:

Workflow ElementSciML-Supported Julia packages
MatplotlibPlots, Makie
scipy.specialSpecialFunctions
scipy.linalg.solveLinearSolve
scipy.integrateIntegrals
scipy.optimizeOptimization
scipy.optimize.fsolveNonlinearSolve
scipy.interpolateDataInterpolations
scipy.fftFFTW
scipy.linalgJulia's Built-In Linear Algebra
scipy.sparseSparseArrays, ARPACK
odeint/solve_ivpDifferentialEquations
scipy.integrate.solve_bvpBoundary-value problem
PyTorchFlux, Lux
gillespy2Catalyst, JumpProcesses
scipy.optimize.approx_fprimeFiniteDiff
autogradForwardDiff*, Enzyme*, DiffEqSensitivity
StanTuring
sympySymbolics

Why is Differentiable Programming Important for Scientific Computing?

Check out this blog post that goes into detail on how training neural networks in tandem with simulation improves performance by orders of magnitude. But can't you use analytical adjoint definitions? You can, but there are tricks to mix automatic differentiation into the adjoint definitions for a few orders of magnitude improvement too, as explained in this blog post.

These facts, along with many others, compose to algorithmic improvements with the implementation improvements, which leads to orders of magnitude improvements!

diff --git a/dev/comparisons/r/index.html b/dev/comparisons/r/index.html index 765706b7aab..5d323cdab36 100644 --- a/dev/comparisons/r/index.html +++ b/dev/comparisons/r/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Getting Started with Julia's SciML for the R User

If you're an R user who has looked into Julia, you're probably wondering where all of the scientific computing packages are. How do I solve ODEs? Solve f(x)=0 for x? Etc. SciML is the ecosystem for doing this with Julia.

Why SciML? High-Level Workflow Reasons

  • Performance - The key reason people are moving from R to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.
  • Composable Library Components - In R environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • A Global Harmonious Documentation for Scientific Computing - R's documentation for scientific computing is scattered in a bunch of individual packages where the developers do not talk to each other! This not only leads to documentation differences, but also “style” differences: one package uses tol while the other uses atol. With Julia's SciML, the whole ecosystem is considered together, and inconsistencies are handled at the global level. The goal is to be working in one environment with one language.
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, deSolve in blue represents R's most commonly used solver:

Need Help Translating from R to Julia?

The following resources can be particularly helpful when adopting Julia for SciML for the first time:

R to Julia SciML Functionality Translations

The following chart will help you get quickly acquainted with Julia's SciML Tools:

R Function/PackageSciML-Supported Julia packages
data.frameDataFrames
plotPlots, Makie
ggplot2AlgebraOfGraphics
deSolveDifferentialEquations
StanTuring

Want to See the Power of Julia?

Check out this R-Bloggers blog post on diffeqr, a package which uses ModelingToolkit to translate R code to Julia, and achieves 350x acceleration over R's popular deSolve ODE solver package. But when the solve is done purely in Julia, it achieves 2777x acceleration over deSolve!

+

Getting Started with Julia's SciML for the R User

If you're an R user who has looked into Julia, you're probably wondering where all of the scientific computing packages are. How do I solve ODEs? Solve f(x)=0 for x? Etc. SciML is the ecosystem for doing this with Julia.

Why SciML? High-Level Workflow Reasons

  • Performance - The key reason people are moving from R to Julia's SciML in droves is performance. Even simple ODE solvers are much faster!, demonstrating orders of magnitude performance improvements for differential equations, nonlinear solving, optimization, and more. And the performance advantages continue to grow as more complex algorithms are required.
  • Composable Library Components - In R environments, every package feels like a silo. Functions made for one file exchange library cannot easily compose with another. SciML's generic coding with JIT compilation these connections create new optimized code on the fly and allow for a more expansive feature set than can ever be documented. Take new high-precision number types from a package and stick them into a nonlinear solver. Take a package for Intel GPU arrays and stick it into the differential equation solver to use specialized hardware acceleration.
  • A Global Harmonious Documentation for Scientific Computing - R's documentation for scientific computing is scattered in a bunch of individual packages where the developers do not talk to each other! This not only leads to documentation differences, but also “style” differences: one package uses tol while the other uses atol. With Julia's SciML, the whole ecosystem is considered together, and inconsistencies are handled at the global level. The goal is to be working in one environment with one language.
  • Easier High-Performance and Parallel Computing - With Julia's ecosystem, CUDA will automatically install of the required binaries and cu(A)*cu(B) is then all that's required to GPU-accelerate large-scale linear algebra. MPI is easy to install and use. Distributed computing through password-less SSH. Multithreading is automatic and baked into many libraries, with a specialized algorithm to ensure hierarchical usage does not oversubscribe threads. Basically, libraries give you a lot of parallelism for free, and doing the rest is a piece of cake.
  • Mix Scientific Computing with Machine Learning - Want to automate the discovery of missing physical laws using neural networks embedded in differentiable simulations? Julia's SciML is the ecosystem with the tooling to integrate machine learning into the traditional high-performance scientific computing domains, from multiphysics simulations to partial differential equations.

In this plot, deSolve in blue represents R's most commonly used solver:

Need Help Translating from R to Julia?

The following resources can be particularly helpful when adopting Julia for SciML for the first time:

R to Julia SciML Functionality Translations

The following chart will help you get quickly acquainted with Julia's SciML Tools:

R Function/PackageSciML-Supported Julia packages
data.frameDataFrames
plotPlots, Makie
ggplot2AlgebraOfGraphics
deSolveDifferentialEquations
StanTuring

Want to See the Power of Julia?

Check out this R-Bloggers blog post on diffeqr, a package which uses ModelingToolkit to translate R code to Julia, and achieves 350x acceleration over R's popular deSolve ODE solver package. But when the solve is done purely in Julia, it achieves 2777x acceleration over deSolve!

diff --git a/dev/getting_started/find_root/index.html b/dev/getting_started/find_root/index.html index 26bdbef7844..ad465e11138 100644 --- a/dev/getting_started/find_root/index.html +++ b/dev/getting_started/find_root/index.html @@ -73,4 +73,4 @@ 0.0 0.0 0.0

Step 5: Analyze the Solution

Now let's check out the solution. First of all, what kind of thing is the sol? We can see that by asking for its type:

typeof(sol)
SciMLBase.NonlinearSolution{Float64, 1, Vector{Float64}, Vector{Float64}, SciMLBase.NonlinearProblem{Vector{Float64}, true, Vector{Float64}, SciMLBase.NonlinearFunction{true, SciMLBase.FullSpecialize, ModelingToolkit.var"#f#733"{RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋arg1, :ˍ₋arg2), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x31381c72, 0xc57f609d, 0x303e44f7, 0x142ed376, 0x9b81df74), Nothing}, RuntimeGeneratedFunctions.RuntimeGeneratedFunction{(:ˍ₋out, :ˍ₋arg1, :ˍ₋arg2), ModelingToolkit.var"#_RGF_ModTag", ModelingToolkit.var"#_RGF_ModTag", (0x071f1454, 0x9075ad55, 0xc8a6d474, 0xdb5593a1, 0xf697d5cb), Nothing}}, LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Vector{Symbol}, Vector{Symbol}, ModelingToolkit.var"#generated_observed#736"{ModelingToolkit.NonlinearSystem, Dict{Any, Any}}, Nothing, ModelingToolkit.NonlinearSystem, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardNonlinearProblem}, NonlinearSolve.NewtonRaphson{0, true, Val{:forward}, Nothing, typeof(NonlinearSolve.DEFAULT_PRECS), true, nothing}, Nothing, Nothing, SciMLBase.NLStats}

From this, we can see that it is an NonlinearSolution. We can see the documentation for how to use the NonlinearSolution by checking the NonlinearSolve.jl solution type page. For example, the solution is stored as .u. What is the solution to our nonlinear system, and what is the final residual value? We can check it as follows:

# Analyze the solution
-@show sol.u, sol.resid
([0.0, 0.0, 0.0], [0.0, 0.0, 0.0])
+@show sol.u, sol.resid
([0.0, 0.0, 0.0], [0.0, 0.0, 0.0])
diff --git a/dev/getting_started/first_optimization/index.html b/dev/getting_started/first_optimization/index.html index a79366b08de..a28e102ce3b 100644 --- a/dev/getting_started/first_optimization/index.html +++ b/dev/getting_started/first_optimization/index.html @@ -32,4 +32,4 @@ sol = solve(prob, NLopt.LD_LBFGS())
u: 2-element Vector{Float64}:
  1.0
  1.0

Step 4: Analyze the Solution

Now let's check out the solution. First of all, what kind of thing is the sol? We can see that by asking for its type:

typeof(sol)
SciMLBase.OptimizationSolution{Float64, 1, Vector{Float64}, Optimization.OptimizationCache{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), OptimizationForwardDiffExt.var"#38#56"{ForwardDiff.GradientConfig{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, Float64, 2, Vector{ForwardDiff.Dual{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, Float64, 2}}}, OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}}}, OptimizationForwardDiffExt.var"#41#59"{ForwardDiff.HessianConfig{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, Float64, 2, Vector{ForwardDiff.Dual{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, ForwardDiff.Dual{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, Float64, 2}, 2}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}}, Float64}, Float64, 2}}}, OptimizationForwardDiffExt.var"#37#55"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}}}, OptimizationForwardDiffExt.var"#44#62", Nothing, OptimizationForwardDiffExt.var"#48#66"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}}, OptimizationForwardDiffExt.var"#53#71"{SciMLBase.OptimizationFunction{true, ADTypes.AutoForwardDiff{nothing, Nothing}, typeof(Main.L), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED_NO_TIME), Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing}, Optimization.ReInitCache{Vector{Float64}, Vector{Float64}}, Vector{Float64}, Vector{Float64}, Nothing, Nothing, Nothing, NLopt.Algorithm, Base.Iterators.Cycle{Tuple{Optimization.NullData}}, Bool, Optimization.var"#41#43"}, NLopt.Algorithm, Float64, NLopt.Opt, Float64, Nothing}

From this, we can see that it is an OptimizationSolution. We can see the documentation for how to use the OptimizationSolution by checking the Optimization.jl solution type page. For example, the solution is stored as .u. What is the solution to our optimization, and what is the final loss value? We can check it as follows:

# Analyze the solution
-@show sol.u, L(sol.u, p)
([1.0, 1.0], 0.0)
+@show sol.u, L(sol.u, p)
([1.0, 1.0], 0.0)
diff --git a/dev/getting_started/first_simulation/index.html b/dev/getting_started/first_simulation/index.html index 62ccded56b8..1f85afa74f9 100644 --- a/dev/getting_started/first_simulation/index.html +++ b/dev/getting_started/first_simulation/index.html @@ -42,89 +42,89 @@ plot(p1, p2, layout = (2, 1)) - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + +

Step-by-Step Solution

Step 1: Install and Import the Required Packages

To do this tutorial, we will need a few components:

To start, let's add these packages as demonstrated in the installation tutorial:

using Pkg
 Pkg.add(["ModelingToolkit", "DifferentialEquations", "Plots"])

Now we're ready. Let's load in these packages:

using ModelingToolkit, DifferentialEquations, Plots

Step 2: Define our ODE Equations

Now let's define our ODEs. We use the ModelingToolkit.@variabes statement to declare our variables. We have the independent variable time t, and then define our 3 state variables:

# Define our state variables: state(t) = initial condition
 @variables t x(t)=1 y(t)=1 z(t)=2

\[ \begin{equation} @@ -245,189 +245,189 @@

- + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
p2 = plot(sol, idxs = z, title = "Total Animals")
- + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + +

Finally, let's make a plot where we merge these two plot elements. To do so, we can take our two plot objects, p1 and p2, and make a plot with both of them. Then we tell Plots to do a layout of (2,1), or 2 rows and 1 columns. Let's see what happens when we bring these together:

plot(p1, p2, layout = (2, 1))
- + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + +

And tada, we have a full analysis of our ecosystem!

Bonus Step: Emoji Variables

If you made it this far, then congrats, you get to learn a fun fact! Since Julia code can use Unicode, emojis work for variable names. Here's the simulation using emojis of rabbits and wolves to define the system:

using ModelingToolkit, DifferentialEquations
 @parameters α=1.5 β=1.0 γ=3.0 δ=1.0
 @variables t 🐰(t)=1.0 🐺(t)=1.0
@@ -481,4 +481,4 @@ 

« Installing SciML SoftwareSolve your first optimization problem »
+ [1.0337581256020607, 0.9063703842886133]

Now go make your professor mad that they have to grade a fully emojified code. I'll vouch for you: the documentation told you to do this.

diff --git a/dev/getting_started/fit_simulation/index.html b/dev/getting_started/fit_simulation/index.html index 059325d255e..d271f66f341 100644 --- a/dev/getting_started/fit_simulation/index.html +++ b/dev/getting_started/fit_simulation/index.html @@ -140,4 +140,4 @@ 1.499584010680642 0.9996974030659543 3.0020191064934587 - 1.0012321222850014

and the answer from the optimization is our desired parameters.

+ 1.0012321222850014

and the answer from the optimization is our desired parameters.

diff --git a/dev/getting_started/getting_started/index.html b/dev/getting_started/getting_started/index.html index c7730d7fd1f..d1d0bfc92b7 100644 --- a/dev/getting_started/getting_started/index.html +++ b/dev/getting_started/getting_started/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Getting Started with Julia's SciML

Quickly: What is Julia's SciML Ecosystem?

Julia's SciML is:

  • SciPy or MATLAB's standard library but in Julia, but
  • Runs orders of magnitude faster, even outperforms C and Fortran libraries, and
  • Is fully compatible with machine learning and automatic differentiation,
  • All while having an easy-to-use high level interactive development environment.

Interested?

Introductory Tutorials

Note

Each of the SciML packages starts with its own introductory tutorial as well! Once you have started to get the hang of a few things, start checking out the introductory tutorials of the different packages. For example, the DifferentialEquations.jl getting started tutorial is a fun one!

Coming from...

Are you familiar with other scientific computing tools? Take a look at the guided introductions below.

+

Getting Started with Julia's SciML

Quickly: What is Julia's SciML Ecosystem?

Julia's SciML is:

  • SciPy or MATLAB's standard library but in Julia, but
  • Runs orders of magnitude faster, even outperforms C and Fortran libraries, and
  • Is fully compatible with machine learning and automatic differentiation,
  • All while having an easy-to-use high level interactive development environment.

Interested?

Introductory Tutorials

Note

Each of the SciML packages starts with its own introductory tutorial as well! Once you have started to get the hang of a few things, start checking out the introductory tutorials of the different packages. For example, the DifferentialEquations.jl getting started tutorial is a fun one!

Coming from...

Are you familiar with other scientific computing tools? Take a look at the guided introductions below.

diff --git a/dev/getting_started/installation/index.html b/dev/getting_started/installation/index.html index fd2278a0fb5..489fa54c706 100644 --- a/dev/getting_started/installation/index.html +++ b/dev/getting_started/installation/index.html @@ -4,4 +4,4 @@ gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash});

Installing SciML Software

Step 1: Install Julia

Download Julia using this website.

Note

Some Linux distributions do weird and incorrect things with Julia installations! Please install Julia using the binaries provided by the official JuliaLang website!

To ensure that you have installed Julia correctly, open it up and type versioninfo() in the REPL. It should look like the following:

(with the CPU/OS/etc. details matching your computer!)

If you got stuck in this installation process, ask for help on the Julia Discourse or in the Julia Zulip chatrooms

Optional Step 1.5: Get VS Code Setup with the Julia Extension

You can run SciML with Julia in any development environment you please, but our recommended environment is VS Code. For more information on using Julia with VS Code, check out the Julia VS Code Extension website. Let's install it!

First download VS Code from the official website.

Next, open Visual Studio Code and click Extensions.

Then, search for “Julia” in the search bar on the top of the extension tab, click on the “Julia” extension, and click the install button on the tab that opens up.

To make sure your installation is correct, try running some code. Open a new file by either going to the top left navigation bar File |> New Text File, or hitting Ctrl+n. Name your new file test.jl (important: the Julia VS Code functionality only turns on when using a .jl file!). Next, type 1+1 and hit Ctrl+Enter. A Julia REPL should pop up and the result 2 should be displayed. Your environment should look something like this:

For more help on using the VS Code editor with Julia, check out the VS Code in Julia documentation. Useful keyboard commands can be found here.

Once again, if you got stuck in this installation process, ask for help on the Julia Discourse or in the Julia Zulip chatrooms

Step 2: Install a SciML Package

SciML is over 130 Julia packages. That's too much stuff to give someone in a single download! Thus instead, the SciML organization divides its functionality into composable modules that can be mixed and matched as required. Installing SciML ecosystem functionality is equivalent to installation of such packages.

For example, do you need the differential equation solver? Then install DifferentialEquations via the command:

using Pkg;
-Pkg.add("DifferentialEquations");

in the Julia REPL. Or, for a more robust REPL experience, hit the ] command to make the blue pkg> REPL environment start, and type in add DifferentialEquations. The package REPL environment will have nice extras like auto-complete that will be useful in the future. This command should run an installation sequence and precompile all of the packages (precompile = "run a bunch of performance optimizations!"). Don't be surprised if this installation process takes ~10 minutes on older computers. During the installation, it should look like this:

And that's it!

How do I test that my installed correctly?

The best way is to build and run your first simulation!

+Pkg.add("DifferentialEquations");

in the Julia REPL. Or, for a more robust REPL experience, hit the ] command to make the blue pkg> REPL environment start, and type in add DifferentialEquations. The package REPL environment will have nice extras like auto-complete that will be useful in the future. This command should run an installation sequence and precompile all of the packages (precompile = "run a bunch of performance optimizations!"). Don't be surprised if this installation process takes ~10 minutes on older computers. During the installation, it should look like this:

And that's it!

How do I test that my installed correctly?

The best way is to build and run your first simulation!

diff --git a/dev/highlevels/array_libraries/index.html b/dev/highlevels/array_libraries/index.html index bf650b11686..61bc66933ed 100644 --- a/dev/highlevels/array_libraries/index.html +++ b/dev/highlevels/array_libraries/index.html @@ -26,4 +26,4 @@ lorenz_p = (σ = 10.0, ρ = 28.0, β = 8 / 3) lorenz_ic = ComponentArray(x = 0.0, y = 0.0, z = 0.0) -lorenz_prob = ODEProblem(lorenz!, lorenz_ic, tspan, lorenz_p)

Is that beautiful? Yes, it is.

StaticArrays.jl: Statically-Defined Arrays

StaticArrays.jl is a library for statically-defined arrays. Because these arrays have type-level information for size, they recompile the solvers for every new size. They can be dramatically faster for small sizes (up to approximately size 10), but for larger equations they increase compile time with little to no benefit.

CUDA.jl: NVIDIA CUDA-Based GPU Array Computations

CUDA.jl is the library for defining arrays which live on NVIDIA GPUs (CuArray). SciML's libraries will respect the GPU-ness of the inputs, i.e., if the input arrays live on the GPU then the operations will all take place on the GPU or else the libraries will error if it's unable to do so. Thus, using CUDA.jl's CuArray is how one GPU-accelerates any computation with the SciML organization's libraries. Simply use a CuArray as the initial condition to an ODE solve or as the initial guess for a nonlinear solve, and the whole solve will recompile to take place on the GPU.

AMDGPU.jl: AMD-Based GPU Array Computations

AMDGPU.jl is the library for defining arrays which live on AMD GPUs (ROCArray). SciML's libraries will respect the GPU-ness of the inputs, i.e., if the input arrays live on the GPU then the operations will all take place on the GPU or else the libraries will error if it's unable to do so. Thus using AMDGPU.jl's ROCArray is how one GPU-accelerates any computation with the SciML organization's libraries. Simply use a ROCArray as the initial condition to an ODE solve or as the initial guess for a nonlinear solve, and the whole solve will recompile to take place on the GPU.

FillArrays.jl: Lazy Arrays

FillArrays.jl is a library for defining arrays with lazy values. For example, an O(1) representation of the identity matrix is given by Eye{Int}(5). FillArrays.jl is used extensively throughout the ecosystem to improve runtime and memory performance.

BandedMatrices.jl: Fast Banded Matrices

Banded matrices show up in many equation solver contexts, such as the Jacobians of many partial differential equations. While the base SparseMatrixCSC sparse matrix type can represent such matrices, BandedMatrices.jl is a specialized format specifically for BandedMatrices which can be used to greatly improve performance of operations on a banded matrix.

BlockBandedMatrices.jl: Fast Block-Banded Matrices

Block banded matrices show up in many equation solver contexts, such as the Jacobians of many systems of partial differential equations. While the base SparseMatrixCSC sparse matrix type can represent such matrices, BlockBandedMatrices.jl is a specialized format specifically for BlockBandedMatrices which can be used to greatly improve performance of operations on a block-banded matrix.

+lorenz_prob = ODEProblem(lorenz!, lorenz_ic, tspan, lorenz_p)

Is that beautiful? Yes, it is.

StaticArrays.jl: Statically-Defined Arrays

StaticArrays.jl is a library for statically-defined arrays. Because these arrays have type-level information for size, they recompile the solvers for every new size. They can be dramatically faster for small sizes (up to approximately size 10), but for larger equations they increase compile time with little to no benefit.

CUDA.jl: NVIDIA CUDA-Based GPU Array Computations

CUDA.jl is the library for defining arrays which live on NVIDIA GPUs (CuArray). SciML's libraries will respect the GPU-ness of the inputs, i.e., if the input arrays live on the GPU then the operations will all take place on the GPU or else the libraries will error if it's unable to do so. Thus, using CUDA.jl's CuArray is how one GPU-accelerates any computation with the SciML organization's libraries. Simply use a CuArray as the initial condition to an ODE solve or as the initial guess for a nonlinear solve, and the whole solve will recompile to take place on the GPU.

AMDGPU.jl: AMD-Based GPU Array Computations

AMDGPU.jl is the library for defining arrays which live on AMD GPUs (ROCArray). SciML's libraries will respect the GPU-ness of the inputs, i.e., if the input arrays live on the GPU then the operations will all take place on the GPU or else the libraries will error if it's unable to do so. Thus using AMDGPU.jl's ROCArray is how one GPU-accelerates any computation with the SciML organization's libraries. Simply use a ROCArray as the initial condition to an ODE solve or as the initial guess for a nonlinear solve, and the whole solve will recompile to take place on the GPU.

FillArrays.jl: Lazy Arrays

FillArrays.jl is a library for defining arrays with lazy values. For example, an O(1) representation of the identity matrix is given by Eye{Int}(5). FillArrays.jl is used extensively throughout the ecosystem to improve runtime and memory performance.

BandedMatrices.jl: Fast Banded Matrices

Banded matrices show up in many equation solver contexts, such as the Jacobians of many partial differential equations. While the base SparseMatrixCSC sparse matrix type can represent such matrices, BandedMatrices.jl is a specialized format specifically for BandedMatrices which can be used to greatly improve performance of operations on a banded matrix.

BlockBandedMatrices.jl: Fast Block-Banded Matrices

Block banded matrices show up in many equation solver contexts, such as the Jacobians of many systems of partial differential equations. While the base SparseMatrixCSC sparse matrix type can represent such matrices, BlockBandedMatrices.jl is a specialized format specifically for BlockBandedMatrices which can be used to greatly improve performance of operations on a block-banded matrix.

diff --git a/dev/highlevels/developer_documentation/index.html b/dev/highlevels/developer_documentation/index.html index 35e05e2b73f..23fceee2fe1 100644 --- a/dev/highlevels/developer_documentation/index.html +++ b/dev/highlevels/developer_documentation/index.html @@ -4,4 +4,4 @@ gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash});

Developer Documentation

For uniformity and clarity, the SciML Open-Source Software Organization has many well-defined rules and practices for its development. However, we stress one important principle:

Do not be deterred from contributing if you think you do not know everything. No one knows everything. These rules and styles are designed for iterative contributions. Open pull requests and contribute what you can with what you know, and the maintainers will help you learn and do the rest!

If you need any help contributing, please feel welcome joining our community channels.

We welcome everybody.

Getting Started With Contributing to SciML

To get started contributing to SciML, check out the following resources:

SciMLStyle: The SciML Style Guide for Julia

SciML Code Style

This is a style guide for how to program in Julia for SciML contributions. It describes everything one needs to know, from preferred naming schemes of functions to fundamental dogmas for designing traits. We stress that this style guide is meant to be comprehensive for the sake of designing automatic formatters and teaching desired rules, but complete knowledge and adherence to the style guide is not required for contributions!

COLPRAC: Contributor's Guide on Collaborative Practices for Community Packages

ColPrac: Contributor's Guide on Collaborative Practices for Community Packages

What are the rules for when PRs should be merged? What are the rules for whether to tag a major, minor, or patch release? All of these development rules are defined in COLPRAC.

DiffEq Developer Documentation

There are many solver libraries which share similar internals, such as OrdinaryDiffEq.jl, StochasticDiffEq.jl, and DelayDiffEq.jl. This section of the documentation describes the internal systems of these packages and how they are used to quickly write efficient solvers.

Third-Party Libraries to Note

Documenter.jl

Documenter.jl is the documentation generation library that the SciML organization uses, and thus its documentation is the documentation of the documentation.

JuliaFormatter.jl

JuliaFormatter.jl is the formatter used by the SciML organization to enforce the SciML Style. Setting style = "sciml" in a .JuliaFormatter.toml file of a repo and using the standard FormatCheck.yml as part of continuous integration makes JuliaFormatter check for SciML Style compliance on pull requests.

To run JuliaFormatter in a SciML repository, do:

using JuliaFomatter, DevedPackage
-JuliaFormatter.format(pkgdir(DevedPackage))

which will reformat the code according to the SciML Style.

GitHub Actions Continuous Integrations

The SciML Organization uses continuous integration testing to always ensure tests are passing when merging pull requests. The organization uses the GitHub Actions supplied by Julia Actions to accomplish this. Common continuous integration scripts are:

  • CI.yml, the standard CI script
  • Downstream.yml, used to specify packages for downstream testing. This will make packages which depend on the current package also be tested to ensure that “non-breaking changes” do not actually break other packages.
  • Documentation.yml, used to run the documentation automatic generation with Documenter.jl
  • FormatCheck.yml, used to check JuliaFormatter SciML Style compliance

CompatHelper

CompatHelper is used to automatically create pull requests whenever a dependent package is upper bounded. The results of CompatHelper PRs should be checked to ensure that the latest version of the dependencies are grabbed for the test process. After successful CompatHelper PRs, i.e. if the increase of the upper bound did not cause a break to the tests, a new version tag should follow. It is set up by adding the CompatHelper.yml GitHub action.

TagBot

TagBot automatically creates tags in the GitHub repository whenever a package is registered to the Julia General repository. It is set up by adding the TagBot.yml GitHub action.

+JuliaFormatter.format(pkgdir(DevedPackage))

which will reformat the code according to the SciML Style.

GitHub Actions Continuous Integrations

The SciML Organization uses continuous integration testing to always ensure tests are passing when merging pull requests. The organization uses the GitHub Actions supplied by Julia Actions to accomplish this. Common continuous integration scripts are:

  • CI.yml, the standard CI script
  • Downstream.yml, used to specify packages for downstream testing. This will make packages which depend on the current package also be tested to ensure that “non-breaking changes” do not actually break other packages.
  • Documentation.yml, used to run the documentation automatic generation with Documenter.jl
  • FormatCheck.yml, used to check JuliaFormatter SciML Style compliance

CompatHelper

CompatHelper is used to automatically create pull requests whenever a dependent package is upper bounded. The results of CompatHelper PRs should be checked to ensure that the latest version of the dependencies are grabbed for the test process. After successful CompatHelper PRs, i.e. if the increase of the upper bound did not cause a break to the tests, a new version tag should follow. It is set up by adding the CompatHelper.yml GitHub action.

TagBot

TagBot automatically creates tags in the GitHub repository whenever a package is registered to the Julia General repository. It is set up by adding the TagBot.yml GitHub action.

diff --git a/dev/highlevels/equation_solvers/index.html b/dev/highlevels/equation_solvers/index.html index b0a9d5bae07..30719612c35 100644 --- a/dev/highlevels/equation_solvers/index.html +++ b/dev/highlevels/equation_solvers/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Equation Solvers

The SciML Equation Solvers cover a large set of SciMLProblems with SciMLAlgorithms that are efficient, numerically stable, and flexible. These methods tie into libraries like SciMLSensitivity.jl to be fully differentiable and compatible with machine learning pipelines, and are designed for integration with applications like parameter estimation, global sensitivity analysis, and more.

LinearSolve.jl: Unified Interface for Linear Solvers

LinearSolve.jl is the canonical library for solving LinearProblems. It includes:

  • Fast pure Julia LU factorizations which outperform standard BLAS
  • KLU for faster sparse LU factorization on unstructured matrices
  • UMFPACK for faster sparse LU factorization on matrices with some repeated structure
  • MKLPardiso wrappers for handling many sparse matrices faster than SuiteSparse (KLU, UMFPACK) methods
  • GPU-offloading for large dense matrices
  • Wrappers to all of the Krylov implementations (Krylov.jl, IterativeSolvers.jl, KrylovKit.jl) for easy testing of all of them. LinearSolve.jl handles the API differences, especially with the preconditioner definitions
  • A polyalgorithm that smartly chooses between these methods
  • A caching interface which automates caching of symbolic factorizations and numerical factorizations as optimally as possible
  • Compatible with arbitrary AbstractArray and Number types, such as GPU-based arrays, uncertainty quantification number types, and more.

NonlinearSolve.jl: Unified Interface for Nonlinear Solvers

NonlinearSolve.jl is the canonical library for solving NonlinearProblems. It includes:

  • Fast non-allocating implementations on static arrays of common methods (Newton-Rhapson)
  • Bracketing methods (Bisection, Falsi) for methods with known upper and lower bounds (IntervalNonlinearProblem)
  • Wrappers to common other solvers (NLsolve.jl, MINPACK, KINSOL from Sundials) for trust region methods, line search-based approaches, etc.
  • Built over the LinearSolve.jl API for maximum flexibility and performance in the solving approach
  • Compatible with arbitrary AbstractArray and Number types, such as GPU-based arrays, uncertainty quantification number types, and more.

DifferentialEquations.jl: Unified Interface for Differential Equation Solvers

DifferentialEquations.jl is the canonical library for solving DEProblems. This includes:

  • Discrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations) (DiscreteProblem)
  • Ordinary differential equations (ODEs) (ODEProblem)
  • Split and Partitioned ODEs (Symplectic integrators, IMEX Methods) (SplitODEProblem)
  • Stochastic ordinary differential equations (SODEs or SDEs) (SDEProblem)
  • Stochastic differential-algebraic equations (SDAEs) (SDEProblem with mass matrices)
  • Random differential equations (RODEs or RDEs) (RODEProblem)
  • Differential algebraic equations (DAEs) (DAEProblem and ODEProblem with mass matrices)
  • Delay differential equations (DDEs) (DDEProblem)
  • Neutral, retarded, and algebraic delay differential equations (NDDEs, RDDEs, and DDAEs)
  • Stochastic delay differential equations (SDDEs) (SDDEProblem)
  • Experimental support for stochastic neutral, retarded, and algebraic delay differential equations (SNDDEs, SRDDEs, and SDDAEs)
  • Mixed discrete and continuous equations (Hybrid Equations, Jump Diffusions) (DEProblems with callbacks and JumpProblem)

The well-optimized DifferentialEquations solvers benchmark as some of the fastest implementations of classic algorithms. It also includes algorithms from recent research which routinely outperform the “standard” C/Fortran methods, and algorithms optimized for high-precision and HPC applications. Simultaneously, it wraps the classic C/Fortran methods, making it easy to switch over to them whenever necessary. Solving differential equations with different methods from different languages and packages can be done by changing one line of code, allowing for easy benchmarking to ensure you are using the fastest method possible.

DifferentialEquations.jl integrates with the Julia package sphere. Examples are:

  • GPU acceleration through CUDAnative.jl and CuArrays.jl
  • Automated sparsity detection with Symbolics.jl
  • Automatic Jacobian coloring with SparseDiffTools.jl, allowing for fast solutions to problems with sparse or structured (Tridiagonal, Banded, BlockBanded, etc.) Jacobians
  • Allowing the specification of linear solvers for maximal efficiency
  • Progress meter integration with the Juno IDE for estimated time to solution
  • Automatic plotting of time series and phase plots
  • Built-in interpolations
  • Wraps for common C/Fortran methods, like Sundials and Hairer's radau
  • Arbitrary precision with BigFloats and Arbfloats
  • Arbitrary array types, allowing the definition of differential equations on matrices and distributed arrays
  • Unit-checked arithmetic with Unitful

Optimization.jl: Unified Interface for Optimization

Optimization.jl is the canonical library for solving OptimizationProblems. It includes wrappers of most of the Julia nonlinear optimization ecosystem, allowing one syntax to use all packages in a uniform manner. This covers:

Integrals.jl: Unified Interface for Numerical Integration

Integrals.jl is the canonical library for solving IntegralsProblems. It includes wrappers of most of the Julia quadrature ecosystem, allowing one syntax to use all packages in a uniform manner. This covers:

  • Gauss-Kronrod quadrature
  • Cubature methods (both h and p cubature)
  • Adaptive Monte Carlo methods

JumpProcesses.jl: Stochastic Simulation Algorithms for Jump Processes, Jump-ODEs, and Jump-Diffusions

JumpProcesses.jl is the library for Poisson jump processes, also known as chemical master equations or Gillespie simulations, for simulating chemical reaction networks and other applications. It allows for solving with many methods, including:

  • Direct: the Gillespie Direct method SSA.
  • RDirect: A variant of Gillespie's Direct method that uses rejection to sample the next reaction.
  • DirectCR: The Composition-Rejection Direct method of Slepoy et al. For large networks and linear chain-type networks, it will often give better performance than Direct. (Requires dependency graph, see below.)
  • DirectFW: the Gillespie Direct method SSA with FunctionWrappers. This aggregator uses a different internal storage format for collections of ConstantRateJumps.
  • FRM: the Gillespie first reaction method SSA. Direct should generally offer better performance and be preferred to FRM.
  • FRMFW: the Gillespie first reaction method SSA with FunctionWrappers.
  • NRM: The Gibson-Bruck Next Reaction Method. For some reaction network structures, this may offer better performance than Direct (for example, large, linear chains of reactions). (Requires dependency graph, see below.)
  • RSSA: The Rejection SSA (RSSA) method of Thanh et al. With RSSACR, for very large reaction networks, it often offers the best performance of all methods. (Requires dependency graph, see below.)
  • RSSACR: The Rejection SSA (RSSA) with Composition-Rejection method of Thanh et al. With RSSA, for very large reaction networks, it often offers the best performance of all methods. (Requires dependency graph, see below.)
  • SortingDirect: The Sorting Direct Method of McCollum et al. It will usually offer performance as good as Direct, and for some systems can offer substantially better performance. (Requires dependency graph, see below.)

The design of JumpProcesses.jl composes with DifferentialEquations.jl, allowing for discrete stochastic chemical reactions to be easily mixed with differential equation models, allowing for simulation of hybrid systems, jump diffusions, and differential equations driven by Levy processes.

In addition, JumpProcesses's interfaces allow for solving with regular jump methods, such as adaptive Tau-Leaping.

Third-Party Libraries to Note

JuMP.jl: Julia for Mathematical Programming

While Optimization.jl is the preferred library for nonlinear optimization, for all other forms of optimization Julia for Mathematical Programming (JuMP) is the star. JuMP is the leading choice in Julia for doing:

  • Linear Programming
  • Quadratic Programming
  • Convex Programming
  • Conic Programming
  • Semidefinite Programming
  • Mixed-Complementarity Programming
  • Integer Programming
  • Mixed Integer (nonlinear/linear) Programming
  • (Mixed Integer) Second Order Conic Programming

JuMP can also be used for some nonlinear programming, though the Optimization.jl bindings to the JuMP solvers (via MathOptInterface.jl) is generally preferred.

FractionalDiffEq.jl: Fractional Differential Equation Solvers

FractionalDiffEq.jl is a set of high-performance solvers for fractional differential equations.

ManifoldDiffEq.jl: Solvers for Differential Equations on Manifolds

ManifoldDiffEq.jl is a set of high-performance solvers for differential equations on manifolds using methods such as Lie Group actions and frozen coefficients (Crouch-Grossman methods). These solvers can in many cases out-perform the OrdinaryDiffEq.jl nonautonomous operator ODE solvers by using methods specialized on manifold definitions of ManifoldsBase.

Manopt.jl: Optimization on Manifolds

ManOpt.jl allows for easy and efficient solving of nonlinear optimization problems on manifolds.

+

Equation Solvers

The SciML Equation Solvers cover a large set of SciMLProblems with SciMLAlgorithms that are efficient, numerically stable, and flexible. These methods tie into libraries like SciMLSensitivity.jl to be fully differentiable and compatible with machine learning pipelines, and are designed for integration with applications like parameter estimation, global sensitivity analysis, and more.

LinearSolve.jl: Unified Interface for Linear Solvers

LinearSolve.jl is the canonical library for solving LinearProblems. It includes:

  • Fast pure Julia LU factorizations which outperform standard BLAS
  • KLU for faster sparse LU factorization on unstructured matrices
  • UMFPACK for faster sparse LU factorization on matrices with some repeated structure
  • MKLPardiso wrappers for handling many sparse matrices faster than SuiteSparse (KLU, UMFPACK) methods
  • GPU-offloading for large dense matrices
  • Wrappers to all of the Krylov implementations (Krylov.jl, IterativeSolvers.jl, KrylovKit.jl) for easy testing of all of them. LinearSolve.jl handles the API differences, especially with the preconditioner definitions
  • A polyalgorithm that smartly chooses between these methods
  • A caching interface which automates caching of symbolic factorizations and numerical factorizations as optimally as possible
  • Compatible with arbitrary AbstractArray and Number types, such as GPU-based arrays, uncertainty quantification number types, and more.

NonlinearSolve.jl: Unified Interface for Nonlinear Solvers

NonlinearSolve.jl is the canonical library for solving NonlinearProblems. It includes:

  • Fast non-allocating implementations on static arrays of common methods (Newton-Rhapson)
  • Bracketing methods (Bisection, Falsi) for methods with known upper and lower bounds (IntervalNonlinearProblem)
  • Wrappers to common other solvers (NLsolve.jl, MINPACK, KINSOL from Sundials) for trust region methods, line search-based approaches, etc.
  • Built over the LinearSolve.jl API for maximum flexibility and performance in the solving approach
  • Compatible with arbitrary AbstractArray and Number types, such as GPU-based arrays, uncertainty quantification number types, and more.

DifferentialEquations.jl: Unified Interface for Differential Equation Solvers

DifferentialEquations.jl is the canonical library for solving DEProblems. This includes:

  • Discrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations) (DiscreteProblem)
  • Ordinary differential equations (ODEs) (ODEProblem)
  • Split and Partitioned ODEs (Symplectic integrators, IMEX Methods) (SplitODEProblem)
  • Stochastic ordinary differential equations (SODEs or SDEs) (SDEProblem)
  • Stochastic differential-algebraic equations (SDAEs) (SDEProblem with mass matrices)
  • Random differential equations (RODEs or RDEs) (RODEProblem)
  • Differential algebraic equations (DAEs) (DAEProblem and ODEProblem with mass matrices)
  • Delay differential equations (DDEs) (DDEProblem)
  • Neutral, retarded, and algebraic delay differential equations (NDDEs, RDDEs, and DDAEs)
  • Stochastic delay differential equations (SDDEs) (SDDEProblem)
  • Experimental support for stochastic neutral, retarded, and algebraic delay differential equations (SNDDEs, SRDDEs, and SDDAEs)
  • Mixed discrete and continuous equations (Hybrid Equations, Jump Diffusions) (DEProblems with callbacks and JumpProblem)

The well-optimized DifferentialEquations solvers benchmark as some of the fastest implementations of classic algorithms. It also includes algorithms from recent research which routinely outperform the “standard” C/Fortran methods, and algorithms optimized for high-precision and HPC applications. Simultaneously, it wraps the classic C/Fortran methods, making it easy to switch over to them whenever necessary. Solving differential equations with different methods from different languages and packages can be done by changing one line of code, allowing for easy benchmarking to ensure you are using the fastest method possible.

DifferentialEquations.jl integrates with the Julia package sphere. Examples are:

  • GPU acceleration through CUDAnative.jl and CuArrays.jl
  • Automated sparsity detection with Symbolics.jl
  • Automatic Jacobian coloring with SparseDiffTools.jl, allowing for fast solutions to problems with sparse or structured (Tridiagonal, Banded, BlockBanded, etc.) Jacobians
  • Allowing the specification of linear solvers for maximal efficiency
  • Progress meter integration with the Juno IDE for estimated time to solution
  • Automatic plotting of time series and phase plots
  • Built-in interpolations
  • Wraps for common C/Fortran methods, like Sundials and Hairer's radau
  • Arbitrary precision with BigFloats and Arbfloats
  • Arbitrary array types, allowing the definition of differential equations on matrices and distributed arrays
  • Unit-checked arithmetic with Unitful

Optimization.jl: Unified Interface for Optimization

Optimization.jl is the canonical library for solving OptimizationProblems. It includes wrappers of most of the Julia nonlinear optimization ecosystem, allowing one syntax to use all packages in a uniform manner. This covers:

Integrals.jl: Unified Interface for Numerical Integration

Integrals.jl is the canonical library for solving IntegralsProblems. It includes wrappers of most of the Julia quadrature ecosystem, allowing one syntax to use all packages in a uniform manner. This covers:

  • Gauss-Kronrod quadrature
  • Cubature methods (both h and p cubature)
  • Adaptive Monte Carlo methods

JumpProcesses.jl: Stochastic Simulation Algorithms for Jump Processes, Jump-ODEs, and Jump-Diffusions

JumpProcesses.jl is the library for Poisson jump processes, also known as chemical master equations or Gillespie simulations, for simulating chemical reaction networks and other applications. It allows for solving with many methods, including:

  • Direct: the Gillespie Direct method SSA.
  • RDirect: A variant of Gillespie's Direct method that uses rejection to sample the next reaction.
  • DirectCR: The Composition-Rejection Direct method of Slepoy et al. For large networks and linear chain-type networks, it will often give better performance than Direct. (Requires dependency graph, see below.)
  • DirectFW: the Gillespie Direct method SSA with FunctionWrappers. This aggregator uses a different internal storage format for collections of ConstantRateJumps.
  • FRM: the Gillespie first reaction method SSA. Direct should generally offer better performance and be preferred to FRM.
  • FRMFW: the Gillespie first reaction method SSA with FunctionWrappers.
  • NRM: The Gibson-Bruck Next Reaction Method. For some reaction network structures, this may offer better performance than Direct (for example, large, linear chains of reactions). (Requires dependency graph, see below.)
  • RSSA: The Rejection SSA (RSSA) method of Thanh et al. With RSSACR, for very large reaction networks, it often offers the best performance of all methods. (Requires dependency graph, see below.)
  • RSSACR: The Rejection SSA (RSSA) with Composition-Rejection method of Thanh et al. With RSSA, for very large reaction networks, it often offers the best performance of all methods. (Requires dependency graph, see below.)
  • SortingDirect: The Sorting Direct Method of McCollum et al. It will usually offer performance as good as Direct, and for some systems can offer substantially better performance. (Requires dependency graph, see below.)

The design of JumpProcesses.jl composes with DifferentialEquations.jl, allowing for discrete stochastic chemical reactions to be easily mixed with differential equation models, allowing for simulation of hybrid systems, jump diffusions, and differential equations driven by Levy processes.

In addition, JumpProcesses's interfaces allow for solving with regular jump methods, such as adaptive Tau-Leaping.

Third-Party Libraries to Note

JuMP.jl: Julia for Mathematical Programming

While Optimization.jl is the preferred library for nonlinear optimization, for all other forms of optimization Julia for Mathematical Programming (JuMP) is the star. JuMP is the leading choice in Julia for doing:

  • Linear Programming
  • Quadratic Programming
  • Convex Programming
  • Conic Programming
  • Semidefinite Programming
  • Mixed-Complementarity Programming
  • Integer Programming
  • Mixed Integer (nonlinear/linear) Programming
  • (Mixed Integer) Second Order Conic Programming

JuMP can also be used for some nonlinear programming, though the Optimization.jl bindings to the JuMP solvers (via MathOptInterface.jl) is generally preferred.

FractionalDiffEq.jl: Fractional Differential Equation Solvers

FractionalDiffEq.jl is a set of high-performance solvers for fractional differential equations.

ManifoldDiffEq.jl: Solvers for Differential Equations on Manifolds

ManifoldDiffEq.jl is a set of high-performance solvers for differential equations on manifolds using methods such as Lie Group actions and frozen coefficients (Crouch-Grossman methods). These solvers can in many cases out-perform the OrdinaryDiffEq.jl nonautonomous operator ODE solvers by using methods specialized on manifold definitions of ManifoldsBase.

Manopt.jl: Optimization on Manifolds

ManOpt.jl allows for easy and efficient solving of nonlinear optimization problems on manifolds.

diff --git a/dev/highlevels/function_approximation/index.html b/dev/highlevels/function_approximation/index.html index 36bb0b96b3f..df89cb83448 100644 --- a/dev/highlevels/function_approximation/index.html +++ b/dev/highlevels/function_approximation/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Function Approximation

While SciML is not an ecosystem for machine learning, SciML has many libraries for doing machine learning with its equation solver libraries and machine learning libraries which are integrated into the equation solvers.

Surrogates.jl: Easy Generation of Differentiable Surrogate Models

Surrogates.jl is a library for generating surrogate approximations to computationally expensive simulations. It has the following high-dimensional function approximators:

  • Kriging
  • Kriging using Stheno
  • Radial Basis
  • Wendland
  • Linear
  • Second Order Polynomial
  • Support Vector Machines (Wait for LIBSVM resolution)
  • Neural Networks
  • Random Forests
  • Lobachevsky splines
  • Inverse-distance
  • Polynomial expansions
  • Variable fidelity
  • Mixture of experts (Waiting GaussianMixtures package to work on v1.5)
  • Earth
  • Gradient Enhanced Kriging

ReservoirComputing.jl: Fast and Flexible Reservoir Computing Methods

ReservoirComputing.jl is a library for doing machine learning using reservoir computing techniques, such as with methods like Echo State Networks (ESNs). Its reservoir computing methods make it stabilized for usage with difficult equations like stiff dynamics, chaotic equations, and more.

Third-Party Libraries to Note

Flux.jl: the ML library that doesn't make you tensor

Flux.jl is the most popular machine learning library in the Julia programming language. SciML's libraries are heavily tested with it and its automatic differentiation engine Zygote.jl for composability and compatibility.

Lux.jl: Explicitly Parameterized Neural Networks in Julia

Lux.jl is a library for fully explicitly parameterized neural networks. Thus, while alternative interfaces are required to use Flux with many equation solvers (i.e. Flux.destructure), Lux.jl's explicit design marries effortlessly with the SciML equation solver libraries. For this reason, SciML's library are also heavily tested with Lux to ensure compatibility with neural network definitions from here.

SimpleChains.jl: Fast Small-Scale Machine Learning

SimpleChains.jl is a library specialized for small-scale machine learning. It uses non-allocating mutating forms to be highly efficient for the cases where matrix multiplication kernels cannot overcome the common overheads of machine learning libraries. Thus for SciML cases with small neural networks (<100 node layers) and non-batched usage (many/most use cases), SimpleChains.jl can be the fastest choice for the neural network definitions.

NNLib.jl: Neural Network Primitives with Multiple Backends

NNLib.jl is the core library which defines the handling of common functions, like conv and how they map to device accelerators such as the NVIDIA cudnn. This library can thus be used to directly grab many of the core functions used in machine learning, such as common activation functions and gather/scatter operations, without depending on the given style of any machine learning library.

GeometricFlux.jl: Geometric Deep Learning and Graph Neural Networks

GeometricFlux.jl is a library for graph neural networks and geometric deep learning. It is the one that is used and tested by the SciML developers for mixing with equation solver applications.

AbstractGPs.jl: Fast and Flexible Gaussian Processes

AbstractGPs.jl is the fast and flexible Gaussian Process library that is used by the SciML packages and recommended for downstream usage.

MLDatasets.jl: Common Machine Learning Datasets

MLDatasets.jl is a common interface for accessing common machine learning datasets. For example, if you want to run a test on MNIST data, MLDatasets is the quickest way to obtain it.

MLUtils.jl: Utility Functions for Machine Learning Pipelines

MLUtils.jl is a library of utility functions for making writing common machine learning pipelines easier. This includes functionality for:

  • An extensible dataset interface (numobs and getobs).
  • Data iteration and data loaders (eachobs and DataLoader).
  • Lazy data views (obsview).
  • Resampling procedures (undersample and oversample).
  • Train/test splits (splitobs)
  • Data partitioning and aggregation tools (batch, unbatch, chunk, group_counts, group_indices).
  • Folds for cross-validation (kfolds, leavepout).
  • Datasets lazy transformations (mapobs, filterobs, groupobs, joinobs, shuffleobs).
  • Toy datasets for demonstration purpose.
  • Other data handling utilities (flatten, normalise, unsqueeze, stack, unstack).
+

Function Approximation

While SciML is not an ecosystem for machine learning, SciML has many libraries for doing machine learning with its equation solver libraries and machine learning libraries which are integrated into the equation solvers.

Surrogates.jl: Easy Generation of Differentiable Surrogate Models

Surrogates.jl is a library for generating surrogate approximations to computationally expensive simulations. It has the following high-dimensional function approximators:

  • Kriging
  • Kriging using Stheno
  • Radial Basis
  • Wendland
  • Linear
  • Second Order Polynomial
  • Support Vector Machines (Wait for LIBSVM resolution)
  • Neural Networks
  • Random Forests
  • Lobachevsky splines
  • Inverse-distance
  • Polynomial expansions
  • Variable fidelity
  • Mixture of experts (Waiting GaussianMixtures package to work on v1.5)
  • Earth
  • Gradient Enhanced Kriging

ReservoirComputing.jl: Fast and Flexible Reservoir Computing Methods

ReservoirComputing.jl is a library for doing machine learning using reservoir computing techniques, such as with methods like Echo State Networks (ESNs). Its reservoir computing methods make it stabilized for usage with difficult equations like stiff dynamics, chaotic equations, and more.

Third-Party Libraries to Note

Flux.jl: the ML library that doesn't make you tensor

Flux.jl is the most popular machine learning library in the Julia programming language. SciML's libraries are heavily tested with it and its automatic differentiation engine Zygote.jl for composability and compatibility.

Lux.jl: Explicitly Parameterized Neural Networks in Julia

Lux.jl is a library for fully explicitly parameterized neural networks. Thus, while alternative interfaces are required to use Flux with many equation solvers (i.e. Flux.destructure), Lux.jl's explicit design marries effortlessly with the SciML equation solver libraries. For this reason, SciML's library are also heavily tested with Lux to ensure compatibility with neural network definitions from here.

SimpleChains.jl: Fast Small-Scale Machine Learning

SimpleChains.jl is a library specialized for small-scale machine learning. It uses non-allocating mutating forms to be highly efficient for the cases where matrix multiplication kernels cannot overcome the common overheads of machine learning libraries. Thus for SciML cases with small neural networks (<100 node layers) and non-batched usage (many/most use cases), SimpleChains.jl can be the fastest choice for the neural network definitions.

NNLib.jl: Neural Network Primitives with Multiple Backends

NNLib.jl is the core library which defines the handling of common functions, like conv and how they map to device accelerators such as the NVIDIA cudnn. This library can thus be used to directly grab many of the core functions used in machine learning, such as common activation functions and gather/scatter operations, without depending on the given style of any machine learning library.

GeometricFlux.jl: Geometric Deep Learning and Graph Neural Networks

GeometricFlux.jl is a library for graph neural networks and geometric deep learning. It is the one that is used and tested by the SciML developers for mixing with equation solver applications.

AbstractGPs.jl: Fast and Flexible Gaussian Processes

AbstractGPs.jl is the fast and flexible Gaussian Process library that is used by the SciML packages and recommended for downstream usage.

MLDatasets.jl: Common Machine Learning Datasets

MLDatasets.jl is a common interface for accessing common machine learning datasets. For example, if you want to run a test on MNIST data, MLDatasets is the quickest way to obtain it.

MLUtils.jl: Utility Functions for Machine Learning Pipelines

MLUtils.jl is a library of utility functions for making writing common machine learning pipelines easier. This includes functionality for:

  • An extensible dataset interface (numobs and getobs).
  • Data iteration and data loaders (eachobs and DataLoader).
  • Lazy data views (obsview).
  • Resampling procedures (undersample and oversample).
  • Train/test splits (splitobs)
  • Data partitioning and aggregation tools (batch, unbatch, chunk, group_counts, group_indices).
  • Folds for cross-validation (kfolds, leavepout).
  • Datasets lazy transformations (mapobs, filterobs, groupobs, joinobs, shuffleobs).
  • Toy datasets for demonstration purpose.
  • Other data handling utilities (flatten, normalise, unsqueeze, stack, unstack).
diff --git a/dev/highlevels/implicit_layers/index.html b/dev/highlevels/implicit_layers/index.html index 67202ea5a18..167352f7f25 100644 --- a/dev/highlevels/implicit_layers/index.html +++ b/dev/highlevels/implicit_layers/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Implicit Layer Deep Learning

Implicit layer deep learning is a field which uses implicit rules, such as differential equations and nonlinear solvers, to define the layers of neural networks. This field has brought the potential to automatically optimize network depth and improve training performance. SciML's differentiable solver ecosystem is specifically designed to accommodate implicit layer methodologies, and provides libraries with pre-built layers for common methods.

DiffEqFlux.jl: High Level Pre-Built Architectures for Implicit Deep Learning

DiffEqFlux.jl is a library of pre-built architectures for implicit deep learning, including layer definitions for methods like:

DeepEquilibriumNetworks.jl: Deep Equilibrium Models Made Fast

DeepEquilibriumNetworks.jl is a library of optimized layer implementations for Deep Equilibrium Models (DEQs). It uses special training techniques such as implicit-explicit regularization in order to accelerate the convergence over traditional implementations, all while using the optimized and flexible SciML libraries under the hood.

+

Implicit Layer Deep Learning

Implicit layer deep learning is a field which uses implicit rules, such as differential equations and nonlinear solvers, to define the layers of neural networks. This field has brought the potential to automatically optimize network depth and improve training performance. SciML's differentiable solver ecosystem is specifically designed to accommodate implicit layer methodologies, and provides libraries with pre-built layers for common methods.

DiffEqFlux.jl: High Level Pre-Built Architectures for Implicit Deep Learning

DiffEqFlux.jl is a library of pre-built architectures for implicit deep learning, including layer definitions for methods like:

DeepEquilibriumNetworks.jl: Deep Equilibrium Models Made Fast

DeepEquilibriumNetworks.jl is a library of optimized layer implementations for Deep Equilibrium Models (DEQs). It uses special training techniques such as implicit-explicit regularization in order to accelerate the convergence over traditional implementations, all while using the optimized and flexible SciML libraries under the hood.

diff --git a/dev/highlevels/interfaces/index.html b/dev/highlevels/interfaces/index.html index a118243dcb1..11f1bdcf1bf 100644 --- a/dev/highlevels/interfaces/index.html +++ b/dev/highlevels/interfaces/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

The SciML Interface Libraries

SciMLBase.jl: The SciML Common Interface

SciMLBase.jl defines the core interfaces of the SciML libraries, such as the definitions of abstract types like SciMLProblem, along with their instantiations like ODEProblem. While SciMLBase.jl is insufficient to solve any equations, it holds all the equation definitions, and thus downstream libraries which wish to allow for using SciML solvers without depending on any solvers can directly depend on SciMLBase.jl.

SciMLOperators.jl: The AbstractSciMLOperator Interface

SciMLOperators.jl defines the interface for how matrix-free linear and affine operators are defined and used throughout the SciML ecosystem.

DiffEqNoiseProcess.jl: The SciML Common Noise Interface

DiffEqNoiseProcess.jl defines the common interface for stochastic noise processes used by the equation solvers of the SciML ecosystem.

CommonSolve.jl: The Common Definition of Solve

CommonSolve.jl is the library that defines the solve, solve!, and init interfaces which are used throughout all the SciML equation solvers. It's defined as an extremely lightweight library so that other ecosystems can build on the same solve definition without clashing with SciML when both export.

Static.jl: A Shared Interface for Static Compile-Time Computation

Static.jl is a set of statically parameterized types for performing operations in a statically-defined (compiler-optimized) way with respect to values.

DiffEqBase.jl: A Library of Shared Components for Differential Equation Solvers

DiffEqBase.jl is the core shared component of the DifferentialEquations.jl ecosystem. It's not intended for non-developer users to interface directly with, instead it's used for the common functionality for uniformity of implementation between the solver libraries.

Third-Party Libraries to Note

ArrayInterface.jl: Extensions to the Julia AbstractArray Interface

ArrayInterface.jl are traits and functions which extend the Julia Base AbstractArray interface, giving a much larger set of queries to allow for writing high-performance generic code over all array types. For example, functions include can_change_size to know if an AbstractArray type is compatible with resize!, fast_scalar_indexing to know whether direct scalar indexing A[i] is optimized, and functions like findstructralnz to get the structural non-zeros of arbitrary sparse and structured matrices.

Adapt.jl: Conversion to Allow Chip-Generic Programs

Adapt.jl makes it possible to write code that is generic to the compute devices, i.e. code that works on both CPUs and GPUs. It defines the adapt function which acts like convert(T, x), but without the restriction of returning a T. This allows you to “convert” wrapper types, like Adjoint to be GPU compatible (for example) without throwing away the wrapper.

Example usage:

adapt(CuArray, ::Adjoint{Array})::Adjoint{CuArray}

AbstractFFTs.jl: High Level Shared Interface for Fast Fourier Transformation Libraries

AbstractFFTs.jl defines the common interface for Fast Fourier Transformations (FFTs) in Julia. Similar to SciMLBase.jl, AbstractFFTs.jl is not a solver library but instead a shared API which is extended by solver libraries such as FFTW.jl. Code written using AbstractFFTs.jl can be made compatible with FFT libraries without having an explicit dependency on a solver.

GPUArrays.jl: Common Interface for GPU-Based Array Types

GPUArrays.jl defines the shared higher-level operations for GPU-based array types, like CUDA.jl's CuArray and AMDGPU.jl's ROCmArray. Packages in SciML use the designation x isa AbstractGPUArray in order to find out if a user's operation is on the GPU and specialize computations.

RecipesBase.jl: Standard Plotting Recipe Interface

RecipesBase.jl defines the common interface for plotting recipes, composable transformations of Julia data types into simpler data types for visualization with libraries such as Plots.jl and Makie.jl. SciML libraries attempt to always include plot recipes wherever possible for ease of visualization.

Tables.jl: Common Interface for Tabular Data Types

Tables.jl is a common interface for defining tabular data structures, such as DataFrames.jl. SciML's libraries extend the Tables.jl interface to allow for automated conversions into data frame libraries without explicit dependence on any singular implementation.

+

The SciML Interface Libraries

SciMLBase.jl: The SciML Common Interface

SciMLBase.jl defines the core interfaces of the SciML libraries, such as the definitions of abstract types like SciMLProblem, along with their instantiations like ODEProblem. While SciMLBase.jl is insufficient to solve any equations, it holds all the equation definitions, and thus downstream libraries which wish to allow for using SciML solvers without depending on any solvers can directly depend on SciMLBase.jl.

SciMLOperators.jl: The AbstractSciMLOperator Interface

SciMLOperators.jl defines the interface for how matrix-free linear and affine operators are defined and used throughout the SciML ecosystem.

DiffEqNoiseProcess.jl: The SciML Common Noise Interface

DiffEqNoiseProcess.jl defines the common interface for stochastic noise processes used by the equation solvers of the SciML ecosystem.

CommonSolve.jl: The Common Definition of Solve

CommonSolve.jl is the library that defines the solve, solve!, and init interfaces which are used throughout all the SciML equation solvers. It's defined as an extremely lightweight library so that other ecosystems can build on the same solve definition without clashing with SciML when both export.

Static.jl: A Shared Interface for Static Compile-Time Computation

Static.jl is a set of statically parameterized types for performing operations in a statically-defined (compiler-optimized) way with respect to values.

DiffEqBase.jl: A Library of Shared Components for Differential Equation Solvers

DiffEqBase.jl is the core shared component of the DifferentialEquations.jl ecosystem. It's not intended for non-developer users to interface directly with, instead it's used for the common functionality for uniformity of implementation between the solver libraries.

Third-Party Libraries to Note

ArrayInterface.jl: Extensions to the Julia AbstractArray Interface

ArrayInterface.jl are traits and functions which extend the Julia Base AbstractArray interface, giving a much larger set of queries to allow for writing high-performance generic code over all array types. For example, functions include can_change_size to know if an AbstractArray type is compatible with resize!, fast_scalar_indexing to know whether direct scalar indexing A[i] is optimized, and functions like findstructralnz to get the structural non-zeros of arbitrary sparse and structured matrices.

Adapt.jl: Conversion to Allow Chip-Generic Programs

Adapt.jl makes it possible to write code that is generic to the compute devices, i.e. code that works on both CPUs and GPUs. It defines the adapt function which acts like convert(T, x), but without the restriction of returning a T. This allows you to “convert” wrapper types, like Adjoint to be GPU compatible (for example) without throwing away the wrapper.

Example usage:

adapt(CuArray, ::Adjoint{Array})::Adjoint{CuArray}

AbstractFFTs.jl: High Level Shared Interface for Fast Fourier Transformation Libraries

AbstractFFTs.jl defines the common interface for Fast Fourier Transformations (FFTs) in Julia. Similar to SciMLBase.jl, AbstractFFTs.jl is not a solver library but instead a shared API which is extended by solver libraries such as FFTW.jl. Code written using AbstractFFTs.jl can be made compatible with FFT libraries without having an explicit dependency on a solver.

GPUArrays.jl: Common Interface for GPU-Based Array Types

GPUArrays.jl defines the shared higher-level operations for GPU-based array types, like CUDA.jl's CuArray and AMDGPU.jl's ROCmArray. Packages in SciML use the designation x isa AbstractGPUArray in order to find out if a user's operation is on the GPU and specialize computations.

RecipesBase.jl: Standard Plotting Recipe Interface

RecipesBase.jl defines the common interface for plotting recipes, composable transformations of Julia data types into simpler data types for visualization with libraries such as Plots.jl and Makie.jl. SciML libraries attempt to always include plot recipes wherever possible for ease of visualization.

Tables.jl: Common Interface for Tabular Data Types

Tables.jl is a common interface for defining tabular data structures, such as DataFrames.jl. SciML's libraries extend the Tables.jl interface to allow for automated conversions into data frame libraries without explicit dependence on any singular implementation.

diff --git a/dev/highlevels/inverse_problems/index.html b/dev/highlevels/inverse_problems/index.html index 5678115518d..bd39f80e296 100644 --- a/dev/highlevels/inverse_problems/index.html +++ b/dev/highlevels/inverse_problems/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Parameter Estimation, Bayesian Analysis, and Inverse Problems

Parameter estimation for models and equations, also known as dynamic data analysis, solving the inverse problem, or Bayesian posterior estimation (when done probabilistically), is provided by the SciML tools for the equations in its set. In this introduction, we briefly present the relevant packages that facilitate parameter estimation, namely:

We also provide information regarding the respective strengths of these packages so that you can easily decide which one suits your needs best.

SciMLSensitivity.jl: Local Sensitivity Analysis and Automatic Differentiation Support for Solvers

SciMLSensitivity.jl is the system for local sensitivity, which all other inverse problem methods rely on. This package defines the interactions between the equation solvers and automatic differentiation, defining fast overloads for forward and adjoint (reverse) sensitivity analysis for fast gradient and Jacobian calculations with respect to model inputs. Its documentation covers how to use direct differentiation of equation solvers in conjunction with tools like Optimization.jl to perform model calibration of ODEs against data, PDE-constrained optimization, nonlinear optimal controls analysis, and much more. As a lower level tool, this library is very versatile, feature-rich, and high-performance, giving all the tools required but not directly providing a higher level interface.

Note

Sensitivity analysis is kept in a separate library from the solvers (SciMLSensitivity.jl), in order to not require all equation solvers to have a dependency on all automatic differentiation libraries. If automatic differentiation is applied to a solver library without importing SciMLSensitivity.jl, an error is thrown letting the user know to import SciMLSensitivity.jl for the functionality to exist.

DataDrivenDiffEq.jl: Data-Driven Modeling and Equation Discovery

The distinguishing feature of this package is that its ultimate goal is to identify the differential equation model that generated the input data. Depending on the user's needs, the package can provide structural identification of a given differential equation (output in a symbolic form) or structural estimation (output as a function for prediction purposes).

DiffEqParamEstim.jl: Simplified Parameter Estimation Interface

This package is for simplified parameter estimation. While not as flexible of a system like DiffEqFlux.jl, it provides ready-made functions for doing standard optimization procedures like L2 fitting and MAP estimates. Among other features, it allows for the optimization of parameters in ODEs, stochastic problems, and delay differential equations.

DiffEqBayes.jl: Simplified Bayesian Estimation Interface

As the name suggests, this package has been designed to provide the estimation of differential equations parameters by Bayesian methods. It works in conjunction with Turing.jl, CmdStan.jl, DynamicHMC.jl, and ApproxBayes.jl. While not as flexible as direct usage of DiffEqFlux.jl or Turing.jl, DiffEqBayes.jl can be an approachable interface for those not familiar with Bayesian estimation, and provides a nice way to use Stan from pure Julia.

Third-Party Tools of Note

Turing.jl: A Flexible Probabilistic Programming Language for Bayesian Analysis

In the context of differential equations and parameter estimation, Turing.jl allows for a Bayesian estimation of differential equations (used in conjunction with the high-level package DiffEqBayes.jl). For more examples on combining Turing.jl with DiffEqBayes.jl, see the documentation below. It is important to note that Turing.jl can also perform Bayesian estimation without relying on DiffEqBayes.jl (for an example, consult this tutorial).

Topopt.jl: Topology Optimization in Julia

Topopt.jl solves topology optimization problems which are inverse problems on partial differential equations, solving for an optimal domain.

Recommended Automatic Differentiation Libraries

Solving inverse problems commonly requires using automatic differentiation (AD). SciML includes extensive support for automatic differentiation throughout its solvers, though some AD libraries are more tested than others. The following libraries are the current recommendations of the SciML developers.

ForwardDiff.jl: Operator-Overloading Forward Mode Automatic Differentiation

ForwardDiff.jl is a library for operator-overloading based forward-mode automatic differentiation. It's commonly used as the default method for generating Jacobians throughout the SciML solver libraries.

Note

Because ForwardDiff.jl uses an operator overloading approach, uses of ForwardDiff.jl require that any caches for non-allocating mutating code allows for Dual numbers. To allow such code to be ForwardDiff.jl-compatible, see PreallocationTools.jl.

Enzyme.jl: LLVM-Level Forward and Reverse Mode Automatic Differentiation

Enzyme.jl is an LLVM-level AD library for forward and reverse automatic differentiation. It supports many features required for high performance, such as being able to differentiate mutating and interleave compiler optimization with the AD passes. However, it does not support all of the Julia runtime, and thus some code with many dynamic behaviors and garbage collection (GC) invocations can be incompatible with Enzyme. Enzyme.jl is quickly becoming the new standard AD for SciML.

Zygote.jl: Julia-Level Source-to-Source Reverse Mode Automatic Differentiation

Zygote.jl is the current standard user-level reverse-mode automatic differentiation library for the SciML solvers. User-level means that many library tutorials, like in SciMLSensitivity.jl and DiffEqFlux.jl, showcase user code using Zygote.jl. This is because Zygote.jl is the AD engine associated with the Flux machine learning library. However, Zygote.jl has many limitations which limits its performance in equation solver contexts, such as an inability to handle mutation and introducing many small allocations and type-instabilities. For this reason, the SciML equation solvers define differentiation overloads using ChainRules.jl, meaning that the equation solvers tend not to use Zygote.jl internally even if the user code uses Zygote.gradient. In this manner, the speed and performance of more advanced techniques can be preserved while using the Julia standard.

FiniteDiff.jl: Fast Finite Difference Approximations

FiniteDiff.jl is the preferred fallback library for numerical differentiation and is commonly used by SciML solver libraries when automatic differentiation is disabled.

SparseDiffTools.jl: Tools for Fast Automatic Differentiation with Sparse Operators

SparseDiffTools.jl is a library for sparse automatic differentiation. It's used internally by many of the SciML equation solver libraries, which explicitly expose interfaces for colorvec color vectors generated by SparseDiffTools.jl's methods. SparseDiffTools.jl also includes many features useful to users, such as operators for matrix-free Jacobian-vector and Hessian-vector products.

+

Parameter Estimation, Bayesian Analysis, and Inverse Problems

Parameter estimation for models and equations, also known as dynamic data analysis, solving the inverse problem, or Bayesian posterior estimation (when done probabilistically), is provided by the SciML tools for the equations in its set. In this introduction, we briefly present the relevant packages that facilitate parameter estimation, namely:

We also provide information regarding the respective strengths of these packages so that you can easily decide which one suits your needs best.

SciMLSensitivity.jl: Local Sensitivity Analysis and Automatic Differentiation Support for Solvers

SciMLSensitivity.jl is the system for local sensitivity, which all other inverse problem methods rely on. This package defines the interactions between the equation solvers and automatic differentiation, defining fast overloads for forward and adjoint (reverse) sensitivity analysis for fast gradient and Jacobian calculations with respect to model inputs. Its documentation covers how to use direct differentiation of equation solvers in conjunction with tools like Optimization.jl to perform model calibration of ODEs against data, PDE-constrained optimization, nonlinear optimal controls analysis, and much more. As a lower level tool, this library is very versatile, feature-rich, and high-performance, giving all the tools required but not directly providing a higher level interface.

Note

Sensitivity analysis is kept in a separate library from the solvers (SciMLSensitivity.jl), in order to not require all equation solvers to have a dependency on all automatic differentiation libraries. If automatic differentiation is applied to a solver library without importing SciMLSensitivity.jl, an error is thrown letting the user know to import SciMLSensitivity.jl for the functionality to exist.

DataDrivenDiffEq.jl: Data-Driven Modeling and Equation Discovery

The distinguishing feature of this package is that its ultimate goal is to identify the differential equation model that generated the input data. Depending on the user's needs, the package can provide structural identification of a given differential equation (output in a symbolic form) or structural estimation (output as a function for prediction purposes).

DiffEqParamEstim.jl: Simplified Parameter Estimation Interface

This package is for simplified parameter estimation. While not as flexible of a system like DiffEqFlux.jl, it provides ready-made functions for doing standard optimization procedures like L2 fitting and MAP estimates. Among other features, it allows for the optimization of parameters in ODEs, stochastic problems, and delay differential equations.

DiffEqBayes.jl: Simplified Bayesian Estimation Interface

As the name suggests, this package has been designed to provide the estimation of differential equations parameters by Bayesian methods. It works in conjunction with Turing.jl, CmdStan.jl, DynamicHMC.jl, and ApproxBayes.jl. While not as flexible as direct usage of DiffEqFlux.jl or Turing.jl, DiffEqBayes.jl can be an approachable interface for those not familiar with Bayesian estimation, and provides a nice way to use Stan from pure Julia.

Third-Party Tools of Note

Turing.jl: A Flexible Probabilistic Programming Language for Bayesian Analysis

In the context of differential equations and parameter estimation, Turing.jl allows for a Bayesian estimation of differential equations (used in conjunction with the high-level package DiffEqBayes.jl). For more examples on combining Turing.jl with DiffEqBayes.jl, see the documentation below. It is important to note that Turing.jl can also perform Bayesian estimation without relying on DiffEqBayes.jl (for an example, consult this tutorial).

Topopt.jl: Topology Optimization in Julia

Topopt.jl solves topology optimization problems which are inverse problems on partial differential equations, solving for an optimal domain.

Recommended Automatic Differentiation Libraries

Solving inverse problems commonly requires using automatic differentiation (AD). SciML includes extensive support for automatic differentiation throughout its solvers, though some AD libraries are more tested than others. The following libraries are the current recommendations of the SciML developers.

ForwardDiff.jl: Operator-Overloading Forward Mode Automatic Differentiation

ForwardDiff.jl is a library for operator-overloading based forward-mode automatic differentiation. It's commonly used as the default method for generating Jacobians throughout the SciML solver libraries.

Note

Because ForwardDiff.jl uses an operator overloading approach, uses of ForwardDiff.jl require that any caches for non-allocating mutating code allows for Dual numbers. To allow such code to be ForwardDiff.jl-compatible, see PreallocationTools.jl.

Enzyme.jl: LLVM-Level Forward and Reverse Mode Automatic Differentiation

Enzyme.jl is an LLVM-level AD library for forward and reverse automatic differentiation. It supports many features required for high performance, such as being able to differentiate mutating and interleave compiler optimization with the AD passes. However, it does not support all of the Julia runtime, and thus some code with many dynamic behaviors and garbage collection (GC) invocations can be incompatible with Enzyme. Enzyme.jl is quickly becoming the new standard AD for SciML.

Zygote.jl: Julia-Level Source-to-Source Reverse Mode Automatic Differentiation

Zygote.jl is the current standard user-level reverse-mode automatic differentiation library for the SciML solvers. User-level means that many library tutorials, like in SciMLSensitivity.jl and DiffEqFlux.jl, showcase user code using Zygote.jl. This is because Zygote.jl is the AD engine associated with the Flux machine learning library. However, Zygote.jl has many limitations which limits its performance in equation solver contexts, such as an inability to handle mutation and introducing many small allocations and type-instabilities. For this reason, the SciML equation solvers define differentiation overloads using ChainRules.jl, meaning that the equation solvers tend not to use Zygote.jl internally even if the user code uses Zygote.gradient. In this manner, the speed and performance of more advanced techniques can be preserved while using the Julia standard.

FiniteDiff.jl: Fast Finite Difference Approximations

FiniteDiff.jl is the preferred fallback library for numerical differentiation and is commonly used by SciML solver libraries when automatic differentiation is disabled.

SparseDiffTools.jl: Tools for Fast Automatic Differentiation with Sparse Operators

SparseDiffTools.jl is a library for sparse automatic differentiation. It's used internally by many of the SciML equation solver libraries, which explicitly expose interfaces for colorvec color vectors generated by SparseDiffTools.jl's methods. SparseDiffTools.jl also includes many features useful to users, such as operators for matrix-free Jacobian-vector and Hessian-vector products.

diff --git a/dev/highlevels/learning_resources/index.html b/dev/highlevels/learning_resources/index.html index 196075adb48..710f133e18c 100644 --- a/dev/highlevels/learning_resources/index.html +++ b/dev/highlevels/learning_resources/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Curated Learning, Teaching, and Training Resources

While the SciML documentation is made to be comprehensive, there will always be good alternative resources. The purpose of this section of the documentation is to highlight the alternative resources which can be helpful for learning how to use the SciML Open-Source Software libraries.

JuliaCon and SciMLCon Videos

Many tutorials and introductions to packages have been taught through previous JuliaCon/SciMLCon workshops and talks. The following is a curated list of such training videos:

SciML Book: Parallel Computing and Scientific Machine Learning (SciML): Methods and Applications

The book Parallel Computing and Scientific Machine Learning (SciML): Methods and Applications is a compilation of the lecture notes from the MIT Course 18.337J/6.338J: Parallel Computing and Scientific Machine Learning. It contains a walkthrough of many of the methods implemented in the SciML libraries, as well as how to understand much of the functionality at a deeper level. This course was intended for MIT graduate students in engineering, computer science, and mathematics and thus may have a high prerequisite requirement than many other resources.

sir-julia: Various implementations of the classical SIR model in Julia

For those who like to learn by example, the repository sir-julia is a great resource! It showcases how to use the SciML libraries in many different ways to simulate different variations of the classic SIR epidemic model.

Other Books Featuring SciML

+

Curated Learning, Teaching, and Training Resources

While the SciML documentation is made to be comprehensive, there will always be good alternative resources. The purpose of this section of the documentation is to highlight the alternative resources which can be helpful for learning how to use the SciML Open-Source Software libraries.

JuliaCon and SciMLCon Videos

Many tutorials and introductions to packages have been taught through previous JuliaCon/SciMLCon workshops and talks. The following is a curated list of such training videos:

SciML Book: Parallel Computing and Scientific Machine Learning (SciML): Methods and Applications

The book Parallel Computing and Scientific Machine Learning (SciML): Methods and Applications is a compilation of the lecture notes from the MIT Course 18.337J/6.338J: Parallel Computing and Scientific Machine Learning. It contains a walkthrough of many of the methods implemented in the SciML libraries, as well as how to understand much of the functionality at a deeper level. This course was intended for MIT graduate students in engineering, computer science, and mathematics and thus may have a high prerequisite requirement than many other resources.

sir-julia: Various implementations of the classical SIR model in Julia

For those who like to learn by example, the repository sir-julia is a great resource! It showcases how to use the SciML libraries in many different ways to simulate different variations of the classic SIR epidemic model.

Other Books Featuring SciML

diff --git a/dev/highlevels/model_libraries_and_importers/index.html b/dev/highlevels/model_libraries_and_importers/index.html index 2ce9a96843f..32c7c6fe8c1 100644 --- a/dev/highlevels/model_libraries_and_importers/index.html +++ b/dev/highlevels/model_libraries_and_importers/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Model Libraries and Importers

Models are passed on from generation to generation. Many models are not built from scratch but have a legacy of the known physics, biology, and chemistry embedded into them. Julia's SciML offers a range of pre-built modeling tools, from reusable acausal components to direct imports from common file formats.

ModelingToolkitStandardLibrary.jl: A Standard Library for ModelingToolkit

Given the composable nature of acausal modeling systems, it's helpful to not have to define every component from scratch and instead build off a common base of standard components. ModelingToolkitStandardLibrary.jl is that library. It provides components for standard models to start building everything from circuits and engines to robots.

DiffEqCallbacks.jl: Pre-Made Callbacks for DifferentialEquations.jl

DiffEqCallbacks.jl has many event handling and callback definitions which allow for quickly building up complex differential equation models. It includes:

  • Callbacks for specialized output and saving procedures
  • Callbacks for enforcing domain constraints, positivity, and manifolds
  • Timed callbacks for periodic dosing, presetting of tstops, and more
  • Callbacks for determining and terminating at steady state
  • Callbacks for controlling stepsizes and enforcing CFL conditions
  • Callbacks for quantifying uncertainty with respect to numerical errors

SBMLToolkit.jl: SBML Import

SBMLToolkit.jl is a library for reading SBML files into the standard formats for Catalyst.jl and ModelingToolkit.jl. There are well over one thousand biological models available in the BioModels Repository.

CellMLToolkit.jl: CellML Import

CellMLToolkit.jl is a library for reading CellML files into the standard formats for ModelingToolkit.jl. There are several hundred biological models available in the CellML Model Repository.

ReactionNetworkImporters.jl: BioNetGen Import

ReactionNetworkImporters.jl is a library for reading BioNetGen .net files and various stoichiometry matrix representations into the standard formats for Catalyst.jl and ModelingToolkit.jl.

+

Model Libraries and Importers

Models are passed on from generation to generation. Many models are not built from scratch but have a legacy of the known physics, biology, and chemistry embedded into them. Julia's SciML offers a range of pre-built modeling tools, from reusable acausal components to direct imports from common file formats.

ModelingToolkitStandardLibrary.jl: A Standard Library for ModelingToolkit

Given the composable nature of acausal modeling systems, it's helpful to not have to define every component from scratch and instead build off a common base of standard components. ModelingToolkitStandardLibrary.jl is that library. It provides components for standard models to start building everything from circuits and engines to robots.

DiffEqCallbacks.jl: Pre-Made Callbacks for DifferentialEquations.jl

DiffEqCallbacks.jl has many event handling and callback definitions which allow for quickly building up complex differential equation models. It includes:

  • Callbacks for specialized output and saving procedures
  • Callbacks for enforcing domain constraints, positivity, and manifolds
  • Timed callbacks for periodic dosing, presetting of tstops, and more
  • Callbacks for determining and terminating at steady state
  • Callbacks for controlling stepsizes and enforcing CFL conditions
  • Callbacks for quantifying uncertainty with respect to numerical errors

SBMLToolkit.jl: SBML Import

SBMLToolkit.jl is a library for reading SBML files into the standard formats for Catalyst.jl and ModelingToolkit.jl. There are well over one thousand biological models available in the BioModels Repository.

CellMLToolkit.jl: CellML Import

CellMLToolkit.jl is a library for reading CellML files into the standard formats for ModelingToolkit.jl. There are several hundred biological models available in the CellML Model Repository.

ReactionNetworkImporters.jl: BioNetGen Import

ReactionNetworkImporters.jl is a library for reading BioNetGen .net files and various stoichiometry matrix representations into the standard formats for Catalyst.jl and ModelingToolkit.jl.

diff --git a/dev/highlevels/modeling_languages/index.html b/dev/highlevels/modeling_languages/index.html index 7a5d42ea5c0..fa3bce3640b 100644 --- a/dev/highlevels/modeling_languages/index.html +++ b/dev/highlevels/modeling_languages/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Modeling Languages

While in theory one can build perfect code for all models from scratch, in practice many scientists and engineers need or want some help! The SciML modeling tools provide a higher level interface over the equation solver, which helps the translation from good models to good simulations in a way that abstracts away the mathematical and computational details without giving up performance.

ModelingToolkit.jl: Acausal Symbolic Modeling

Acausal modeling is an extension of causal modeling that is more composable and allows for more code reuse. Build a model of an electric engine, then build a model of a battery, and now declare connections by stating "the voltage at the engine equals the voltage at the connector of the battery", and generate the composed model. The tool for this is ModelingToolkit.jl. ModelingToolkit.jl is a sophisticated symbolic modeling library which allows for specifying these types of large-scale differential equation models in a simple way, abstracting away the computational details. However, its symbolic analysis allows for generating much more performant code for differential-algebraic equations than most users could ever write by hand, with its structural_simplify automatically correcting the model to improve parallelism, numerical stability, and automatically remove variables which it can show are redundant.

ModelingToolkit.jl is the base of the SciML symbolic modeling ecosystem, defining the AbstractSystem types, such as ODESystem, SDESystem, OptimizationSystem, PDESystem, and more, which are then used by all the other modeling tools. As such, when using other modeling tools like Catalyst.jl, the reference for all the things that can be done with the symbolic representation is simply ModelingToolkit.jl.

Catalyst.jl: Chemical Reaction Networks (CRN), Systems Biology, and Quantitative Systems Pharmacology (QSP) Modeling

Catalyst.jl is a modeling interface for efficient simulation of mass action ODE, chemical Langevin SDE, and stochastic chemical kinetics jump process (i.e. chemical master equation) models for chemical reaction networks and population processes. It uses a highly intuitive chemical reaction syntax interface, which generates all the extra functionality necessary for the fastest use with JumpProcesses.jl, DifferentialEquations.jl, and higher level SciML libraries. Its ReactionSystem type is a programmable extension of the ModelingToolkit AbstractSystem interface, meaning that complex reaction systems are represented symbolically, and then compiled to optimized representations automatically when converting ReactionSystems to concrete ODE/SDE/jump process representations. Catalyst also provides functionality to support chemical reaction network and steady-state analysis.

For an overview of the library, see Modeling Biochemical Systems with Catalyst.jl - Samuel Isaacson

NBodySimulator.jl: A differentiable simulator for N-body problems, including astrophysical and molecular dynamics

NBodySimulator.jl is a differentiable simulator for N-body problems, including astrophysical and molecular dynamics. It uses the DifferentialEquations.jl solvers, allowing for one to choose between a large variety of symplectic integration schemes. It implements many of the thermostats required for doing standard molecular dynamics approximations.

DiffEqFinancial.jl: Financial models for use in the DifferentialEquations ecosystem

The goal of DiffEqFinancial.jl is to be a feature-complete set of solvers for the types of problems found in libraries like QuantLib, such as the Heston process or the Black-Scholes model.

ParameterizedFunctions.jl: Simple Differential Equation Definitions Made Easy

This image that went viral is actually runnable code from ParameterizedFunctions.jl. Define equations and models using a very simple high-level syntax and let the code generation tools build symbolic fast Jacobian, gradient, etc. functions for you.

Third-Party Tools of Note

MomentClosure.jl: Automated Generation of Moment Closure Equations

MomentClosure.jl is a library for generating the moment closure equations for a given chemical master equation or stochastic differential equation. Thus instead of solving a stochastic model thousands of times to find the mean and variance, this library can generate the deterministic equations for how the mean and variance evolve in order to be solved in a single run. MomentClosure.jl uses Catalyst ReactionSystem and ModelingToolkit SDESystem types as the input for its symbolic generation processes.

Agents.jl: Agent-Based Modeling Framework in Julia

If one wants to do agent-based modeling in Julia, Agents.jl is the go-to library. It's fast and flexible, making it a solid foundation for any agent-based model.

Unitful.jl: A Julia package for physical units

Supports not only SI units, but also any other unit system. Unitful.jl has minimal run-time penalty of units. Includes facilities for dimensional analysis, and integrates easily with the usual mathematical operations and collections that are defined in Julia.

ReactionMechanismSimulator.jl: Simulation and Analysis of Large Chemical Reaction Systems

ReactionMechanismSimulator.jl is a tool for simulating and analyzing large chemical reaction mechanisms. It interfaces with the ReactionMechanismGenerator suite for automatically constructing reaction pathways from chemical components to quickly build realistic models of chemical systems.

FiniteStateProjection.jl: Direct Solution of Chemical Master Equations

FiniteStateProjection.jl is a library for finite state projection direct solving of the chemical master equation. It automatically converts the Catalyst ReactionSystem definitions into ModelingToolkit ODESystem representations for the evolution of probability distributions to allow for directly solving the weak form of the stochastic model.

AlgebraicPetri.jl: Applied Category Theory of Modeling

AlgebraicPetri.jl is a library for automating the intuitive generation of dynamical models using a Category theory-based approach.

QuantumOptics.jl: Simulating quantum systems.

QuantumOptics.jl makes it easy to simulate various kinds of quantum systems. It is inspired by the Quantum Optics Toolbox for MATLAB and the Python framework QuTiP.

+

Modeling Languages

While in theory one can build perfect code for all models from scratch, in practice many scientists and engineers need or want some help! The SciML modeling tools provide a higher level interface over the equation solver, which helps the translation from good models to good simulations in a way that abstracts away the mathematical and computational details without giving up performance.

ModelingToolkit.jl: Acausal Symbolic Modeling

Acausal modeling is an extension of causal modeling that is more composable and allows for more code reuse. Build a model of an electric engine, then build a model of a battery, and now declare connections by stating "the voltage at the engine equals the voltage at the connector of the battery", and generate the composed model. The tool for this is ModelingToolkit.jl. ModelingToolkit.jl is a sophisticated symbolic modeling library which allows for specifying these types of large-scale differential equation models in a simple way, abstracting away the computational details. However, its symbolic analysis allows for generating much more performant code for differential-algebraic equations than most users could ever write by hand, with its structural_simplify automatically correcting the model to improve parallelism, numerical stability, and automatically remove variables which it can show are redundant.

ModelingToolkit.jl is the base of the SciML symbolic modeling ecosystem, defining the AbstractSystem types, such as ODESystem, SDESystem, OptimizationSystem, PDESystem, and more, which are then used by all the other modeling tools. As such, when using other modeling tools like Catalyst.jl, the reference for all the things that can be done with the symbolic representation is simply ModelingToolkit.jl.

Catalyst.jl: Chemical Reaction Networks (CRN), Systems Biology, and Quantitative Systems Pharmacology (QSP) Modeling

Catalyst.jl is a modeling interface for efficient simulation of mass action ODE, chemical Langevin SDE, and stochastic chemical kinetics jump process (i.e. chemical master equation) models for chemical reaction networks and population processes. It uses a highly intuitive chemical reaction syntax interface, which generates all the extra functionality necessary for the fastest use with JumpProcesses.jl, DifferentialEquations.jl, and higher level SciML libraries. Its ReactionSystem type is a programmable extension of the ModelingToolkit AbstractSystem interface, meaning that complex reaction systems are represented symbolically, and then compiled to optimized representations automatically when converting ReactionSystems to concrete ODE/SDE/jump process representations. Catalyst also provides functionality to support chemical reaction network and steady-state analysis.

For an overview of the library, see Modeling Biochemical Systems with Catalyst.jl - Samuel Isaacson

NBodySimulator.jl: A differentiable simulator for N-body problems, including astrophysical and molecular dynamics

NBodySimulator.jl is a differentiable simulator for N-body problems, including astrophysical and molecular dynamics. It uses the DifferentialEquations.jl solvers, allowing for one to choose between a large variety of symplectic integration schemes. It implements many of the thermostats required for doing standard molecular dynamics approximations.

DiffEqFinancial.jl: Financial models for use in the DifferentialEquations ecosystem

The goal of DiffEqFinancial.jl is to be a feature-complete set of solvers for the types of problems found in libraries like QuantLib, such as the Heston process or the Black-Scholes model.

ParameterizedFunctions.jl: Simple Differential Equation Definitions Made Easy

This image that went viral is actually runnable code from ParameterizedFunctions.jl. Define equations and models using a very simple high-level syntax and let the code generation tools build symbolic fast Jacobian, gradient, etc. functions for you.

Third-Party Tools of Note

MomentClosure.jl: Automated Generation of Moment Closure Equations

MomentClosure.jl is a library for generating the moment closure equations for a given chemical master equation or stochastic differential equation. Thus instead of solving a stochastic model thousands of times to find the mean and variance, this library can generate the deterministic equations for how the mean and variance evolve in order to be solved in a single run. MomentClosure.jl uses Catalyst ReactionSystem and ModelingToolkit SDESystem types as the input for its symbolic generation processes.

Agents.jl: Agent-Based Modeling Framework in Julia

If one wants to do agent-based modeling in Julia, Agents.jl is the go-to library. It's fast and flexible, making it a solid foundation for any agent-based model.

Unitful.jl: A Julia package for physical units

Supports not only SI units, but also any other unit system. Unitful.jl has minimal run-time penalty of units. Includes facilities for dimensional analysis, and integrates easily with the usual mathematical operations and collections that are defined in Julia.

ReactionMechanismSimulator.jl: Simulation and Analysis of Large Chemical Reaction Systems

ReactionMechanismSimulator.jl is a tool for simulating and analyzing large chemical reaction mechanisms. It interfaces with the ReactionMechanismGenerator suite for automatically constructing reaction pathways from chemical components to quickly build realistic models of chemical systems.

FiniteStateProjection.jl: Direct Solution of Chemical Master Equations

FiniteStateProjection.jl is a library for finite state projection direct solving of the chemical master equation. It automatically converts the Catalyst ReactionSystem definitions into ModelingToolkit ODESystem representations for the evolution of probability distributions to allow for directly solving the weak form of the stochastic model.

AlgebraicPetri.jl: Applied Category Theory of Modeling

AlgebraicPetri.jl is a library for automating the intuitive generation of dynamical models using a Category theory-based approach.

QuantumOptics.jl: Simulating quantum systems.

QuantumOptics.jl makes it easy to simulate various kinds of quantum systems. It is inspired by the Quantum Optics Toolbox for MATLAB and the Python framework QuTiP.

diff --git a/dev/highlevels/numerical_utilities/index.html b/dev/highlevels/numerical_utilities/index.html index d07bcfbc2e9..ab11c3e2e18 100644 --- a/dev/highlevels/numerical_utilities/index.html +++ b/dev/highlevels/numerical_utilities/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

SciML Numerical Utility Libraries

ExponentialUtilities.jl: Faster Matrix Exponentials

ExponentialUtilities.jl is a library for efficient computation of matrix exponentials. While Julia has a built-in exp(A) method, ExponentialUtilities.jl offers many features around this to improve performance in scientific contexts, including:

  • Faster methods for (non-allocating) matrix exponentials via exponential!
  • Methods for computing matrix exponential that are generic to number types and arrays (i.e. GPUs)
  • Methods for computing Arnoldi iterations on Krylov subspaces
  • Direct computation of exp(t*A)*v, i.e. exponentiation of a matrix times a vector, without computing the matrix exponential
  • Direct computation of ϕ_m(t*A)*v operations, where ϕ_0(z) = exp(z) and ϕ_(k+1)(z) = (ϕ_k(z) - 1) / z

ExponentialUtilities.jl includes complex adaptive time stepping techniques such as KIOPS in order to perform these calculations in a fast and numerically-stable way.

QuasiMonteCarlo.jl: Fast Quasi-Random Number Generation

QuasiMonteCarlo.jl is a library for fast generation of low discrepancy Quasi-Monte Carlo samples, using methods like:

  • GridSample(dx) where the grid is given by lb:dx[i]:ub in the ith direction.
  • UniformSample for uniformly distributed random numbers.
  • SobolSample for the Sobol sequence.
  • LatinHypercubeSample for a Latin Hypercube.
  • LatticeRuleSample for a randomly-shifted rank-1 lattice rule.
  • LowDiscrepancySample(base) where base[i] is the base in the ith direction.
  • GoldenSample for a Golden Ratio sequence.
  • KroneckerSample(alpha, s0) for a Kronecker sequence, where alpha is a length-d vector of irrational numbers (often sqrt(d)) and s0 is a length-d seed vector (often 0).
  • SectionSample(x0, sampler) where sampler is any sampler above and x0 is a vector of either NaN for a free dimension or some scalar for a constrained dimension.

PoissonRandom.jl: Fast Poisson Random Number Generation

PoissonRandom.jl is just fast Poisson random number generation for Poisson processes, like chemical master equations.

PreallocationTools.jl: Write Non-Allocating Code Easier

PreallocationTools.jl is a library of tools for writing non-allocating code that interacts well with advanced features like automatic differentiation and symbolics.

RuntimeGeneratedFunctions.jl: Efficient Staged Programming in Julia

RuntimeGeneratedFunctions.jl allows for staged programming in Julia, compiling functions at runtime with full optimizations. This is used by many libraries such as ModelingToolkit.jl to allow for runtime code generation for improved performance.

EllipsisNotation.jl: Implementation of Ellipsis Array Slicing

EllipsisNotation.jl defines the ellipsis array slicing notation for Julia. It uses .. as a catch-all for “all dimensions”, allowing for indexing like [..,1] to mean [:,:,:,1] on four dimensional arrays, in a way that is generic to the number of dimensions in the underlying array.

Third-Party Libraries to Note

Distributions.jl: Representations of Probability Distributions

Distributions.jl is a library for defining distributions in Julia. It's used all throughout the SciML libraries for specifications of probability distributions.

Note

For full compatibility with automatic differentiation, see DistributionsAD.jl

FFTW.jl: Fastest Fourier Transformation in the West

FFTW.jl is the preferred library for fast Fourier Transformations on the CPU.

SpecialFunctions.jl: Implementations of Mathematical Special Functions

SpecialFunctions.jl is a library of implementations of special functions, like Bessel functions and error functions (erf). This library is compatible with automatic differentiation.

LoopVectorization.jl: Automated Loop Accelerator

LoopVectorization.jl is a library which provides the @turbo and @tturbo macros for accelerating the computation of loops. This can be used to accelerating the model functions sent to the equation solvers, for example, accelerating handwritten PDE discretizations.

Polyester.jl: Cheap Threads

Polyester.jl is a cheaper version of threads for Julia, which use a set pool of threads for lower overhead. Note that Polyester does not compose with the standard Julia composable threading infrastructure, and thus one must take care not to compose two levels of Polyester, as this will oversubscribe the computation and lead to performance degradation. Many SciML solvers have options to use Polyester for threading to achieve the top performance.

Tullio.jl: Fast Tensor Calculations and Einstein Notation

Tullio.jl is a library for fast tensor calculations with Einstein notation. It allows for defining operations which are compatible with automatic differentiation, GPUs, and more.

ParallelStencil.jl: High-Level Code for Parallelized Stencil Computations

ParallelStencil.jl is a library for writing high-level code for parallelized stencil computations. It is compatible with SciML equation solvers and is thus a good way to generate GPU and distributed parallel model code.

DataInterpolations.jl: One-Dimensional Interpolations

DataInterpolations.jl is a library of one-dimensional interpolation schemes which are composable with automatic differentiation and the SciML ecosystem. It includes direct interpolation methods and regression techniques for handling noisy data. Its methods include:

  • ConstantInterpolation(u,t) - A piecewise constant interpolation.

  • LinearInterpolation(u,t) - A linear interpolation.

  • QuadraticInterpolation(u,t) - A quadratic interpolation.

  • LagrangeInterpolation(u,t,n) - A Lagrange interpolation of order n.

  • QuadraticSpline(u,t) - A quadratic spline interpolation.

  • CubicSpline(u,t) - A cubic spline interpolation.

  • BSplineInterpolation(u,t,d,pVec,knotVec) - An interpolation B-spline. This is a B-spline which hits each of the data points. The argument choices are:

    • d - degree of B-spline
    • pVec - Symbol to Parameters Vector, pVec = :Uniform for uniform spaced parameters and pVec = :ArcLen for parameters generated by chord length method.
    • knotVec - Symbol to Knot Vector, knotVec = :Uniform for uniform knot vector, knotVec = :Average for average spaced knot vector.
  • BSplineApprox(u,t,d,h,pVec,knotVec) - A regression B-spline which smooths the fitting curve. The argument choices are the same as the BSplineInterpolation, with the additional parameter h<length(t) which is the number of control points to use, with smaller h indicating more smoothing.

  • Curvefit(u,t,m,p,alg) - An interpolation which is done by fitting a user-given functional form m(t,p) where p is the vector of parameters. The user's input p is an initial value for a least-square fitting, alg is the algorithm choice used to optimize the cost function (sum of squared deviations) via Optim.jl and optimal ps are used in the interpolation.

These interpolations match the SciML interfaces and have direct support for packages like ModelingToolkit.jl.

Julia Utilities

StaticCompiler.jl

StaticCompiler.jl is a package for generating static binaries from Julia code. It only supports a subset of Julia, so not all equation solver algorithms are compatible with StaticCompiler.jl.

PackageCompiler.jl

PackageCompiler.jl is a package for generating shared libraries from Julia code. It builds the entirety of Julia by bundling a system image with the Julia runtime. It thus builds complete binaries that can hold all the functionality of SciML. Furthermore, it can also be used to generate new system images to decrease startup times and remove JIT-compilation from SciML usage.

+

SciML Numerical Utility Libraries

ExponentialUtilities.jl: Faster Matrix Exponentials

ExponentialUtilities.jl is a library for efficient computation of matrix exponentials. While Julia has a built-in exp(A) method, ExponentialUtilities.jl offers many features around this to improve performance in scientific contexts, including:

  • Faster methods for (non-allocating) matrix exponentials via exponential!
  • Methods for computing matrix exponential that are generic to number types and arrays (i.e. GPUs)
  • Methods for computing Arnoldi iterations on Krylov subspaces
  • Direct computation of exp(t*A)*v, i.e. exponentiation of a matrix times a vector, without computing the matrix exponential
  • Direct computation of ϕ_m(t*A)*v operations, where ϕ_0(z) = exp(z) and ϕ_(k+1)(z) = (ϕ_k(z) - 1) / z

ExponentialUtilities.jl includes complex adaptive time stepping techniques such as KIOPS in order to perform these calculations in a fast and numerically-stable way.

QuasiMonteCarlo.jl: Fast Quasi-Random Number Generation

QuasiMonteCarlo.jl is a library for fast generation of low discrepancy Quasi-Monte Carlo samples, using methods like:

  • GridSample(dx) where the grid is given by lb:dx[i]:ub in the ith direction.
  • UniformSample for uniformly distributed random numbers.
  • SobolSample for the Sobol sequence.
  • LatinHypercubeSample for a Latin Hypercube.
  • LatticeRuleSample for a randomly-shifted rank-1 lattice rule.
  • LowDiscrepancySample(base) where base[i] is the base in the ith direction.
  • GoldenSample for a Golden Ratio sequence.
  • KroneckerSample(alpha, s0) for a Kronecker sequence, where alpha is a length-d vector of irrational numbers (often sqrt(d)) and s0 is a length-d seed vector (often 0).
  • SectionSample(x0, sampler) where sampler is any sampler above and x0 is a vector of either NaN for a free dimension or some scalar for a constrained dimension.

PoissonRandom.jl: Fast Poisson Random Number Generation

PoissonRandom.jl is just fast Poisson random number generation for Poisson processes, like chemical master equations.

PreallocationTools.jl: Write Non-Allocating Code Easier

PreallocationTools.jl is a library of tools for writing non-allocating code that interacts well with advanced features like automatic differentiation and symbolics.

RuntimeGeneratedFunctions.jl: Efficient Staged Programming in Julia

RuntimeGeneratedFunctions.jl allows for staged programming in Julia, compiling functions at runtime with full optimizations. This is used by many libraries such as ModelingToolkit.jl to allow for runtime code generation for improved performance.

EllipsisNotation.jl: Implementation of Ellipsis Array Slicing

EllipsisNotation.jl defines the ellipsis array slicing notation for Julia. It uses .. as a catch-all for “all dimensions”, allowing for indexing like [..,1] to mean [:,:,:,1] on four dimensional arrays, in a way that is generic to the number of dimensions in the underlying array.

Third-Party Libraries to Note

Distributions.jl: Representations of Probability Distributions

Distributions.jl is a library for defining distributions in Julia. It's used all throughout the SciML libraries for specifications of probability distributions.

Note

For full compatibility with automatic differentiation, see DistributionsAD.jl

FFTW.jl: Fastest Fourier Transformation in the West

FFTW.jl is the preferred library for fast Fourier Transformations on the CPU.

SpecialFunctions.jl: Implementations of Mathematical Special Functions

SpecialFunctions.jl is a library of implementations of special functions, like Bessel functions and error functions (erf). This library is compatible with automatic differentiation.

LoopVectorization.jl: Automated Loop Accelerator

LoopVectorization.jl is a library which provides the @turbo and @tturbo macros for accelerating the computation of loops. This can be used to accelerating the model functions sent to the equation solvers, for example, accelerating handwritten PDE discretizations.

Polyester.jl: Cheap Threads

Polyester.jl is a cheaper version of threads for Julia, which use a set pool of threads for lower overhead. Note that Polyester does not compose with the standard Julia composable threading infrastructure, and thus one must take care not to compose two levels of Polyester, as this will oversubscribe the computation and lead to performance degradation. Many SciML solvers have options to use Polyester for threading to achieve the top performance.

Tullio.jl: Fast Tensor Calculations and Einstein Notation

Tullio.jl is a library for fast tensor calculations with Einstein notation. It allows for defining operations which are compatible with automatic differentiation, GPUs, and more.

ParallelStencil.jl: High-Level Code for Parallelized Stencil Computations

ParallelStencil.jl is a library for writing high-level code for parallelized stencil computations. It is compatible with SciML equation solvers and is thus a good way to generate GPU and distributed parallel model code.

DataInterpolations.jl: One-Dimensional Interpolations

DataInterpolations.jl is a library of one-dimensional interpolation schemes which are composable with automatic differentiation and the SciML ecosystem. It includes direct interpolation methods and regression techniques for handling noisy data. Its methods include:

  • ConstantInterpolation(u,t) - A piecewise constant interpolation.

  • LinearInterpolation(u,t) - A linear interpolation.

  • QuadraticInterpolation(u,t) - A quadratic interpolation.

  • LagrangeInterpolation(u,t,n) - A Lagrange interpolation of order n.

  • QuadraticSpline(u,t) - A quadratic spline interpolation.

  • CubicSpline(u,t) - A cubic spline interpolation.

  • BSplineInterpolation(u,t,d,pVec,knotVec) - An interpolation B-spline. This is a B-spline which hits each of the data points. The argument choices are:

    • d - degree of B-spline
    • pVec - Symbol to Parameters Vector, pVec = :Uniform for uniform spaced parameters and pVec = :ArcLen for parameters generated by chord length method.
    • knotVec - Symbol to Knot Vector, knotVec = :Uniform for uniform knot vector, knotVec = :Average for average spaced knot vector.
  • BSplineApprox(u,t,d,h,pVec,knotVec) - A regression B-spline which smooths the fitting curve. The argument choices are the same as the BSplineInterpolation, with the additional parameter h<length(t) which is the number of control points to use, with smaller h indicating more smoothing.

  • Curvefit(u,t,m,p,alg) - An interpolation which is done by fitting a user-given functional form m(t,p) where p is the vector of parameters. The user's input p is an initial value for a least-square fitting, alg is the algorithm choice used to optimize the cost function (sum of squared deviations) via Optim.jl and optimal ps are used in the interpolation.

These interpolations match the SciML interfaces and have direct support for packages like ModelingToolkit.jl.

Julia Utilities

StaticCompiler.jl

StaticCompiler.jl is a package for generating static binaries from Julia code. It only supports a subset of Julia, so not all equation solver algorithms are compatible with StaticCompiler.jl.

PackageCompiler.jl

PackageCompiler.jl is a package for generating shared libraries from Julia code. It builds the entirety of Julia by bundling a system image with the Julia runtime. It thus builds complete binaries that can hold all the functionality of SciML. Furthermore, it can also be used to generate new system images to decrease startup times and remove JIT-compilation from SciML usage.

diff --git a/dev/highlevels/parameter_analysis/index.html b/dev/highlevels/parameter_analysis/index.html index 3258a0246eb..08220e19f2d 100644 --- a/dev/highlevels/parameter_analysis/index.html +++ b/dev/highlevels/parameter_analysis/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Parameter Analysis Utilities

GlobalSensitivity.jl: Global Sensitivity Analysis

Derivatives calculate the local sensitivity of a model, i.e. the change in the simulation's outcome if one were to change the parameter with respect to some chosen part of the parameter space. But how does a simulation's output change “in general” with respect to a given parameter? That is what global sensitivity analysis (GSA) computes, and thus GlobalSensitivity.jl is the way to answer that question. GlobalSensitivity.jl includes a wide array of methods, including:

  • Morris's method
  • Sobol's method
  • Regression methods (PCC, SRC, Pearson)
  • eFAST
  • Delta Moment-Independent method
  • Derivative-based Global Sensitivity Measures (DGSM)
  • EASI
  • Fractional Factorial method
  • Random Balance Design FAST method

StructuralIdentifiability.jl: Identifiability Analysis Made Simple

Performing parameter estimation from a data set means attempting to recover parameters like reaction rates by fitting some model to the data. But how do you know whether you have enough data to even consider getting the “correct” parameters back? StructuralIdentifiability.jl allows for running a structural identifiability analysis on a given model to determine whether it's theoretically possible to recover the correct parameters. It can state whether a given type of output data can be used to globally recover the parameters (i.e. only a unique parameter set for the model produces a given output), whether the parameters are only locally identifiable (i.e. there are finitely many parameter sets which could generate the seen data), or whether it's unidentifiable (there are infinitely many parameters which generate the same output data).

For more information on what StructuralIdentifiability.jl is all about, see the SciMLCon 2022 tutorial video.

MinimallyDisruptiveCurves.jl

MinimallyDisruptiveCurves.jl is a library for finding relationships between parameters of models, finding the curves on which the solution is constant.

Third-Party Libraries to Note

SIAN.jl: Structural Identifiability Analyzer

SIAN.jl is a structural identifiability analysis package which uses an entirely different algorithm from StructuralIdentifiability.jl. For information on the differences between the two approaches, see the Structural Identifiability Tools in Julia tutorial.

DynamicalSystems.jl: A Suite of Dynamical Systems Analysis

DynamicalSystems.jl is an entire ecosystem of dynamical systems analysis methods, for computing measures of chaos (dimension estimation, Lyapunov coefficients), generating delay embeddings, and much more. It uses the SciML tools for its internal equation solving and thus shares much of its API, adding a layer of new tools for extended analyses.

For more information, watch the tutorial Introduction to DynamicalSystems.jl.

BifurcationKit.jl

BifurcationKit.jl is a tool for performing bifurcation analysis. It uses and composes with many SciML equation solvers.

ReachabilityAnalysis.jl

ReachabilityAnalysis.jl is a library for performing reachability analysis of dynamical systems, determining for a given uncertainty interval the full set of possible outcomes from a dynamical system.

ControlSystems.jl

ControlSystems.jl is a library for building and analyzing control systems.

+

Parameter Analysis Utilities

GlobalSensitivity.jl: Global Sensitivity Analysis

Derivatives calculate the local sensitivity of a model, i.e. the change in the simulation's outcome if one were to change the parameter with respect to some chosen part of the parameter space. But how does a simulation's output change “in general” with respect to a given parameter? That is what global sensitivity analysis (GSA) computes, and thus GlobalSensitivity.jl is the way to answer that question. GlobalSensitivity.jl includes a wide array of methods, including:

  • Morris's method
  • Sobol's method
  • Regression methods (PCC, SRC, Pearson)
  • eFAST
  • Delta Moment-Independent method
  • Derivative-based Global Sensitivity Measures (DGSM)
  • EASI
  • Fractional Factorial method
  • Random Balance Design FAST method

StructuralIdentifiability.jl: Identifiability Analysis Made Simple

Performing parameter estimation from a data set means attempting to recover parameters like reaction rates by fitting some model to the data. But how do you know whether you have enough data to even consider getting the “correct” parameters back? StructuralIdentifiability.jl allows for running a structural identifiability analysis on a given model to determine whether it's theoretically possible to recover the correct parameters. It can state whether a given type of output data can be used to globally recover the parameters (i.e. only a unique parameter set for the model produces a given output), whether the parameters are only locally identifiable (i.e. there are finitely many parameter sets which could generate the seen data), or whether it's unidentifiable (there are infinitely many parameters which generate the same output data).

For more information on what StructuralIdentifiability.jl is all about, see the SciMLCon 2022 tutorial video.

MinimallyDisruptiveCurves.jl

MinimallyDisruptiveCurves.jl is a library for finding relationships between parameters of models, finding the curves on which the solution is constant.

Third-Party Libraries to Note

SIAN.jl: Structural Identifiability Analyzer

SIAN.jl is a structural identifiability analysis package which uses an entirely different algorithm from StructuralIdentifiability.jl. For information on the differences between the two approaches, see the Structural Identifiability Tools in Julia tutorial.

DynamicalSystems.jl: A Suite of Dynamical Systems Analysis

DynamicalSystems.jl is an entire ecosystem of dynamical systems analysis methods, for computing measures of chaos (dimension estimation, Lyapunov coefficients), generating delay embeddings, and much more. It uses the SciML tools for its internal equation solving and thus shares much of its API, adding a layer of new tools for extended analyses.

For more information, watch the tutorial Introduction to DynamicalSystems.jl.

BifurcationKit.jl

BifurcationKit.jl is a tool for performing bifurcation analysis. It uses and composes with many SciML equation solvers.

ReachabilityAnalysis.jl

ReachabilityAnalysis.jl is a library for performing reachability analysis of dynamical systems, determining for a given uncertainty interval the full set of possible outcomes from a dynamical system.

ControlSystems.jl

ControlSystems.jl is a library for building and analyzing control systems.

diff --git a/dev/highlevels/partial_differential_equation_solvers/index.html b/dev/highlevels/partial_differential_equation_solvers/index.html index d51706c19ad..097be2b4614 100644 --- a/dev/highlevels/partial_differential_equation_solvers/index.html +++ b/dev/highlevels/partial_differential_equation_solvers/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Partial Differential Equations (PDE)

NeuralPDE.jl: Physics-Informed Neural Network (PINN) PDE Solvers

NeuralPDE.jl is a partial differential equation solver library which uses physics-informed neural networks (PINNs) to solve the equations. It uses the ModelingToolkit.jl symbolic PDESystem as its input and can handle a wide variety of equation types, including systems of partial differential equations, partial differential-algebraic equations, and integro-differential equations. Its benefit is its flexibility, and it can be used to easily generate surrogate solutions over entire parameter ranges. However, its downside is solver speed: PINN solvers tend to be a lot slower than other methods for solving PDEs.

MethodOflines.jl: Automated Finite Difference Method (FDM)

MethodOflines.jl is a partial differential equation solver library which automates the discretization of PDEs via the finite difference method. It uses the ModelingToolkit.jl symbolic PDESystem as its input, and generates AbstractSystems and SciMLProblems whose numerical solution gives the solution to the PDE.

FEniCS.jl: Wrappers for the Finite Element Method (FEM)

FEniCS.jl is a wrapper for the popular FEniCS finite element method library.

HighDimPDE.jl: High-dimensional PDE Solvers

HighDimPDE.jl is a partial differential equation solver library which implements algorithms that break down the curse of dimensionality to solve the equations. It implements deep-learning based and Picard-iteration based methods to approximately solve high-dimensional, nonlinear, non-local PDEs in up to 10,000 dimensions. Its cons are accuracy: high-dimensional solvers are stochastic, and might result in wrong solutions if the solver meta-parameters are not appropriate.

NeuralOperators.jl: (Fourier) Neural Operators and DeepONets for PDE Solving

NeuralOperators.jl is a library for operator learning based PDE solvers. This includes techniques like:

  • Fourier Neural Operators (FNO)
  • Deep Operator Networks (DeepONets)
  • Markov Neural Operators (MNO)

Currently, its connection to PDE solving must be specified manually, though an interface for ModelingToolkit PDESystems is in progress.

DiffEqOperators.jl: Operators for Finite Difference Method (FDM) Discretizations

DiffEqOperators.jl is a library for defining finite difference operators to easily perform manual FDM semi-discretizations of partial differential equations. This library is fairly incomplete and most cases should receive better performance using MethodOflines.jl.

Third-Party Libraries to Note

ApproxFun.jl: Automated Spectral Discretizations

ApproxFun.jl is a package for approximating functions in basis sets. One particular use case is with spectral basis sets, such as Chebyshev functions and Fourier decompositions, making it easy to represent spectral and pseudospectral discretizations of partial differential equations as ordinary differential equations for the SciML equation solvers.

Gridap.jl: Julia-Based Tools for Finite Element Discretizations

Gridap.jl is a package for grid-based approximation of partial differential equations, particularly notable for its use of conforming and nonconforming finite element (FEM) discretizations.

Trixi.jl: Adaptive High-Order Numerical Simulations of Hyperbolic Equations

Trixi.jl is a package for numerical simulation of hyperbolic conservation laws, i.e. a large set of hyperbolic partial differential equations, which interfaces and uses the SciML ordinary differential equation solvers.

VoronoiFVM.jl: Tools for the Voronoi Finite Volume Discretizations

VoronoiFVM.jl is a library for generating FVM discretizations of systems of PDEs. It interfaces with many of the SciML equation solver libraries to allow for ease of discretization and flexibility in the solver choice.

+

Partial Differential Equations (PDE)

NeuralPDE.jl: Physics-Informed Neural Network (PINN) PDE Solvers

NeuralPDE.jl is a partial differential equation solver library which uses physics-informed neural networks (PINNs) to solve the equations. It uses the ModelingToolkit.jl symbolic PDESystem as its input and can handle a wide variety of equation types, including systems of partial differential equations, partial differential-algebraic equations, and integro-differential equations. Its benefit is its flexibility, and it can be used to easily generate surrogate solutions over entire parameter ranges. However, its downside is solver speed: PINN solvers tend to be a lot slower than other methods for solving PDEs.

MethodOflines.jl: Automated Finite Difference Method (FDM)

MethodOflines.jl is a partial differential equation solver library which automates the discretization of PDEs via the finite difference method. It uses the ModelingToolkit.jl symbolic PDESystem as its input, and generates AbstractSystems and SciMLProblems whose numerical solution gives the solution to the PDE.

FEniCS.jl: Wrappers for the Finite Element Method (FEM)

FEniCS.jl is a wrapper for the popular FEniCS finite element method library.

HighDimPDE.jl: High-dimensional PDE Solvers

HighDimPDE.jl is a partial differential equation solver library which implements algorithms that break down the curse of dimensionality to solve the equations. It implements deep-learning based and Picard-iteration based methods to approximately solve high-dimensional, nonlinear, non-local PDEs in up to 10,000 dimensions. Its cons are accuracy: high-dimensional solvers are stochastic, and might result in wrong solutions if the solver meta-parameters are not appropriate.

NeuralOperators.jl: (Fourier) Neural Operators and DeepONets for PDE Solving

NeuralOperators.jl is a library for operator learning based PDE solvers. This includes techniques like:

  • Fourier Neural Operators (FNO)
  • Deep Operator Networks (DeepONets)
  • Markov Neural Operators (MNO)

Currently, its connection to PDE solving must be specified manually, though an interface for ModelingToolkit PDESystems is in progress.

DiffEqOperators.jl: Operators for Finite Difference Method (FDM) Discretizations

DiffEqOperators.jl is a library for defining finite difference operators to easily perform manual FDM semi-discretizations of partial differential equations. This library is fairly incomplete and most cases should receive better performance using MethodOflines.jl.

Third-Party Libraries to Note

ApproxFun.jl: Automated Spectral Discretizations

ApproxFun.jl is a package for approximating functions in basis sets. One particular use case is with spectral basis sets, such as Chebyshev functions and Fourier decompositions, making it easy to represent spectral and pseudospectral discretizations of partial differential equations as ordinary differential equations for the SciML equation solvers.

Gridap.jl: Julia-Based Tools for Finite Element Discretizations

Gridap.jl is a package for grid-based approximation of partial differential equations, particularly notable for its use of conforming and nonconforming finite element (FEM) discretizations.

Trixi.jl: Adaptive High-Order Numerical Simulations of Hyperbolic Equations

Trixi.jl is a package for numerical simulation of hyperbolic conservation laws, i.e. a large set of hyperbolic partial differential equations, which interfaces and uses the SciML ordinary differential equation solvers.

VoronoiFVM.jl: Tools for the Voronoi Finite Volume Discretizations

VoronoiFVM.jl is a library for generating FVM discretizations of systems of PDEs. It interfaces with many of the SciML equation solver libraries to allow for ease of discretization and flexibility in the solver choice.

diff --git a/dev/highlevels/plots_visualization/index.html b/dev/highlevels/plots_visualization/index.html index 41bc086ddd9..a9da681b12e 100644 --- a/dev/highlevels/plots_visualization/index.html +++ b/dev/highlevels/plots_visualization/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

SciML-Supported Plotting and Visualization Libraries

The following libraries are the plotting and visualization libraries which are supported and co-developed by the SciML developers. Other libraries may be used, though these are the libraries used in the tutorials and which have special hooks to ensure ergonomic usage with SciML tooling.

Plots.jl

Plots.jl is the current standard plotting system for the SciML ecosystem. SciML types attempt to include plot recipes for as many types as possible, allowing for automatic visualization with the Plots.jl system. All current tutorials and documentation default to using Plots.jl.

Makie.jl

Makie.jl is a high-performance interactive plotting system for the Julia programming language. It's planned to be the default plotting system used by the SciML organization in the near future.

+

SciML-Supported Plotting and Visualization Libraries

The following libraries are the plotting and visualization libraries which are supported and co-developed by the SciML developers. Other libraries may be used, though these are the libraries used in the tutorials and which have special hooks to ensure ergonomic usage with SciML tooling.

Plots.jl

Plots.jl is the current standard plotting system for the SciML ecosystem. SciML types attempt to include plot recipes for as many types as possible, allowing for automatic visualization with the Plots.jl system. All current tutorials and documentation default to using Plots.jl.

Makie.jl

Makie.jl is a high-performance interactive plotting system for the Julia programming language. It's planned to be the default plotting system used by the SciML organization in the near future.

diff --git a/dev/highlevels/symbolic_learning/index.html b/dev/highlevels/symbolic_learning/index.html index ef4a13b29ab..25c9876eeef 100644 --- a/dev/highlevels/symbolic_learning/index.html +++ b/dev/highlevels/symbolic_learning/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Symbolic Learning and Artificial Intelligence

Symbolic learning, the classical artificial intelligence, is a set of methods for learning symbolic equations from data and numerical functions. SciML offers an array of symbolic learning utilities which connect with the other machine learning and equation solver functionalities to make it easy to embed prior knowledge and discover missing physics. For more information, see Universal Differential Equations for Scientific Machine Learning.

DataDrivenDiffEq.jl: Data-Driven Modeling and Automated Discovery of Dynamical Systems

DataDrivenDiffEq.jl is a general interface for data-driven modeling, containing a large array of techniques such as:

  • Koopman operator methods (Dynamic-Mode Decomposition (DMD) and variations)
  • Sparse Identification of Dynamical Systems (SINDy and variations like iSINDy)
  • Sparse regression methods (STSLQ, SR3, etc.)
  • PDEFind
  • Wrappers for SymbolicRegression.jl
  • AI Feynman
  • OccamNet

SymbolicNumericIntegration.jl: Symbolic Integration via Numerical Methods

SymbolicNumericIntegration.jl is a package computing the solution to symbolic integration problem using numerical methods (numerical integration mixed with sparse regression).

Third-Party Libraries to Note

SymbolicRegression.jl

SymbolicRegression.jl is a symbolic regression library which uses genetic algorithms with parallelization to achieve fast and robust symbolic learning.

+

Symbolic Learning and Artificial Intelligence

Symbolic learning, the classical artificial intelligence, is a set of methods for learning symbolic equations from data and numerical functions. SciML offers an array of symbolic learning utilities which connect with the other machine learning and equation solver functionalities to make it easy to embed prior knowledge and discover missing physics. For more information, see Universal Differential Equations for Scientific Machine Learning.

DataDrivenDiffEq.jl: Data-Driven Modeling and Automated Discovery of Dynamical Systems

DataDrivenDiffEq.jl is a general interface for data-driven modeling, containing a large array of techniques such as:

  • Koopman operator methods (Dynamic-Mode Decomposition (DMD) and variations)
  • Sparse Identification of Dynamical Systems (SINDy and variations like iSINDy)
  • Sparse regression methods (STSLQ, SR3, etc.)
  • PDEFind
  • Wrappers for SymbolicRegression.jl
  • AI Feynman
  • OccamNet

SymbolicNumericIntegration.jl: Symbolic Integration via Numerical Methods

SymbolicNumericIntegration.jl is a package computing the solution to symbolic integration problem using numerical methods (numerical integration mixed with sparse regression).

Third-Party Libraries to Note

SymbolicRegression.jl

SymbolicRegression.jl is a symbolic regression library which uses genetic algorithms with parallelization to achieve fast and robust symbolic learning.

diff --git a/dev/highlevels/symbolic_tools/index.html b/dev/highlevels/symbolic_tools/index.html index f3a0d5eb2ef..780c77ab55f 100644 --- a/dev/highlevels/symbolic_tools/index.html +++ b/dev/highlevels/symbolic_tools/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Symbolic Model Tooling and JuliaSymbolics

JuliaSymbolics is a sister organization of SciML. It spawned out of the symbolic modeling tools being developed within SciML (ModelingToolkit.jl) to become its own organization dedicated to building a fully-featured Julia-based Computer Algebra System (CAS). As such, the two organizations are closely aligned in terms of its developer community, and many of the SciML libraries use Symbolics.jl extensively.

ModelOrderReduction.jl: Automated Model Reduction for Fast Approximations of Solutions

ModelOrderReduction.jl is a package for automating the reduction of models. These methods function a submodel with a projection, where solving the smaller model provides approximation information about the full model. MOR.jl uses ModelingToolkit.jl as a system description and automatically transforms equations to the subform, defining the observables to automatically lazily reconstruct the full model on-demand in a fast and stable form.

Symbolics.jl: The Computer Algebra System (CAS) of the Julia Programming Language

Symbolics.jl is the CAS of the Julia programming language. If something needs to be done symbolically, most likely Symbolics.jl is the answer.

MetaTheory.jl: E-Graphs to Automate Symbolic Transformations

Metatheory.jl is a library for defining e-graph rewriters for use on the common symbolic interface. This can be used to do all sorts of analysis and code transformations, such as improving code performance, numerical stability, and more. See Automated Code Optimization with E-Graphs for more details.

SymbolicUtils.jl: Define Your Own Computer Algebra System

SymbolicUtils.jl is the underlying utility library and rule-based rewriting language on which Symbolics.jl is developed. Symbolics.jl is standardized type and rule definitions built using SymbolicUtils.jl. However, if non-standard types are required, such as symbolic computing over Fock algebras, then SymbolicUtils.jl is the library from which the new symbolic types can be implemented.

+

Symbolic Model Tooling and JuliaSymbolics

JuliaSymbolics is a sister organization of SciML. It spawned out of the symbolic modeling tools being developed within SciML (ModelingToolkit.jl) to become its own organization dedicated to building a fully-featured Julia-based Computer Algebra System (CAS). As such, the two organizations are closely aligned in terms of its developer community, and many of the SciML libraries use Symbolics.jl extensively.

ModelOrderReduction.jl: Automated Model Reduction for Fast Approximations of Solutions

ModelOrderReduction.jl is a package for automating the reduction of models. These methods function a submodel with a projection, where solving the smaller model provides approximation information about the full model. MOR.jl uses ModelingToolkit.jl as a system description and automatically transforms equations to the subform, defining the observables to automatically lazily reconstruct the full model on-demand in a fast and stable form.

Symbolics.jl: The Computer Algebra System (CAS) of the Julia Programming Language

Symbolics.jl is the CAS of the Julia programming language. If something needs to be done symbolically, most likely Symbolics.jl is the answer.

MetaTheory.jl: E-Graphs to Automate Symbolic Transformations

Metatheory.jl is a library for defining e-graph rewriters for use on the common symbolic interface. This can be used to do all sorts of analysis and code transformations, such as improving code performance, numerical stability, and more. See Automated Code Optimization with E-Graphs for more details.

SymbolicUtils.jl: Define Your Own Computer Algebra System

SymbolicUtils.jl is the underlying utility library and rule-based rewriting language on which Symbolics.jl is developed. Symbolics.jl is standardized type and rule definitions built using SymbolicUtils.jl. However, if non-standard types are required, such as symbolic computing over Fock algebras, then SymbolicUtils.jl is the library from which the new symbolic types can be implemented.

diff --git a/dev/highlevels/uncertainty_quantification/index.html b/dev/highlevels/uncertainty_quantification/index.html index e90a7d2df0a..997e0535ca9 100644 --- a/dev/highlevels/uncertainty_quantification/index.html +++ b/dev/highlevels/uncertainty_quantification/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Uncertainty Quantification

There's always uncertainty in our models. Whether it's in the form of the model's equations or in the model's parameters, the uncertainty in our simulation's output often needs to be quantified. The following tools automate this process.

For Measurements.jl vs MonteCarloMeasurements.jl vs Intervals.jl, and the relation to other methods, see the Uncertainty Programming chapter of the SciML Book.

PolyChaos.jl: Intrusive Polynomial Chaos Expansions Made Unintrusive

PolyChaos.jl is a library for calculating intrusive polynomial chaos expansions (PCE) on arbitrary Julia functions. This allows for inputting representations of probability distributions into functions to compute the output distribution in an expansion representation. While normally this would require deriving the PCE-expanded equations by hand, PolyChaos.jl does this at the compiler level using Julia's multiple dispatch, giving a high-performance implementation to a normally complex and tedious mathematical transformation.

SciMLExpectations.jl: Fast Calculations of Expectations of Equation Solutions

SciMLExpectations.jl is a library for accelerating the calculation of expectations of equation solutions with respect to input probability distributions, allowing for applications like robust optimization with respect to uncertainty. It uses Koopman operator techniques to calculate these expectations without requiring the propagation of uncertainties through a solver, effectively performing the adjoint of uncertainty quantification and being much more efficient in the process.

Third-Party Libraries to Note

Measurements.jl: Automated Linear Error Propagation

Measurements.jl is a library for automating linear error propagation. Uncertain numbers are defined as x = 3.8 ± 0.4 and are pushed through calculations using a normal distribution approximation in order to compute an approximate uncertain output. Measurements.jl uses a dictionary-based approach to keep track of correlations to improve the accuracy over naive implementations, though note that linear error propagation theory still has some major issues handling some types of equations, as described in detail in the MonteCarloMeasurements.jl documentation.

MonteCarloMeasurements.jl: Automated Monte Carlo Error Propagation

MonteCarloMeasurements.jl is a library for automating the uncertainty quantification of equation solution using Monte Carlo methods. It defines number types which sample from an input distribution to receive a representative set of parameters that propagate through the solver to calculate a representative set of possible solutions. Note that Monte Carlo techniques can be expensive but are exact, in the sense that as the number of sample points increases to infinity it will compute a correct approximation of the output uncertainty.

ProbNumDiffEq.jl: Probabilistic Numerics Based Differential Equation Solvers

ProbNumDiffEq.jl is a set of probabilistic numerical ODE solvers which compute the solution of a differential equation along with a posterior distribution to estimate its numerical approximation error. Thus these specialized integrators compute an uncertainty output similar to the ProbInts technique of DiffEqUncertainty, but use specialized integration techniques in order to do it much faster for specific kinds of equations.

TaylorIntegration.jl: Taylor Series Integration for Rigorous Numerical Bounds

TaylorIntegration.jl is a library for Taylor series integrators, which has special functionality for computing the interval bound of possible solutions with respect to numerical approximation error.

IntervalArithmetic.jl: Rigorous Numerical Intervals

IntervalArithmetic.jl is a library for performing interval arithmetic calculations on arbitrary Julia code. Interval arithmetic computes rigorous computations with respect to finite-precision floating-point arithmetic, i.e. its intervals are guaranteed to include the true solution. However, interval arithmetic intervals can grow at exponential rates in many problems, thus being unsuitable for analyses in many equation solver contexts.

+

Uncertainty Quantification

There's always uncertainty in our models. Whether it's in the form of the model's equations or in the model's parameters, the uncertainty in our simulation's output often needs to be quantified. The following tools automate this process.

For Measurements.jl vs MonteCarloMeasurements.jl vs Intervals.jl, and the relation to other methods, see the Uncertainty Programming chapter of the SciML Book.

PolyChaos.jl: Intrusive Polynomial Chaos Expansions Made Unintrusive

PolyChaos.jl is a library for calculating intrusive polynomial chaos expansions (PCE) on arbitrary Julia functions. This allows for inputting representations of probability distributions into functions to compute the output distribution in an expansion representation. While normally this would require deriving the PCE-expanded equations by hand, PolyChaos.jl does this at the compiler level using Julia's multiple dispatch, giving a high-performance implementation to a normally complex and tedious mathematical transformation.

SciMLExpectations.jl: Fast Calculations of Expectations of Equation Solutions

SciMLExpectations.jl is a library for accelerating the calculation of expectations of equation solutions with respect to input probability distributions, allowing for applications like robust optimization with respect to uncertainty. It uses Koopman operator techniques to calculate these expectations without requiring the propagation of uncertainties through a solver, effectively performing the adjoint of uncertainty quantification and being much more efficient in the process.

Third-Party Libraries to Note

Measurements.jl: Automated Linear Error Propagation

Measurements.jl is a library for automating linear error propagation. Uncertain numbers are defined as x = 3.8 ± 0.4 and are pushed through calculations using a normal distribution approximation in order to compute an approximate uncertain output. Measurements.jl uses a dictionary-based approach to keep track of correlations to improve the accuracy over naive implementations, though note that linear error propagation theory still has some major issues handling some types of equations, as described in detail in the MonteCarloMeasurements.jl documentation.

MonteCarloMeasurements.jl: Automated Monte Carlo Error Propagation

MonteCarloMeasurements.jl is a library for automating the uncertainty quantification of equation solution using Monte Carlo methods. It defines number types which sample from an input distribution to receive a representative set of parameters that propagate through the solver to calculate a representative set of possible solutions. Note that Monte Carlo techniques can be expensive but are exact, in the sense that as the number of sample points increases to infinity it will compute a correct approximation of the output uncertainty.

ProbNumDiffEq.jl: Probabilistic Numerics Based Differential Equation Solvers

ProbNumDiffEq.jl is a set of probabilistic numerical ODE solvers which compute the solution of a differential equation along with a posterior distribution to estimate its numerical approximation error. Thus these specialized integrators compute an uncertainty output similar to the ProbInts technique of DiffEqUncertainty, but use specialized integration techniques in order to do it much faster for specific kinds of equations.

TaylorIntegration.jl: Taylor Series Integration for Rigorous Numerical Bounds

TaylorIntegration.jl is a library for Taylor series integrators, which has special functionality for computing the interval bound of possible solutions with respect to numerical approximation error.

IntervalArithmetic.jl: Rigorous Numerical Intervals

IntervalArithmetic.jl is a library for performing interval arithmetic calculations on arbitrary Julia code. Interval arithmetic computes rigorous computations with respect to finite-precision floating-point arithmetic, i.e. its intervals are guaranteed to include the true solution. However, interval arithmetic intervals can grow at exponential rates in many problems, thus being unsuitable for analyses in many equation solver contexts.

diff --git a/dev/index.html b/dev/index.html index a99d6bfdccf..a97b89c6214 100644 --- a/dev/index.html +++ b/dev/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

SciML: Differentiable Modeling and Simulation Combined with Machine Learning

The SciML organization is a collection of tools for solving equations and modeling systems developed in the Julia programming language with bindings to other languages such as R and Python. The organization provides well-maintained tools which compose together as a coherent ecosystem. It has a coherent development principle, unified APIs over large collections of equation solvers, pervasive differentiability and sensitivity analysis, and features many of the highest performance and parallel implementations one can find.

Scientific Machine Learning (SciML) = Scientific Computing + Machine Learning

Where to Start?

And for diving into the details, use the bar on the top to navigate to the submodule of interest!

+

SciML: Differentiable Modeling and Simulation Combined with Machine Learning

The SciML organization is a collection of tools for solving equations and modeling systems developed in the Julia programming language with bindings to other languages such as R and Python. The organization provides well-maintained tools which compose together as a coherent ecosystem. It has a coherent development principle, unified APIs over large collections of equation solvers, pervasive differentiability and sensitivity analysis, and features many of the highest performance and parallel implementations one can find.

Scientific Machine Learning (SciML) = Scientific Computing + Machine Learning

Where to Start?

And for diving into the details, use the bar on the top to navigate to the submodule of interest!

diff --git a/dev/overview/index.html b/dev/overview/index.html index b89d4e14c95..868d63b7e5d 100644 --- a/dev/overview/index.html +++ b/dev/overview/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Detailed Overview of the SciML Software Ecosystem

SciML: Combining High-Performance Scientific Computing and Machine Learning

SciML is not standard machine learning, SciML is the combination of scientific computing techniques with machine learning. Thus the SciML organization is not an organization for machine learning libraries (see FluxML for machine learning in Julia), rather SciML is an organization dedicated to the development of scientific computing tools which work seamlessly in conjunction with next-generation machine learning workflows. This includes:

  • High-performance and accurate tools for standard scientific computing modeling and simulation
  • Compatibility with differentiable programming and automatic differentiation
  • Tools for building complex multiscale models
  • Methods for handling inverse problems, model calibration, controls, and Bayesian analysis
  • Symbolic modeling tools for generating efficient code for numerical equation solvers
  • Methods for automatic discovery of (bio)physical equations

and much more. For an overview of the broad goals of the SciML organization, watch:

Overview of Computational Science in Julia with SciML

Below is a simplification of the user-facing packages for use in scientific computing and SciML workflows.

Workflow ElementSciML-Supported Julia packages
Plotting and VisualizationPlots*, Makie*
Sparse matrixSparseArrays*
Interpolation/approximationDataInterpolations*, ApproxFun*
Linear system / least squaresLinearSolve
Nonlinear system / rootfindingNonlinearSolve
Polynomial rootsPolynomials*
IntegrationIntegrals
Nonlinear OptimizationOptimization
Other Optimization (linear, quadratic, convex, etc.)JuMP*
Initial-value problemDifferentialEquations
Boundary-value problemDifferentialEquations
Continuous-Time Markov Chains (Poisson Jumps), Jump DiffusionsJumpProcesses
Finite differencesFiniteDifferences*, FiniteDiff*
Automatic DifferentiationForwardDiff*, Enzyme*, DiffEqSensitivity
Bayesian ModelingTuring*
Deep LearningFlux*
Acausal Modeling / DAEsModelingToolkit
Chemical Reaction NetworksCatalyst
Symbolic ComputingSymbolics
Fast Fourier TransformFFTW*
Partial Differential Equation DiscretizationsAssociated Julia packages
–-–-
Finite DifferencesMethodOfLines
Discontinuous GalerkinTrixi*
Finite ElementGridap*
Physics-Informed Neural NetworksNeuralPDE
Neural OperatorsNeuralOperators
High Dimensional Deep LearningHighDimPDE

* Denotes a non-SciML package that is heavily tested against as part of SciML workflows and has frequent collaboration with the SciML developers.

SciML Mind Map

Domains of SciML

The SciML common interface covers the following domains:

  • Linear systems (LinearProblem)

    • Direct methods for dense and sparse
    • Iterative solvers with preconditioning
  • Nonlinear Systems (NonlinearProblem)

    • Systems of nonlinear equations
    • Scalar bracketing systems
  • Integrals (quadrature) (IntegralProblem)

  • Differential Equations

    • Discrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations) (DiscreteProblem and JumpProblem)
    • Ordinary differential equations (ODEs) (ODEProblem)
    • Split and Partitioned ODEs (Symplectic integrators, IMEX Methods) (SplitODEProblem)
    • Stochastic ordinary differential equations (SODEs or SDEs) (SDEProblem)
    • Stochastic differential-algebraic equations (SDAEs) (SDEProblem with mass matrices)
    • Random differential equations (RODEs or RDEs) (RODEProblem)
    • Differential algebraic equations (DAEs) (DAEProblem and ODEProblem with mass matrices)
    • Delay differential equations (DDEs) (DDEProblem)
    • Neutral, retarded, and algebraic delay differential equations (NDDEs, RDDEs, and DDAEs)
    • Stochastic delay differential equations (SDDEs) (SDDEProblem)
    • Experimental support for stochastic neutral, retarded, and algebraic delay differential equations (SNDDEs, SRDDEs, and SDDAEs)
    • Mixed discrete and continuous equations (Hybrid Equations, Jump Diffusions) (DEProblems with callbacks and JumpProblem)
  • Optimization (OptimizationProblem)

    • Nonlinear (constrained) optimization
  • (Stochastic/Delay/Differential-Algebraic) Partial Differential Equations (PDESystem)

    • Finite difference and finite volume methods
    • Interfaces to finite element methods
    • Physics-Informed Neural Networks (PINNs)
    • Integro-Differential Equations
    • Fractional Differential Equations
  • Specialized Forms

    • Partial Integro-Differential Equations (PIPDEProblem)
  • Data-driven modeling

    • Discrete-time data-driven dynamical systems (DiscreteDataDrivenProblem)
    • Continuous-time data-driven dynamical systems (ContinuousDataDrivenProblem)
    • Symbolic regression (DirectDataDrivenProblem)
  • Uncertainty quantification and expected values (ExpectationProblem)

The SciML common interface also includes ModelingToolkit.jl for defining such systems symbolically, allowing for optimizations like automated generation of parallel code, symbolic simplification, and generation of sparsity patterns.

Inverse Problems, Parameter Estimation, and Structural Identification

Parameter estimation and inverse problems are solved directly on their constituent problem types using tools like SciMLSensitivity.jl. Thus for example, there is no ODEInverseProblem, and instead ODEProblem is used to find the parameters p that solve the inverse problem. Check out the SciMLSensitivity documentation for a discussion on connections to automatic differentiation, optimization, and adjoints.

Common Interface High-Level Overview

The SciML interface is common as the usage of arguments is standardized across all of the problem domains. Underlying high-level ideas include:

  • All domains use the same interface of defining a AbstractSciMLProblem which is then solved via solve(prob,alg;kwargs), where alg is a AbstractSciMLAlgorithm. The keyword argument namings are standardized across the organization.
  • AbstractSciMLProblems are generally defined by a AbstractSciMLFunction which can define extra details about a model function, such as its analytical Jacobian, its sparsity patterns and so on.
  • There is an organization-wide method for defining linear and nonlinear solvers used within other solvers, giving maximum control of performance to the user.
  • Types used within the packages are defined by the input types. For example, packages attempt to internally use the type of the initial condition as the type for the state within differential equation solvers.
  • solve calls should be thread-safe and parallel-safe.
  • init(prob,alg;kwargs) returns an iterator which allows for directly iterating over the solution process
  • High performance is key. Any performance that is not at the top level is considered a bug and should be reported as such.
  • All functions have an in-place and out-of-place form, where the in-place form is made to utilize mutation for high performance on large-scale problems and the out-of-place form is for compatibility with tooling like static arrays and some reverse-mode automatic differentiation systems.

Flowchart Example for PDE-Constrained Optimal Control

The following example showcases how the pieces of the common interface connect to solve a problem that mixes inference, symbolics, and numerics.

External Binding Libraries

  • diffeqr

    • Solving differential equations in R using DifferentialEquations.jl with ModelingToolkit for JIT compilation and GPU-acceleration
  • diffeqpy

    • Solving differential equations in Python using DifferentialEquations.jl

Note About Third-Party Libraries

The SciML documentation references and recommends many third-party libraries for improving ones modeling, simulation, and analysis workflow in Julia. Take these as a positive affirmation of the quality of these libraries, as these libraries are commonly tested by SciML developers who are in contact with the development teams of these groups. It also documents the libraries which are commonly chosen by SciML as dependencies. Do not take omissions as negative affirmations against a given library, i.e. a library left off of the list by SciML is not a negative endorsement. Rather, it means that compatibility with SciML is untested, SciML developers may have a personal preference for another choice, or SciML developers may be simply unaware of the library's existence. If one would like to add a third-party library to the SciML documentation, open a pull request with the requested text.

Note that the libraries in this documentation are only those that are meant to be used in the SciML extended universe of modeling, simulation, and analysis and thus there are many high-quality libraries in other domains (machine learning, data science, etc.) which are purposefully not included. For an overview of the Julia package ecosystem, see the JuliaHub Search Engine.

+

Detailed Overview of the SciML Software Ecosystem

SciML: Combining High-Performance Scientific Computing and Machine Learning

SciML is not standard machine learning, SciML is the combination of scientific computing techniques with machine learning. Thus the SciML organization is not an organization for machine learning libraries (see FluxML for machine learning in Julia), rather SciML is an organization dedicated to the development of scientific computing tools which work seamlessly in conjunction with next-generation machine learning workflows. This includes:

  • High-performance and accurate tools for standard scientific computing modeling and simulation
  • Compatibility with differentiable programming and automatic differentiation
  • Tools for building complex multiscale models
  • Methods for handling inverse problems, model calibration, controls, and Bayesian analysis
  • Symbolic modeling tools for generating efficient code for numerical equation solvers
  • Methods for automatic discovery of (bio)physical equations

and much more. For an overview of the broad goals of the SciML organization, watch:

Overview of Computational Science in Julia with SciML

Below is a simplification of the user-facing packages for use in scientific computing and SciML workflows.

Workflow ElementSciML-Supported Julia packages
Plotting and VisualizationPlots*, Makie*
Sparse matrixSparseArrays*
Interpolation/approximationDataInterpolations*, ApproxFun*
Linear system / least squaresLinearSolve
Nonlinear system / rootfindingNonlinearSolve
Polynomial rootsPolynomials*
IntegrationIntegrals
Nonlinear OptimizationOptimization
Other Optimization (linear, quadratic, convex, etc.)JuMP*
Initial-value problemDifferentialEquations
Boundary-value problemDifferentialEquations
Continuous-Time Markov Chains (Poisson Jumps), Jump DiffusionsJumpProcesses
Finite differencesFiniteDifferences*, FiniteDiff*
Automatic DifferentiationForwardDiff*, Enzyme*, DiffEqSensitivity
Bayesian ModelingTuring*
Deep LearningFlux*
Acausal Modeling / DAEsModelingToolkit
Chemical Reaction NetworksCatalyst
Symbolic ComputingSymbolics
Fast Fourier TransformFFTW*
Partial Differential Equation DiscretizationsAssociated Julia packages
–-–-
Finite DifferencesMethodOfLines
Discontinuous GalerkinTrixi*
Finite ElementGridap*
Physics-Informed Neural NetworksNeuralPDE
Neural OperatorsNeuralOperators
High Dimensional Deep LearningHighDimPDE

* Denotes a non-SciML package that is heavily tested against as part of SciML workflows and has frequent collaboration with the SciML developers.

SciML Mind Map

Domains of SciML

The SciML common interface covers the following domains:

  • Linear systems (LinearProblem)

    • Direct methods for dense and sparse
    • Iterative solvers with preconditioning
  • Nonlinear Systems (NonlinearProblem)

    • Systems of nonlinear equations
    • Scalar bracketing systems
  • Integrals (quadrature) (IntegralProblem)

  • Differential Equations

    • Discrete equations (function maps, discrete stochastic (Gillespie/Markov) simulations) (DiscreteProblem and JumpProblem)
    • Ordinary differential equations (ODEs) (ODEProblem)
    • Split and Partitioned ODEs (Symplectic integrators, IMEX Methods) (SplitODEProblem)
    • Stochastic ordinary differential equations (SODEs or SDEs) (SDEProblem)
    • Stochastic differential-algebraic equations (SDAEs) (SDEProblem with mass matrices)
    • Random differential equations (RODEs or RDEs) (RODEProblem)
    • Differential algebraic equations (DAEs) (DAEProblem and ODEProblem with mass matrices)
    • Delay differential equations (DDEs) (DDEProblem)
    • Neutral, retarded, and algebraic delay differential equations (NDDEs, RDDEs, and DDAEs)
    • Stochastic delay differential equations (SDDEs) (SDDEProblem)
    • Experimental support for stochastic neutral, retarded, and algebraic delay differential equations (SNDDEs, SRDDEs, and SDDAEs)
    • Mixed discrete and continuous equations (Hybrid Equations, Jump Diffusions) (DEProblems with callbacks and JumpProblem)
  • Optimization (OptimizationProblem)

    • Nonlinear (constrained) optimization
  • (Stochastic/Delay/Differential-Algebraic) Partial Differential Equations (PDESystem)

    • Finite difference and finite volume methods
    • Interfaces to finite element methods
    • Physics-Informed Neural Networks (PINNs)
    • Integro-Differential Equations
    • Fractional Differential Equations
  • Specialized Forms

    • Partial Integro-Differential Equations (PIPDEProblem)
  • Data-driven modeling

    • Discrete-time data-driven dynamical systems (DiscreteDataDrivenProblem)
    • Continuous-time data-driven dynamical systems (ContinuousDataDrivenProblem)
    • Symbolic regression (DirectDataDrivenProblem)
  • Uncertainty quantification and expected values (ExpectationProblem)

The SciML common interface also includes ModelingToolkit.jl for defining such systems symbolically, allowing for optimizations like automated generation of parallel code, symbolic simplification, and generation of sparsity patterns.

Inverse Problems, Parameter Estimation, and Structural Identification

Parameter estimation and inverse problems are solved directly on their constituent problem types using tools like SciMLSensitivity.jl. Thus for example, there is no ODEInverseProblem, and instead ODEProblem is used to find the parameters p that solve the inverse problem. Check out the SciMLSensitivity documentation for a discussion on connections to automatic differentiation, optimization, and adjoints.

Common Interface High-Level Overview

The SciML interface is common as the usage of arguments is standardized across all of the problem domains. Underlying high-level ideas include:

  • All domains use the same interface of defining a AbstractSciMLProblem which is then solved via solve(prob,alg;kwargs), where alg is a AbstractSciMLAlgorithm. The keyword argument namings are standardized across the organization.
  • AbstractSciMLProblems are generally defined by a AbstractSciMLFunction which can define extra details about a model function, such as its analytical Jacobian, its sparsity patterns and so on.
  • There is an organization-wide method for defining linear and nonlinear solvers used within other solvers, giving maximum control of performance to the user.
  • Types used within the packages are defined by the input types. For example, packages attempt to internally use the type of the initial condition as the type for the state within differential equation solvers.
  • solve calls should be thread-safe and parallel-safe.
  • init(prob,alg;kwargs) returns an iterator which allows for directly iterating over the solution process
  • High performance is key. Any performance that is not at the top level is considered a bug and should be reported as such.
  • All functions have an in-place and out-of-place form, where the in-place form is made to utilize mutation for high performance on large-scale problems and the out-of-place form is for compatibility with tooling like static arrays and some reverse-mode automatic differentiation systems.

Flowchart Example for PDE-Constrained Optimal Control

The following example showcases how the pieces of the common interface connect to solve a problem that mixes inference, symbolics, and numerics.

External Binding Libraries

  • diffeqr

    • Solving differential equations in R using DifferentialEquations.jl with ModelingToolkit for JIT compilation and GPU-acceleration
  • diffeqpy

    • Solving differential equations in Python using DifferentialEquations.jl

Note About Third-Party Libraries

The SciML documentation references and recommends many third-party libraries for improving ones modeling, simulation, and analysis workflow in Julia. Take these as a positive affirmation of the quality of these libraries, as these libraries are commonly tested by SciML developers who are in contact with the development teams of these groups. It also documents the libraries which are commonly chosen by SciML as dependencies. Do not take omissions as negative affirmations against a given library, i.e. a library left off of the list by SciML is not a negative endorsement. Rather, it means that compatibility with SciML is untested, SciML developers may have a personal preference for another choice, or SciML developers may be simply unaware of the library's existence. If one would like to add a third-party library to the SciML documentation, open a pull request with the requested text.

Note that the libraries in this documentation are only those that are meant to be used in the SciML extended universe of modeling, simulation, and analysis and thus there are many high-quality libraries in other domains (machine learning, data science, etc.) which are purposefully not included. For an overview of the Julia package ecosystem, see the JuliaHub Search Engine.

diff --git a/dev/search/index.html b/dev/search/index.html index a3634296989..cb33c284c13 100644 --- a/dev/search/index.html +++ b/dev/search/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

Loading search...

    +

    Loading search...

      diff --git a/dev/showcase/bayesian_neural_ode/index.html b/dev/showcase/bayesian_neural_ode/index.html index 1fcd609abcc..492269b7f70 100644 --- a/dev/showcase/bayesian_neural_ode/index.html +++ b/dev/showcase/bayesian_neural_ode/index.html @@ -24,24 +24,24 @@ prob_neuralode = NeuralODE(dudt2, tspan, Tsit5(), saveat = tsteps) rng = Random.default_rng() p = Float64.(prob_neuralode.p)
      252-element Vector{Float64}:
      -  0.0946740135550499
      - -0.06895192712545395
      -  0.025188462808728218
      - -0.15108579397201538
      -  0.1345747709274292
      - -0.06528379768133163
      - -0.29343923926353455
      -  0.2644789218902588
      -  0.20572777092456818
      - -0.2001485824584961
      + -0.13664135336875916
      + -0.2656186819076538
      + -0.20960621535778046
      +  0.2923314571380615
      + -0.2101351022720337
      + -0.07807650417089462
      + -0.3195832073688507
      +  0.23736540973186493
      + -0.05271610617637634
      + -0.18366935849189758
         ⋮
      - -0.16261790692806244
      -  0.0230266023427248
      -  0.17098546028137207
      -  0.23557572066783905
      -  0.0929960086941719
      - -0.005417326465249062
      -  0.27089059352874756
      +  0.02988002635538578
      +  0.04223500192165375
      + -0.3171420395374298
      +  0.28972217440605164
      + -0.13236431777477264
      + -0.11407265067100525
      +  0.10723668336868286
         0.0
         0.0

      Note that the f64 is required to put the Flux neural network into Float64 precision.

      Step 3: Define the loss function for the Neural ODE.

      function predict_neuralode(p)
           Array(prob_neuralode(u0, p))
      @@ -61,522 +61,492 @@
       h = Hamiltonian(metric, l, dldθ)
      Hamiltonian(metric=DiagEuclideanMetric([1.0, 1.0, 1.0, 1.0, 1.0, 1 ...]), kinetic=AdvancedHMC.GaussianKinetic())

      We use the NUTS sampler with an acceptance ratio of δ= 0.45 in this example. In addition, we use Nesterov Dual Averaging for the Step Size adaptation.

      We sample using 500 warmup samples and 500 posterior samples.

      integrator = Leapfrog(find_good_stepsize(h, p))
       kernel = HMCKernel(Trajectory{MultinomialTS}(integrator, GeneralisedNoUTurn()))
       adaptor = StanHMCAdaptor(MassMatrixAdaptor(metric), StepSizeAdaptor(0.45, integrator))
      -samples, stats = sample(h, kernel, p, 500, adaptor, 500; progress = true)
      ([[0.12932825594800568, -0.02921020831109844, -0.25260361696521716, -0.07529149805723433, 0.11423258796333813, -0.11338209101398958, -0.260895619259785, 0.2559551401449385, 0.21431250069235372, -0.24439083734856637  …  0.18605629768102078, -0.16298928261959306, 0.022342978902300074, 0.197367501799322, 0.1574599072967362, 0.07630579647405931, -0.04356799270322403, 0.2537019184192707, -0.06928566174861855, -0.01260449322345175], [0.12932825594800568, -0.02921020831109844, -0.25260361696521716, -0.07529149805723433, 0.11423258796333813, -0.11338209101398958, -0.260895619259785, 0.2559551401449385, 0.21431250069235372, -0.24439083734856637  …  0.18605629768102078, -0.16298928261959306, 0.022342978902300074, 0.197367501799322, 0.1574599072967362, 0.07630579647405931, -0.04356799270322403, 0.2537019184192707, -0.06928566174861855, -0.01260449322345175], [0.12932825594800568, -0.02921020831109844, -0.25260361696521716, -0.07529149805723433, 0.11423258796333813, -0.11338209101398958, -0.260895619259785, 0.2559551401449385, 0.21431250069235372, -0.24439083734856637  …  0.18605629768102078, -0.16298928261959306, 0.022342978902300074, 0.197367501799322, 0.1574599072967362, 0.07630579647405931, -0.04356799270322403, 0.2537019184192707, -0.06928566174861855, -0.01260449322345175], [0.5752961808288843, 0.12464657287399994, -0.7995716583456044, 0.1526896554907333, -0.21066148828514222, -0.4481067172438857, -0.5442661639292692, 0.21505613712711402, -0.1875701326109276, -0.4296406116784853  …  0.2767567780533441, -0.13282301833712154, -0.015385617141473528, 0.18656893967143184, -0.25290520973619823, 0.3282163044575249, 0.0848647261681395, 0.06930503223102696, -0.8441376883630125, -0.13381790079106837], [0.7047714275775441, 0.18840570431413745, -0.879531627006684, 0.1417651872571308, -0.35798741816481555, -0.46703532467932046, -0.32054010331652183, 0.2906610757264455, -0.01732050283476841, -0.31060281675802554  …  0.2582216651892719, -0.42991741998074795, 0.013479631144397416, 0.2210852261405032, -0.15337620711864886, 0.370008394703064, 0.10833943568199646, 0.15230970552591977, -0.8950238185381263, -0.3347955206509124], [0.826446815821379, 0.742442997919344, -0.9141823265742964, -0.18340296078692495, -0.20963273236639357, -0.2783957844235662, -0.037663792772465635, 0.6789448605053617, -0.31122953656135, -0.43716302439429455  …  0.13154662613510523, -0.37187758461071757, -0.02133839704977375, 0.3603594182067316, -0.18771569669985896, 0.2509580206945814, 0.04307435530098565, 0.3538334840680358, -0.3765397841890822, -0.30452962239436093], [0.9514532574280914, 1.065959629810624, -1.2194900971297353, -0.6607567091271515, 0.3155215962936828, 0.15766727861156327, -0.47315040697257393, 0.598336444550189, 0.33819273248564796, -0.5171777328063228  …  0.004212736122291106, -0.08080282026793156, 0.8000285548233874, 0.7609376656999011, -0.44877702709773354, 0.19068474280639966, 0.5215288050921526, 0.909487050536933, 0.4443026977830713, -0.29680941145675144], [-0.20292144755313773, 0.7309631413463968, -0.6130258609358024, -1.0849618547494573, 0.5591453633054965, 0.08656564305237784, -0.0800699773200509, 1.04784461613384, 0.10432098516676003, 0.18626156478836825  …  -0.3015098615702522, 0.11256121505687902, 0.49761999878081975, -0.7771270420888049, -1.074909827481344, -0.053143293288995384, 0.3778774236978509, -0.17119733408121948, -0.5010678396011219, -0.6111234698993535], [-0.3455523949892709, 0.5513705697623763, -0.864963901944476, -1.281475333953451, 0.8365519373559196, 0.11041540162584913, 0.22139368964104714, 1.249224358011393, -0.00973948505483382, -0.4454501820160285  …  -0.21061542211948192, 0.27183810339105374, 0.29581040767458494, -0.3940529806336097, -0.9544769716476683, 0.31786790837657325, 0.4759805896493283, 0.04233027725472363, -0.5173771238370238, -0.6586047008434601], [1.1026336686617844, 0.10159575215395858, -1.6187499816063131, 0.3808567273877658, 0.34876676215120417, 0.1819124521133902, 0.4716551840242965, -0.5809939421264867, 1.1926914795376555, -0.3860751376848426  …  1.2848846313010605, -0.11570668377458629, 0.6558870897688276, 1.334858676728839, 0.2853161099099198, 0.509129311438134, -0.5823212005024563, 0.011352465376320245, -1.4739433319350608, 0.3474096086889565]  …  [0.28240830071582174, -0.6913891671838632, -0.26239538537071416, 0.25473866474342444, 0.2198031509756535, -0.5553446294568176, -0.5814952556429016, -1.1220176848666292, 0.9833998036435031, -0.6586853432534191  …  0.18711252585241528, 1.2267734738269165, 0.36664849329404925, -0.11832972867899769, 0.15319856743772986, -0.23261678167170036, 2.0150009236413697, 0.3364304571035065, -0.20789089881940187, 0.2768856078146214], [0.28135926982497655, -0.7221177431447583, -0.34020465374565173, 0.019167723554446486, 0.3024573281600232, -0.5305878765458781, -0.4846435211883385, -1.1650402576237484, 1.0019524954526777, -0.827982702578272  …  0.03889051947521131, 1.35055889557316, 0.43466895830485164, 0.052743843097653224, 0.28353350979756026, -0.31616786186447715, 2.1532643498564545, 0.38660047355067284, -0.281086089600112, 0.1879964633742769], [-0.15713065681257393, -0.40957845576394486, -0.9103443856765763, 0.005790559729251018, -0.7791199106248651, -0.14872192193138004, -0.6472305883442324, -1.0504914853538336, 1.2530531434744703, -0.4432108867110685  …  0.31368010770667676, 1.7449260622282416, -0.03616953844943871, 0.24190760924577115, 0.042504498791844134, -0.5947951477946191, 1.9437263653106849, -0.24401204021131362, -0.025212309778401727, 0.29190844813495137], [0.09408156298750045, -0.4793294153013517, -0.9060260543484796, 0.07976357332883525, -0.6266794359082004, -0.25039889820425837, -0.7023606095028061, -1.1380097569738348, 1.2906398041442009, 0.04797060544948087  …  0.642657585878261, 1.8321069854795093, -0.2356155045518722, 0.7190950243355896, -0.44606057297995083, -0.18512328338032552, 1.7635924937314726, 0.03826770506888605, -0.27095619100167007, -0.05110439754691242], [-0.06443069949866526, 0.1391454937810589, 0.13355344496257665, -0.42492190283159526, 0.32781625277211607, 0.367215434097175, -0.6029964699431088, 0.7923173278337234, -1.6322560337559637, -0.4681832611002697  …  -0.5649096261239251, -1.3586324442070283, -0.2128423926107436, -0.22726252554133988, -0.9455570106305794, 0.5024852501880952, -0.8901907896757395, -0.17565069014103923, -0.5546479953686987, -0.03130400025465559], [-0.012537651785852533, 0.13488769059375388, 0.09690363290504347, -0.305931071984546, 0.30120390927363794, 0.4355040499902811, -0.5525693799944317, 0.7143949773957763, -1.527355492173864, -0.4177296790492996  …  -0.48126550007636953, -1.3635776955358376, -0.25273832941885, -0.26046648447899007, -0.9764751987575088, 0.5138434239717496, -0.8903999534441697, -0.09891623804092414, -0.5647783435994596, -0.12832039834973769], [0.1361006829710237, -0.1344542147034778, -0.18755172258856143, -0.838782346442642, -0.19071063485899334, 0.5304937843649121, -0.26108477573877903, 0.9806679517499302, -1.2469997032345508, -0.38311979472197477  …  -0.30384147462791133, -1.3513163834824031, -0.4607888909449954, 0.20755239905629672, -1.0704994518678808, 0.27861409013008404, 0.09168714388864863, -0.6769599028863371, -0.72408267555026, -0.2746141180203172], [0.5111074715494088, 0.20828792590468698, -0.33826336656548533, -0.9286427451925487, -0.6327286910487138, -0.039081800086158455, -0.36907811971384247, 0.4373020191211305, -0.009874586950673728, -0.7302183365793813  …  0.7349869315452321, -0.4190596815472576, -0.04157749794133917, -0.3011305951097238, -0.2637780795278487, 0.24274775291253742, -0.3248338661855898, -0.001460221674855643, -0.393553786137991, 0.43485332550080646], [0.4793301217296716, 0.21947294288661778, -0.2875809909351216, -0.9105278440834553, -0.6181102176748603, -0.029919895376440044, -0.37924041100364164, 0.428527279570302, -0.03500077240333861, -0.6920080456501988  …  0.6927104603169618, -0.34433907485853543, -0.003811223100070635, -0.3463424788781344, -0.22451725812474888, 0.2710939782401302, -0.3794366924061155, -0.015129589327867501, -0.38374825685523334, 0.4488891722116033], [0.8244920541167461, 0.1688117973071548, -0.6423013993775144, -0.4569923001931871, -0.8752080482244118, -0.46497584558545707, -0.7948407384419116, -0.3156069940502141, -0.8286692145255602, 0.8995144588118662  …  0.09139194366587622, 1.3853735819018298, -0.11851463470078746, 0.013183953498442322, -0.2070493634882108, 0.8021051698451201, -0.4758158085059325, -0.520483009630884, -0.22074345430150025, 0.9407719870744243]], NamedTuple[(n_steps = 15, is_accept = true, acceptance_rate = 1.0, log_density = -233.8306556208057, hamiltonian_energy = 576.0519668272028, hamiltonian_energy_error = -46.28310243742294, max_hamiltonian_energy_error = -46.28310243742294, tree_depth = 4, numerical_error = false, step_size = 0.025, nom_step_size = 0.025, is_adapt = true), (n_steps = 1, is_accept = true, acceptance_rate = 0.0, log_density = -233.8306556208057, hamiltonian_energy = 371.6962759780288, hamiltonian_energy_error = 0.0, max_hamiltonian_energy_error = 80956.55947298543, tree_depth = 0, numerical_error = true, step_size = 0.6795704571147614, nom_step_size = 0.6795704571147614, is_adapt = true), (n_steps = 2, is_accept = true, acceptance_rate = 6.66860392752201e-193, log_density = -233.8306556208057, hamiltonian_energy = 356.75662894467064, hamiltonian_energy_error = 0.0, max_hamiltonian_energy_error = 13338.74432879012, tree_depth = 1, numerical_error = true, step_size = 0.3164493440113639, nom_step_size = 0.3164493440113639, is_adapt = true), (n_steps = 19, is_accept = true, acceptance_rate = 0.3450356993712858, log_density = -134.98837669217835, hamiltonian_energy = 346.09169080384413, hamiltonian_energy_error = -6.425110568247987, max_hamiltonian_energy_error = 1895.8240157359132, tree_depth = 4, numerical_error = true, step_size = 0.09837809577101383, nom_step_size = 0.09837809577101383, is_adapt = true), (n_steps = 7, is_accept = true, acceptance_rate = 0.4943802242400902, log_density = -129.16390772177365, hamiltonian_energy = 247.24055493375582, hamiltonian_energy_error = 0.0001860477304376218, max_hamiltonian_energy_error = 2040.642228433691, tree_depth = 2, numerical_error = true, step_size = 0.06813989805126368, nom_step_size = 0.06813989805126368, is_adapt = true), (n_steps = 17, is_accept = true, acceptance_rate = 0.22836875175837368, log_density = -100.23192783177387, hamiltonian_energy = 260.62318625380016, hamiltonian_energy_error = -3.9316491276533156, max_hamiltonian_energy_error = 2522.941601782941, tree_depth = 4, numerical_error = true, step_size = 0.07350369748096823, nom_step_size = 0.07350369748096823, is_adapt = true), (n_steps = 63, is_accept = true, acceptance_rate = 0.3358437526582088, log_density = -107.77024336406353, hamiltonian_energy = 235.64452462175308, hamiltonian_energy_error = -8.711863406518745, max_hamiltonian_energy_error = 48.86660341186288, tree_depth = 6, numerical_error = false, step_size = 0.036078774438333114, nom_step_size = 0.036078774438333114, is_adapt = true), (n_steps = 127, is_accept = true, acceptance_rate = 0.6561413527448381, log_density = -146.86267000366894, hamiltonian_energy = 248.5620758624388, hamiltonian_energy_error = 0.5344216325002833, max_hamiltonian_energy_error = 2.6138051464553484, tree_depth = 7, numerical_error = false, step_size = 0.024490088589913864, nom_step_size = 0.024490088589913864, is_adapt = true), (n_steps = 53, is_accept = true, acceptance_rate = 0.10621279742626882, log_density = -138.57050254282254, hamiltonian_energy = 261.19320156967206, hamiltonian_energy_error = -1.5458123794497851, max_hamiltonian_energy_error = 4310.50872147275, tree_depth = 5, numerical_error = true, step_size = 0.04577239287783111, nom_step_size = 0.04577239287783111, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.687632570676438, log_density = -141.62146229933106, hamiltonian_energy = 276.3909883522764, hamiltonian_energy_error = 0.991879030689006, max_hamiltonian_energy_error = 212.37009608650754, tree_depth = 8, numerical_error = false, step_size = 0.015330233958995524, nom_step_size = 0.015330233958995524, is_adapt = true)  …  (n_steps = 9, is_accept = true, acceptance_rate = 0.1116467648921357, log_density = -142.93958829091912, hamiltonian_energy = 269.8634771488758, hamiltonian_energy_error = 0.15386958273967366, max_hamiltonian_energy_error = 1059.1879943578842, tree_depth = 3, numerical_error = true, step_size = 0.08507673179571057, nom_step_size = 0.08507673179571057, is_adapt = true), (n_steps = 106, is_accept = true, acceptance_rate = 0.18311236053614505, log_density = -141.76451590454081, hamiltonian_energy = 275.02350086409365, hamiltonian_energy_error = -0.17594426927826134, max_hamiltonian_energy_error = 1225.82629829, tree_depth = 6, numerical_error = true, step_size = 0.036810442666893074, nom_step_size = 0.036810442666893074, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.2921018370855261, log_density = -132.1811354493697, hamiltonian_energy = 273.64883881418416, hamiltonian_energy_error = 1.0469540517572682, max_hamiltonian_energy_error = 2.536723038765274, tree_depth = 8, numerical_error = false, step_size = 0.019267036138588312, nom_step_size = 0.019267036138588312, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.6104348574814251, log_density = -129.58160266204436, hamiltonian_energy = 233.09470243943443, hamiltonian_energy_error = 0.08649100051408709, max_hamiltonian_energy_error = 1.33565556215558, tree_depth = 8, numerical_error = false, step_size = 0.013330056052755739, nom_step_size = 0.013330056052755739, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.7855606075537827, log_density = -135.52039394889243, hamiltonian_energy = 252.16215719326192, hamiltonian_energy_error = 0.039992935237592064, max_hamiltonian_energy_error = 0.5666075896382949, tree_depth = 8, numerical_error = false, step_size = 0.020265031651663972, nom_step_size = 0.020265031651663972, is_adapt = true), (n_steps = 90, is_accept = true, acceptance_rate = 0.0970173639722327, log_density = -134.18044924130072, hamiltonian_energy = 240.6777716509611, hamiltonian_energy_error = -0.023770563522930388, max_hamiltonian_energy_error = 3784.5683538215953, tree_depth = 6, numerical_error = true, step_size = 0.04694199283121891, nom_step_size = 0.04694199283121891, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.23880442774240104, log_density = -140.17075471229458, hamiltonian_energy = 270.88812426360226, hamiltonian_energy_error = -0.3082282412263453, max_hamiltonian_energy_error = 63.61645495398176, tree_depth = 8, numerical_error = false, step_size = 0.020271751311759987, nom_step_size = 0.020271751311759987, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.6767312405314171, log_density = -137.3127155823239, hamiltonian_energy = 275.64677665575925, hamiltonian_energy_error = 0.6740841408318943, max_hamiltonian_energy_error = 8.202921835221616, tree_depth = 8, numerical_error = false, step_size = 0.01245551804298131, nom_step_size = 0.01245551804298131, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.5707167872497731, log_density = -137.1628160603484, hamiltonian_energy = 281.06338910328486, hamiltonian_energy_error = -0.22324465937379045, max_hamiltonian_energy_error = 4.555779090054443, tree_depth = 8, numerical_error = false, step_size = 0.02193064332629803, nom_step_size = 0.02193064332629803, is_adapt = true), (n_steps = 127, is_accept = true, acceptance_rate = 0.664564501726975, log_density = -145.46908855427685, hamiltonian_energy = 277.1132918075884, hamiltonian_energy_error = 0.343628867678774, max_hamiltonian_energy_error = 33.00347237141489, tree_depth = 7, numerical_error = false, step_size = 0.0297931396098152, nom_step_size = 0.0297931396098152, is_adapt = true)])

      Step 5: Plot diagnostics

      Now let's make sure the fit is good. This can be done by looking at the chain mixing plot and the autocorrelation plot. First, let's create the chain mixing plot using the plot recipes from ????

      samples = hcat(samples...)
      +samples, stats = sample(h, kernel, p, 500, adaptor, 500; progress = true)
      ([[-0.10288323982833103, -0.30368778747955627, -0.18565929541461393, 0.2932270176958391, -0.19232450359319658, 0.0010237387983624557, -0.3602055396841529, 0.2582042940408002, -0.11477894963671226, -0.18410069394991976  …  -0.05476731947248009, 0.024925998092954864, -0.04797728050277089, -0.2829904252435846, 0.3037678630247793, -0.1449676982659088, -0.05705464575071134, 0.09210826508728844, -0.010529739632117558, 0.016549152732972628], [-0.10288323982833103, -0.30368778747955627, -0.18565929541461393, 0.2932270176958391, -0.19232450359319658, 0.0010237387983624557, -0.3602055396841529, 0.2582042940408002, -0.11477894963671226, -0.18410069394991976  …  -0.05476731947248009, 0.024925998092954864, -0.04797728050277089, -0.2829904252435846, 0.3037678630247793, -0.1449676982659088, -0.05705464575071134, 0.09210826508728844, -0.010529739632117558, 0.016549152732972628], [-0.10288323982833103, -0.30368778747955627, -0.18565929541461393, 0.2932270176958391, -0.19232450359319658, 0.0010237387983624557, -0.3602055396841529, 0.2582042940408002, -0.11477894963671226, -0.18410069394991976  …  -0.05476731947248009, 0.024925998092954864, -0.04797728050277089, -0.2829904252435846, 0.3037678630247793, -0.1449676982659088, -0.05705464575071134, 0.09210826508728844, -0.010529739632117558, 0.016549152732972628], [-0.2616122517322865, -0.16967670324547232, 0.029981946793439726, 0.7982227013251215, -0.15957183984050355, 0.46740112577261583, -0.6221416062660821, 0.40583852915307744, 0.12761947291436132, 0.15472894324798556  …  -0.3799809690421321, -0.11214173096259485, -0.4268169047148577, -0.09298819345834616, 0.5425388041756667, 0.12346550771242998, 0.31410875153393575, -0.1179131314350348, -0.2613557537202937, -0.2583474996178085], [-0.2305553262137497, -0.20328728156615616, -0.0599856439278841, -0.029367641916322865, -1.2043097937244587, 0.8753070892814281, -0.5232407587745694, -0.10498270134098416, -0.10642607637513912, 0.1877914630233721  …  -0.2250943744039403, -0.6996316896232946, -0.051079203310544705, -0.3912574264332069, 0.7151178718870406, -0.6057364594664663, 0.21540567843288208, 0.21822093836009895, -0.18766178071036418, -1.092982503646285], [-0.2305553262137497, -0.20328728156615616, -0.0599856439278841, -0.029367641916322865, -1.2043097937244587, 0.8753070892814281, -0.5232407587745694, -0.10498270134098416, -0.10642607637513912, 0.1877914630233721  …  -0.2250943744039403, -0.6996316896232946, -0.051079203310544705, -0.3912574264332069, 0.7151178718870406, -0.6057364594664663, 0.21540567843288208, 0.21822093836009895, -0.18766178071036418, -1.092982503646285], [-0.21641949363893787, -0.36089187735425254, 0.10199686166372818, -0.23830491054674816, -1.36000508396775, 0.7407533975133238, -0.7596525359583597, 0.020102914853655948, 0.1131223246353025, 0.00626650421654908  …  -0.14563199588166917, -0.8657401398752442, 0.038749934767637065, -0.3085490065179713, 1.0596008588823298, -0.5306081690773549, -0.05128707001588957, -0.11923313838996852, -0.3367758234196241, -0.9325119127877782], [-0.8841188945887535, -1.271928068490181, 0.45412450161475976, 0.6049077479803187, -0.7538263415447519, -0.478473465320542, 0.2130531260650273, 0.38654684610024315, 0.0988154098484644, -0.29974611648441696  …  0.5738081663721731, -0.23802321782433955, -0.7370484932217245, -0.2455296123093411, 0.9784250612521029, -0.06454775163950167, 0.34929821238753284, -0.2516144797591524, -0.11641297170723569, -0.6618843777088207], [-0.980736965595891, -0.6441894541206903, 0.10463783668187504, 0.5015467128223811, -0.8321359983193807, -1.3965842312445738, -0.37460307788508634, 0.7346739447818214, 0.45988535586937335, -0.35355780212822446  …  0.1588964231208908, 0.006428511688932008, -0.45585318885146764, 0.6404512653789773, 0.18054794249790507, -0.424153967626961, 0.010414680735513712, -0.4580605688099165, -0.9501851110126744, 0.0535241411189894], [-0.3351741492359679, -1.2681482018012074, -0.6402507626422437, 0.9052964713777018, -0.0283800124063335, -0.12546849548994735, 0.7318992869081682, -0.15011865967335178, 0.294169182201743, -0.1822877134273622  …  0.40349128866140826, -0.7449524785275986, -1.512303664472835, 1.3138150370800317, -0.2780159199154124, 0.27282877065987604, 0.12245467238252153, 0.230354603781306, -0.3921211121556396, -0.750661839199617]  …  [-0.6372008696334299, -0.5935261746941068, -0.16552055756881076, -0.31205796292848753, -0.48825690285775786, 0.11849016947866908, 1.3443759585123882, -1.1981131515492545, -0.25194617699892546, 0.26407655238070676  …  1.4259237250916788, -0.4372219371244143, -0.6742594930574324, -0.5916676466226254, -0.11917242161979745, 0.49847519405515445, 0.6001987927244659, 0.16823247002036437, -0.2564484625770159, 0.8367995469045996], [-0.6500479214400292, -0.5535275882703555, -0.19251900729741925, -0.35452502593184887, -0.5177065719768942, 0.17825800000509168, 1.3601032505614072, -1.3276678319388613, -0.229431988516493, 0.30103442617320775  …  1.4286183937124521, -0.4084410663872776, -0.7066893590027341, -0.6294778314081508, -0.10237084686891393, 0.5312034929703726, 0.6454008123419451, 0.13438620362721992, -0.23207455150549658, 0.9145510033363319], [0.13648782311275273, -0.3243829392237604, 0.2569774213379858, -0.13752835494759566, -0.09482082401347947, 0.4304805286868112, 0.8602410916604142, -0.18832131087050352, 0.8562097648953082, -0.31908253023984756  …  -0.05825207349384944, -0.5206201614878757, -0.021905801647355932, 0.3114776104471349, -0.5988045467000195, -0.9087072158024809, 0.46746502539994955, 1.0310347503906396, -0.35722025744635766, 0.34995538409765964], [0.08462239122715022, 0.059212812216807506, 0.12964321542195684, -0.2463071056598794, -0.355139802045342, -0.05452649964409425, 1.2089914479806103, 0.10970345413241828, 0.6262908088646257, -0.11880047635503503  …  0.1281715965296624, -0.7588453334153854, -0.17316883896239843, 0.14014059167335335, -0.5340693303965911, -0.9131010573636601, 0.649769823618682, 1.410183866813516, -0.295601358584647, 0.636564983034695], [1.3781424216880918, -1.1842901667326078, -0.8214094161134778, -0.03165249823410803, -0.18211979990921004, 0.36316108856113666, -0.14962397619559023, 0.6013296270419743, -0.8738503865138719, -0.368114746963469  …  -1.0605474020172032, -0.7138500814625222, -0.8204631690669324, -1.0611790070437372, -0.9705655225723246, -1.1302645347718023, -0.8460176769042181, 0.8269145600063303, -0.31137332104499194, -0.17887233117340978], [1.0529968724928078, -0.9889041676662944, -0.5307769535479085, -0.08513798412635876, -0.015073418706490165, 0.5196758019542633, 0.09977155777697794, -0.026743871892139615, -0.7536983350528845, -0.13241640009739786  …  -0.5236335823158765, -0.6609520161623257, -0.2552781138110598, -1.5547785056373384, 0.5764232671610847, -0.5130709203100721, 0.8137180073123667, 0.07298863217772315, -0.6538833489722226, 0.895056047900885], [-0.9705782898561034, -0.878076854964079, 0.8235532574978908, -0.4290192809917347, -0.01985961490930085, 0.05189494461841376, 0.08187865540244593, 0.2601516084158805, -0.9930180073063563, 0.03278528933684631  …  0.40430882962918435, -0.03909776371177456, -0.20569014728665097, -0.036965604536163384, 0.18624754633487065, -0.16844547983594843, -0.6527321634123442, 0.6138316753682292, 0.052146918985917196, -0.21172919758956055], [-1.1935802147470207, -0.84923067691585, 0.8691786157419784, -0.548728469088594, 0.3255401951472008, 0.07092421767105606, -0.22586994474864192, 0.24273911844912602, -0.5733934236642747, -0.06389431489705287  …  0.703129809428621, 0.1562515654994282, -0.38849980129064443, -0.00032260229255816775, 0.13432570002089725, -0.37148256246277284, -0.6699781184752072, 0.8535732506915679, 0.10478566045547646, -0.2706838988354406], [-1.1464234645946378, -0.89211806847025, 0.9004233313035324, -0.45263835135965763, 0.33283873222875693, 0.04487005021446397, -0.2957296438503696, 0.1881581643900385, -0.5674081706507622, -0.07460696172473413  …  0.6179845573109409, -0.027487706282164875, -0.30380437356993, -0.0895030114779268, 0.09396682855094883, -0.4006133002228734, -0.8080183149722941, 0.8053777837616657, 0.016719468204323892, -0.406139444007034], [-1.1883940677251976, -0.9372071990357838, 0.9792444938145579, -0.3681540044171485, 0.3246671804765625, -0.023964403179046287, -0.29016250816692124, 0.2643814282075199, -0.7185708441305084, 0.011604671275860637  …  0.7098389972048706, -0.009759698225982511, -0.3976538925098134, -0.11820998786679605, 0.25184905924925194, -0.41572689025314624, -0.8026289137184117, 0.8612441674339981, -0.03100674562183852, -0.4405484146533537]], NamedTuple[(n_steps = 15, is_accept = true, acceptance_rate = 1.0, log_density = -239.41236247916643, hamiltonian_energy = 635.7814705390448, hamiltonian_energy_error = -96.22946024541648, max_hamiltonian_energy_error = -96.22946024541648, tree_depth = 4, numerical_error = false, step_size = 0.025, nom_step_size = 0.025, is_adapt = true), (n_steps = 1, is_accept = true, acceptance_rate = 0.0, log_density = -239.41236247916643, hamiltonian_energy = 368.5035237036341, hamiltonian_energy_error = 0.0, max_hamiltonian_energy_error = 3.2745206324070613e6, tree_depth = 0, numerical_error = true, step_size = 0.6795704571147614, nom_step_size = 0.6795704571147614, is_adapt = true), (n_steps = 3, is_accept = true, acceptance_rate = 4.115212041153673e-160, log_density = -239.41236247916643, hamiltonian_energy = 353.62883993496376, hamiltonian_energy_error = 0.0, max_hamiltonian_energy_error = 1623.1587472530496, tree_depth = 1, numerical_error = true, step_size = 0.3164493440113639, nom_step_size = 0.3164493440113639, is_adapt = true), (n_steps = 10, is_accept = true, acceptance_rate = 0.2000621193192269, log_density = -130.8445065835108, hamiltonian_energy = 383.3066438716504, hamiltonian_energy_error = -8.44470959612454, max_hamiltonian_energy_error = 1935.838960597473, tree_depth = 3, numerical_error = true, step_size = 0.09837809577101383, nom_step_size = 0.09837809577101383, is_adapt = true), (n_steps = 20, is_accept = true, acceptance_rate = 0.8617404830487534, log_density = -97.74823169321074, hamiltonian_energy = 243.8682900938772, hamiltonian_energy_error = -17.552390907491883, max_hamiltonian_energy_error = 2297.9184398239486, tree_depth = 4, numerical_error = true, step_size = 0.045031069611746403, nom_step_size = 0.045031069611746403, is_adapt = true), (n_steps = 2, is_accept = true, acceptance_rate = 3.360407521591632e-116, log_density = -97.74823169321074, hamiltonian_energy = 220.4938010617122, hamiltonian_energy_error = 0.0, max_hamiltonian_energy_error = 1066.5615370919074, tree_depth = 1, numerical_error = true, step_size = 0.14264580726586562, nom_step_size = 0.14264580726586562, is_adapt = true), (n_steps = 63, is_accept = true, acceptance_rate = 0.22716924131652147, log_density = -85.56113790981848, hamiltonian_energy = 242.75303569032363, hamiltonian_energy_error = -0.4281739376316125, max_hamiltonian_energy_error = 77.91855889627203, tree_depth = 6, numerical_error = false, step_size = 0.0354239605774612, nom_step_size = 0.0354239605774612, is_adapt = true), (n_steps = 127, is_accept = true, acceptance_rate = 0.6407376754372875, log_density = -110.67717572305628, hamiltonian_energy = 207.14831637703196, hamiltonian_energy_error = 1.3105726406871554, max_hamiltonian_energy_error = 1.7345671901733795, tree_depth = 7, numerical_error = false, step_size = 0.017139450128451483, nom_step_size = 0.017139450128451483, is_adapt = true), (n_steps = 127, is_accept = true, acceptance_rate = 0.4791917716135713, log_density = -126.61417285915411, hamiltonian_energy = 227.84450772116992, hamiltonian_energy_error = -0.15066164830386697, max_hamiltonian_energy_error = 175.7515379474442, tree_depth = 7, numerical_error = false, step_size = 0.03041515989902078, nom_step_size = 0.03041515989902078, is_adapt = true), (n_steps = 101, is_accept = true, acceptance_rate = 0.507136795960759, log_density = -135.89621343024854, hamiltonian_energy = 261.8440838083088, hamiltonian_energy_error = -0.41693213857854516, max_hamiltonian_energy_error = 1552.2919684119065, tree_depth = 6, numerical_error = true, step_size = 0.03301422991537497, nom_step_size = 0.03301422991537497, is_adapt = true)  …  (n_steps = 127, is_accept = true, acceptance_rate = 0.7643915270601692, log_density = -145.14928355446992, hamiltonian_energy = 263.69739244080677, hamiltonian_energy_error = 0.5218135742919685, max_hamiltonian_energy_error = 1.0915964492575085, tree_depth = 7, numerical_error = false, step_size = 0.028324638446779835, nom_step_size = 0.028324638446779835, is_adapt = true), (n_steps = 17, is_accept = true, acceptance_rate = 0.21894255562019027, log_density = -147.19655999492545, hamiltonian_energy = 263.9757624927681, hamiltonian_energy_error = 0.025943507136275912, max_hamiltonian_energy_error = 3312.736547523114, tree_depth = 4, numerical_error = true, step_size = 0.06370508889661489, nom_step_size = 0.06370508889661489, is_adapt = true), (n_steps = 127, is_accept = true, acceptance_rate = 0.24173461428210213, log_density = -122.75390790108602, hamiltonian_energy = 268.3158123631457, hamiltonian_energy_error = 0.24051380690457336, max_hamiltonian_energy_error = 18.900558116697653, tree_depth = 7, numerical_error = false, step_size = 0.036351019064173644, nom_step_size = 0.036351019064173644, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.17082825448462768, log_density = -118.66494489766043, hamiltonian_energy = 239.8416287516111, hamiltonian_energy_error = -0.315423152049334, max_hamiltonian_energy_error = 13.46783397625029, tree_depth = 8, numerical_error = false, step_size = 0.022123838034681403, nom_step_size = 0.022123838034681403, is_adapt = true), (n_steps = 511, is_accept = true, acceptance_rate = 0.627680927306958, log_density = -156.76900621306567, hamiltonian_energy = 268.6102235398982, hamiltonian_energy_error = -0.4999564433998671, max_hamiltonian_energy_error = 1.5189985700504849, tree_depth = 9, numerical_error = false, step_size = 0.01139217061055047, nom_step_size = 0.01139217061055047, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.501599951351731, log_density = -119.5999983511233, hamiltonian_energy = 260.41691011137425, hamiltonian_energy_error = -0.25534140146601203, max_hamiltonian_energy_error = 9.379897125269508, tree_depth = 8, numerical_error = false, step_size = 0.018046015755775118, nom_step_size = 0.018046015755775118, is_adapt = true), (n_steps = 255, is_accept = true, acceptance_rate = 0.9299473915734214, log_density = -128.53130037224946, hamiltonian_energy = 251.60197176469939, hamiltonian_energy_error = -0.41389653373929036, max_hamiltonian_energy_error = 0.7425563168031601, tree_depth = 8, numerical_error = false, step_size = 0.020925179011610787, nom_step_size = 0.020925179011610787, is_adapt = true), (n_steps = 14, is_accept = true, acceptance_rate = 0.31689255986833953, log_density = -129.69251187343042, hamiltonian_energy = 266.8898830226422, hamiltonian_energy_error = 0.3269459408786588, max_hamiltonian_energy_error = 1018.0535285101896, tree_depth = 3, numerical_error = true, step_size = 0.06784383041391492, nom_step_size = 0.06784383041391492, is_adapt = true), (n_steps = 63, is_accept = true, acceptance_rate = 0.7177648708412376, log_density = -130.84180816139374, hamiltonian_energy = 274.4624130022585, hamiltonian_energy_error = -0.07732051212860824, max_hamiltonian_energy_error = 14.601216023189693, tree_depth = 6, numerical_error = false, step_size = 0.050031553088210896, nom_step_size = 0.050031553088210896, is_adapt = true), (n_steps = 31, is_accept = true, acceptance_rate = 0.01122480487169965, log_density = -134.48745333151743, hamiltonian_energy = 266.85726019885146, hamiltonian_energy_error = 1.3471536640169006, max_hamiltonian_energy_error = 1487.842968764748, tree_depth = 4, numerical_error = true, step_size = 0.09590658963114755, nom_step_size = 0.09590658963114755, is_adapt = true)])

      Step 5: Plot diagnostics

      Now let's make sure the fit is good. This can be done by looking at the chain mixing plot and the autocorrelation plot. First, let's create the chain mixing plot using the plot recipes from ????

      samples = hcat(samples...)
       samples_reduced = samples[1:5, :]
       samples_reshape = reshape(samples_reduced, (500, 5, 1))
       Chain_Spiral = Chains(samples_reshape)
       plot(Chain_Spiral)
      - + - + - + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + +

      Now we check the autocorrelation plot:

      autocorplot(Chain_Spiral)
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + +

      As another diagnostic, let's check the result on retrodicted data. To do this, we generate solutions of the Neural ODE on samples of the neural network parameters, and check the results of the predictions against the data. Let's start by looking at the time series:

      pl = scatter(tsteps, ode_data[1, :], color = :red, label = "Data: Var1", xlabel = "t",
                    title = "Spiral Neural ODE")
      @@ -595,734 +565,734 @@
             ylims = (-2.5, 3.5))
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      That showed the time series form. We can similarly do a phase-space plot:

      pl = scatter(ode_data[1, :], ode_data[2, :], color = :red, label = "Data", xlabel = "Var1",
                    ylabel = "Var2", title = "Spiral Neural ODE")
       for k in 1:300
      @@ -1333,390 +1303,390 @@
             label = "Best fit prediction", ylims = (-2.5, 3))
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/showcase/blackhole/index.html b/dev/showcase/blackhole/index.html index 625d570854e..99877b2e026 100644 --- a/dev/showcase/blackhole/index.html +++ b/dev/showcase/blackhole/index.html @@ -371,304 +371,304 @@ label="waveform data", xlabel="Time", ylabel="Waveform") - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Looks great!

      Automating the Discovery of Relativistic Equations from Newtonian Physics

      Now let's learn the relativistic corrections directly from the data. To define the UDE, we will define a Lux neural network and pass it into our Newtonian Physics + Nerual Network ODE definition from above:

      NN = Lux.Chain((x) -> cos.(x),
           Lux.Dense(1, 32, cos),
           Lux.Dense(32, 32, cos),
      @@ -751,109 +751,109 @@
       plot!(plt, Newt_orbit[1,:], Newt_orbit[2,:], linewidth = 2, label = "Newtonian")
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      plt = plot(tsteps,true_waveform, linewidth = 2, label = "truth", xlabel="Time", ylabel="Waveform")
       plot!(plt,tsteps,pred_waveform, linestyle = :dash, linewidth = 2, label = "prediction")
       plot!(plt,tsteps,Newt_waveform, linewidth = 2, label = "Newtonian")
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Now we'll do the same, but extrapolating the model out in time.

      factor=5
       
       extended_tspan = (tspan[1], factor*tspan[2])
      @@ -873,53 +873,53 @@
       plot!(plt, Newt_orbit[1,:], Newt_orbit[2,:], linewidth = 2, label = "Newtonian")
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      true_waveform = compute_waveform(dt_data, reference_solution, mass_ratio, model_params)[1]
       pred_waveform = compute_waveform(dt_data, optimized_solution, mass_ratio, model_params)[1]
       Newt_waveform = compute_waveform(dt_data, Newtonian_solution, mass_ratio, model_params)[1]
      @@ -928,49 +928,49 @@
       plot!(plt,extended_tsteps,Newt_waveform, linewidth = 2, label = "Newtonian")
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dev/showcase/brusselator/index.html b/dev/showcase/brusselator/index.html index b4b40229c83..c2578600209 100644 --- a/dev/showcase/brusselator/index.html +++ b/dev/showcase/brusselator/index.html @@ -382,4 +382,4 @@ ydomain:([0.0, 11.5], 0.0:0.03125:1.0, 0.0:0.03125:1.0) u: Dict{Symbolics.Num, Array{Float64, 3}} with 2 entries: u(x, y, t) => [0.0 0.115882 … 0.115882 0.0; 0.0 0.115882 … 0.115882 0.0; … ; … - v(x, y, t) => [0.0 0.0 … 0.0 0.0; 0.142219 0.142219 … 0.142219 0.142219; … ; …

      And now we're zooming! For more information on these performance improvements, check out the deeper dive in the DifferentialEquations.jl tutorials.

      If you're interested in figuring out what's the fastest current solver for this kind of PDE, check out the Brusselator benchmark in SciMLBenchmarks.jl

      + v(x, y, t) => [0.0 0.0 … 0.0 0.0; 0.142219 0.142219 … 0.142219 0.142219; … ; …

      And now we're zooming! For more information on these performance improvements, check out the deeper dive in the DifferentialEquations.jl tutorials.

      If you're interested in figuring out what's the fastest current solver for this kind of PDE, check out the Brusselator benchmark in SciMLBenchmarks.jl

      diff --git a/dev/showcase/gpu_spde/index.html b/dev/showcase/gpu_spde/index.html index 74d91d401d0..e36bd64be27 100644 --- a/dev/showcase/gpu_spde/index.html +++ b/dev/showcase/gpu_spde/index.html @@ -213,56 +213,56 @@ plot(p1, p2, p3, layout = grid(3, 1)) - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - +

      and see the pretty gradients. Using this 2nd order ROCK method we solve this equation in about 2 seconds. That's okay.

      Some Optimizations

      There are some optimizations that can still be done. When we do A*B as matrix multiplication, we create another temporary matrix. These allocations can bog down the system. Instead, we can pre-allocate the outputs and use the inplace functions mul! to make better use of memory. The easiest way to store these cache arrays are constant globals, but you can use closures (anonymous functions which capture data, i.e. (x)->f(x,y)) or call-overloaded types to do it without globals. The globals way (the easy way) is simply:

      const MyA = zeros(N, N)
       const AMx = zeros(N, N)
      @@ -1187,58 +1187,58 @@
       plot(p1, p2, p3, layout = grid(3, 1))
      - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - +

      Making Use of GPU Parallelism

      That was all using the CPU. How do we turn on GPU parallelism with DifferentialEquations.jl? Well, you don't. DifferentialEquations.jl "doesn't have GPU bits". So, wait... can we not do GPU parallelism? No, this is the glory of type-genericness, especially in broadcasted operations. To make things use the GPU, we simply use a CuArray from CUDA.jl. If instead of zeros(N,M) we used CuArray(zeros(N,M)), then the array lives on the GPU. CuArray naturally overrides broadcast such that dotted operations are performed on the GPU. DifferentialEquations.jl uses broadcast internally, and thus just by putting the array as a CuArray, the array-type will take over how all internal updates are performed and turn this algorithm into a fully GPU-parallelized algorithm that doesn't require copying to the CPU. Wasn't that simple?

      From that you can probably also see how to multithread everything, or how to set everything up with distributed parallelism. You can make the ODE solvers do whatever you want by defining an array type where the broadcast does whatever special behavior you want.

      So to recap, the entire difference from above is changing to:

      using CUDA
       const gMx = CuArray(Float32.(Mx))
      @@ -1854,13 +1854,13 @@ 

      @time sol = solve(prob2, ROCK2(), progress = true, dt = 0.003, save_everystep = false, + [0.30325767 0.30234623 … 0.9336535 0.9336841; 0.30325767 0.30234623 … 0.9336535 0.9336841; … ; 0.30325767 0.30234623 … 0.9336535 0.9336841; 0.30325767 0.30234623 … 0.9336535 0.9336841;;; 1.3027548 1.302752 … 1.0227438 1.0225888; 1.3027548 1.302752 … 1.0227438 1.0225888; … ; 1.3027548 1.302752 … 1.0227438 1.0225888; 1.3027548 1.302752 … 1.0227438 1.0225888;;; 0.69724476 0.697248 … 0.977256 0.97741115; 0.69724476 0.697248 … 0.977256 0.97741115; … ; 0.69724476 0.697248 … 0.977256 0.97741115; 0.69724476 0.697248 … 0.977256 0.97741115]

      @time sol = solve(prob2, ROCK2(), progress = true, dt = 0.003, save_everystep = false,
                         save_start = false);
      retcode: Success
       Interpolation: 1st order linear
       t: 1-element Vector{Float64}:
        100.0
       u: 1-element Vector{CUDA.CuArray{Float32, 3, CUDA.Mem.DeviceBuffer}}:
      - [0.30271584 0.30306542 … 0.93237853 0.9343681; 0.30271584 0.30306542 … 0.93237853 0.9343681; … ; 0.30271584 0.30306542 … 0.93237853 0.9343681; 0.30271584 0.30306542 … 0.93237853 0.9343681;;; 1.3027564 1.3027575 … 1.0227376 1.022586; 1.3027564 1.3027575 … 1.0227376 1.022586; … ; 1.3027564 1.3027575 … 1.0227376 1.022586; 1.3027564 1.3027575 … 1.0227376 1.022586;;; 0.6972434 0.69724286 … 0.97726214 0.97741383; 0.6972434 0.69724286 … 0.97726214 0.97741383; … ; 0.6972434 0.69724286 … 0.97726214 0.97741383; 0.6972434 0.69724286 … 0.97726214 0.97741383]

      Go have fun.

      And Stochastic PDEs?

      Why not make it an SPDE? All that we need to do is extend each of the PDE equations to have a noise function. In this case, let's use multiplicative noise on each reactant. This means that our noise update equation is:

      function g(du, u, p, t)
      + [0.30325767 0.30234623 … 0.9336535 0.9336841; 0.30325767 0.30234623 … 0.9336535 0.9336841; … ; 0.30325767 0.30234623 … 0.9336535 0.9336841; 0.30325767 0.30234623 … 0.9336535 0.9336841;;; 1.3027548 1.302752 … 1.0227438 1.0225888; 1.3027548 1.302752 … 1.0227438 1.0225888; … ; 1.3027548 1.302752 … 1.0227438 1.0225888; 1.3027548 1.302752 … 1.0227438 1.0225888;;; 0.69724476 0.697248 … 0.977256 0.97741115; 0.69724476 0.697248 … 0.977256 0.97741115; … ; 0.69724476 0.697248 … 0.977256 0.97741115; 0.69724476 0.697248 … 0.977256 0.97741115]

      Go have fun.

      And Stochastic PDEs?

      Why not make it an SPDE? All that we need to do is extend each of the PDE equations to have a noise function. In this case, let's use multiplicative noise on each reactant. This means that our noise update equation is:

      function g(du, u, p, t)
           A = @view u[:, :, 1]
           B = @view u[:, :, 2]
           C = @view u[:, :, 3]
      @@ -1873,7 +1873,7 @@ 

      g (generic function with 1 method)

      Now we just define and solve the system of SDEs:

      prob = SDEProblem(f, g, u0, (0.0, 100.0))
       @time sol = solve(prob, SRIW1());
      retcode: Success
       Interpolation: 1st order linear
      -t: 81899-element Vector{Float64}:
      +t: 81851-element Vector{Float64}:
          0.0
          9.999999999999999e-5
          0.0002125
      @@ -1885,36 +1885,36 @@ 

      using Plots; + [0.09646455070068949 0.19081383362642987 … 0.552696886721195 0.28041727280208684; 0.19098885080628872 0.37859029814190154 … 1.0958729786456187 0.5542563041636865; … ; 0.17822601074279507 0.3515286664616202 … 1.1739563774950208 0.5916687649320154; 0.08842808780974419 0.1740438835286809 … 0.583614409376296 0.2980423164218833;;; 1.4807416791743329 1.2936680976386068 … 0.7779770981286704 1.2966292635353684; 1.508876208788154 1.1986098562272742 … 1.66421364398101 1.4752535343565272; … ; 1.443688829385668 1.412663590399399 … -0.11179642618732723 1.2120386405875985; 1.4502143908713998 1.4771594217931336 … 0.9044031490061342 1.2514272043836012;;; 0.5983030183234982 0.6821515873356683 … 0.9144504181335084 0.5831288669778389; 0.868827395601281 0.7824494000192074 … 0.7407500070840383 1.195265109671546; … ; 0.5644452667257976 0.8169409720032799 … 0.7535341903459564 1.5087496778008656; 0.5051182605788538 0.624129537171639 … 0.9868806212166832 0.8440180357486671] + [0.09758688310330736 0.1902468516615602 … 0.5531380177782256 0.27818715519139847; 0.19128718537977396 0.3795098102161097 … 1.0981386576873329 0.551504516843306; … ; 0.1785260002362333 0.35220479071077104 … 1.1748843284102235 0.5939027877531831; 0.08892836015784608 0.17325630435214767 … 0.5841147415524209 0.2972454421105424;;; 1.480491903387295 1.2945407160065525 … 0.7800364082729647 1.2971501555006806; 1.5094324776271002 1.199171351908066 … 1.6532692582905906 1.4767137932322765; … ; 1.4432289524449515 1.4124413001110552 … -0.1055026445422763 1.2123609430148181; 1.4499711453153903 1.4767044910163016 … 0.9074567637610942 1.2521021195041804;;; 0.5978733498703606 0.6820382828110226 … 0.911765503370522 0.5840677828822599; 0.8696955280836774 0.7804694376416399 … 0.7410969857615677 1.1963183448538186; … ; 0.5652915420763657 0.8176654431919206 … 0.7511466840967094 1.5081183234205446; 0.5053743537350541 0.6242755251157728 … 0.9833661566485732 0.8420520012875503] + [0.09714512235218736 0.1892660359919299 … 0.5550402920892795 0.2792940726506945; 0.1906283426778959 0.3776627134629835 … 1.0974776292813972 0.5501295461268373; … ; 0.17872553882174838 0.35466854689387306 … 1.168643292866164 0.5929300472442849; 0.08944488443820363 0.17603931521854554 … 0.583847172291909 0.2963242356420525;;; 1.4798664962708468 1.2937953175144046 … 0.7769283185029707 1.2955004593462545; 1.5086185605148679 1.2003576466188461 … 1.652094808955759 1.4753707700027177; … ; 1.4438992454628963 1.4112198729753118 … -0.09945957407171424 1.2125590329409737; 1.449927801918963 1.4770040087622682 … 0.9091710561144368 1.2488307976507163;;; 0.5971910859751567 0.6825389935634742 … 0.9074563632216555 0.5815615076583494; 0.8692014390669321 0.7832274455296264 … 0.7538993957009513 1.197161001782196; … ; 0.5656939185435388 0.8187517182736607 … 0.7502100930081615 1.5089410386958992; 0.5054035361774684 0.6237750921909363 … 0.983237745571288 0.8444788394140619] + [0.09612904027205328 0.1896049211120471 … 0.5504739313316087 0.2802166992478846; 0.1902929765746136 0.3776229937619354 … 1.0949949872311229 0.5484391238110213; … ; 0.17932051772753543 0.3571317465213481 … 1.172164098940479 0.5872627560407048; 0.08988241245664566 0.17771873235364466 … 0.5813460606378839 0.29773793478730537;;; 1.480238825080542 1.2948611388410043 … 0.7845727087129132 1.2963937220610773; 1.5098193440236138 1.1986971197942136 … 1.65569885525159 1.4752090723606632; … ; 1.4433702355580154 1.412428958138641 … -0.09156036623273114 1.215184216679148; 1.4486827267455553 1.476601585175237 … 0.9131005079445601 1.2500847213241149;;; 0.5985855533675263 0.6809786428508965 … 0.9036645766030568 0.5821567723545437; 0.8684040127095658 0.7836337640167336 … 0.758929117172378 1.2000131198455712; … ; 0.5660242629247589 0.8218263991882273 … 0.7563067893086569 1.5032854992030378; 0.5052911162783936 0.6244007815055724 … 0.9795232782295895 0.8462738684003863] + [0.09686025056187057 0.18948112766900715 … 0.5464961463571665 0.2805391065595319; 0.19070564633790932 0.37828819189639845 … 1.0941339210035008 0.5420851677312655; … ; 0.18056980587372648 0.3577312095844426 … 1.1820724869501398 0.5839750825823733; 0.09086846990899784 0.17965472858059373 … 0.5755241796046768 0.2994771512940068;;; 1.4808187204529006 1.2938914523039067 … 0.7892889929927628 1.2965687531522203; 1.5086146457887117 1.1975179163119067 … 1.6561168405898363 1.472869835574375; … ; 1.4429662229718394 1.4111724902684042 … -0.08307853789812207 1.2186034949915914; 1.4477980081679223 1.4763261853719578 … 0.9143341524478236 1.2525114069704721;;; 0.5989437510000946 0.6821798036775052 … 0.9026980842232123 0.5803389906436407; 0.868344014025799 0.7854824382260832 … 0.7628409036406361 1.2028511483923983; … ; 0.5670887585152512 0.8260764600068154 … 0.7544233770461286 1.4992952740635483; 0.5053490267139125 0.6251163093093762 … 0.9734744992353622 0.8468273379608423] + [0.09881848077526514 0.18845984123723833 … 0.5326450618052083 0.28671464029126864; 0.19078098201117297 0.3846803827619556 … 1.1194882488772293 0.5284610612210308; … ; 0.18063441953243112 0.3619318602638585 … 1.1976526149525721 0.5696985471755212; 0.09109041441765915 0.18157585133372547 … 0.5619294899423681 0.30555760862267506;;; 1.4809482960439904 1.2935266537738512 … 0.798544133038908 1.2974944116974212; 1.5086618166308075 1.1995939899011474 … 1.652510397255163 1.4733741194571162; … ; 1.4425777862922655 1.4096330241661097 … -0.07610740255036538 1.2226009634327641; 1.4471154764885237 1.47705642096728 … 0.9178344498223053 1.2546615744544;;; 0.5984680334881484 0.6814120617267647 … 0.8961514941887764 0.5794508940243283; 0.8670334760585926 0.7836567151541968 … 0.7612893314168881 1.2018247125540997; … ; 0.5688616129389631 0.8243500574351551 … 0.7522345376007933 1.4962140859581534; 0.5052508944704664 0.6241465539634445 … 0.9715378301393011 0.8435422812953896] + [0.1019500716825797 0.1787042331115414 … 0.4626315058493348 0.31259828163356573; 0.18340836522381662 0.4010443997663521 … 1.2408141968642392 0.4682563758209021; … ; 0.17883005656962192 0.3591246223926366 … 1.2771948140484066 0.5161327456912927; 0.09193591696033436 0.1861787317621486 … 0.5080450115519224 0.33272316120528705;;; 1.4807087845860154 1.2933818521467668 … 0.7982404597158393 1.298109675436605; 1.5094970940745704 1.199545026882167 … 1.638594332300682 1.4748747895075696; … ; 1.4405033838221908 1.4042716531161623 … -0.07456844627994941 1.2251360379823468; 1.4465197748189003 1.4770505178304683 … 0.9261174203245137 1.2522181453770156;;; 0.5961645996106324 0.6793973810236585 … 0.8957102427576406 0.5748581797167526; 0.8634072639298648 0.780034231081711 … 0.7732124379403245 1.2013680807764575; … ; 0.5680270169025045 0.8236805327674771 … 0.7288279279153079 1.481987523791542; 0.5055994443537312 0.6238971132403521 … 0.9668329628139681 0.8412870249175374] + [0.12041184957860032 0.14380543835558945 … 0.16890368101881784 0.45039683810324976; 0.1480366692577263 0.4702557509724498 … 1.8173916339659317 0.18443991374356758; … ; 0.17669527413193692 0.34209217164354117 … 1.6435727358784582 0.3066995942942514; 0.09059175064910904 0.2014979738356065 … 0.2952059790208572 0.4481981147990168;;; 1.4809866037863444 1.2949134604036996 … 0.8052226099454743 1.298416998495018; 1.5100523773808299 1.1990411391681641 … 1.636925349603533 1.481507623854669; … ; 1.44101629016076 1.402105465703674 … -0.058601177932360075 1.217249104348573; 1.4467619010939332 1.4759350886620795 … 0.9294817052082429 1.2516724574567286;;; 0.5965081016544246 0.6784474201195466 … 0.8954449620436628 0.572079767335614; 0.8612374255144222 0.7778521110157187 … 0.780057692274665 1.1977687061904256; … ; 0.5692483973451714 0.8185067471501619 … 0.717679970670317 1.482121213093903; 0.5058230582562696 0.6236846307715691 … 0.9636721067040508 0.837985853794698] + [0.11712444833339042 0.15091478958488877 … 0.21462471080147782 0.4326058058921839; 0.15407315874835564 0.45753630293726516 … 1.7251783807596237 0.21875448041955017; … ; 0.1830659525841155 0.33812147178431906 … 1.5510960856367433 0.3571882578064466; 0.08892368638387413 0.20073680595074786 … 0.3474522889713572 0.4179217863456781;;; 1.4813076252974942 1.2965876082048664 … 0.8102343962515418 1.3009724472014441; 1.509532455197964 1.199291277197112 … 1.6398208801403673 1.4807372607864908; … ; 1.4404726770399043 1.4029235198070806 … -0.06334606848647314 1.2216674748410807; 1.4467707749495098 1.4776510186128913 … 0.9375950681657617 1.252954215965623;;; 0.5975439107657821 0.6797592381010982 … 0.8901677921009914 0.5711203212861102; 0.8612412589108887 0.778523106854961 … 0.7830687097791438 1.1944966132279307; … ; 0.5712672378050376 0.8203070547077294 … 0.7178180372367743 1.4812696459841441; 0.5061268555655746 0.6229147341714016 … 0.9611927985539404 0.8387403839462098]

      using Plots;
       gr();
       
       # Use `Array` to transform the result back into a CPU-based `Array` for plotting
      @@ -1924,448 +1924,466 @@ 

      - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +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 +UzO5rHaLyJY2bmlyYiZYv5La2tmUYzna2vGeYVqVktOT3nWnZi50VD6GTU3ParO65F0/ci7UftY1 +0XfrXNn0iNcutqIdv7p0EHNrV1R3vWB0fvVq6Nx/9+SWYk5rrh6p35mRQvD8ZHQ/zsfy4da3z0yM +6rmp47WP42bN+wn/xZd/Y9fA8Qsv/xKBJAAAAIBjhcASAAAAAAaQiKeUskfU7GrHacmRJNlWPHJP +JjEaHbNHFbPTillpjeVnWnMEao2KjFz/88j4uM5MehV9d5aDqsliZUPJRFfg1pXj5XIFLW7diqyh +UqlqfNRrEWvb3t6UTVOTUWe46K3KdISDtXpVSSujbGKi9TBL9VL4+6g0Nv11JJTS1PhZ7163qNtL +r/nXJZwgYHTsIAxNO9HvrD3ftenod9xb+It4Y9sLfetudE9PSfrK3yb1F3Nz/p1/cueE5lYvDvis +/fntl719POs9Ql8AAAAAeFQRWAIAAAB45F3KfLuRpKvZT3RFfkazM6dDI8mYV6m3WrorSWq4O3Ks +ZOiaUjPcTrSQmdTEiFc5WXI3+qyid/Vkr1K5hluWrZh/Lqa4zkxekhNzItcmrawSCa/laz41pXyh +oMWNm5KkmwuvRq5Px0ZVanh7SZ6bvqy1La/K0jVN1UwQ+G1uete0g7eFtRtKx70QMhZzlEvnZVsx +yUgxkwjtc1l2dxSPeeHjRP5U5D03ttYkGa2V7sq2o+/U65sauNPqMdqr8jD81Gu/TLUlAAAAgCOP +wBIAAAAABmBZ0dxnuxENH6tuUeemg70sV0p3WoGh0cT0VM+5q81w5d9Mq6VqJj4mSbqzEt6PsnMf +ynI9WjV4d/W6zp+6rOXN27KtIPDbrCxpdW1Z0/kz0SDUcvzQz1JMCytzmlu6Hpm7bsp+2Fiveu1w +x7Lee+3U1zRZOKPO+LFeDVcS3lp8VY6JReZt+96TQYvcf34x0Tux7clb/a1KdO/Ji7lsJNC0bVe/ +9/pEj2nuT6BpafDWuAcxmei/D2mmR5C9m3986jOPVqoLAAAAYOgILAEAAACgg7GjP5PaFYedksoq +rlSonWkvKSun5c1F3d24rqWlBUlehWR3DtdOiMo9QtA2x/JCqVLNCykrtbIkKe3ktbG+KkmamTyh +mLxA8OTYBUnS/Opbill9Aq2Ohbit/SYdy7vfthNqmLI2tleVz4z7162V5r3r3SCEyzqjOjPxto45 +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 +" transform="translate(156, 123)"/> - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +iVBORw0KGgoAAAANSUhEUgAABywAAAEoCAYAAAAKWQYgAAAgAElEQVR4nOzd6ZMk133u96f2qq6q +rt732YEBQJAgAS4AQYDYCHBfIJIiCdLS1QvbcSN87b/CEX5hRzgcYeuVI+4Lx40rK3gX0SKvxCtK +FEmRIAmAGAAzmAWz9PS+d9e+Hr84VZWVlVnVPSCAmgG+nwixM0+ePHkye/Ci9cTvnIAxRgAAAAAA +AAAAAAAwCMFBTwAAAAAAAAAAAADABxeBJQAAAAAAAAAAAICBIbAEAAAAAAAAAAAAMDAElgAAAAAA +AAAAAAAGhsASAAAAAAAAAAAAwMAQWAIAAAAAAAAAAAAYGAJLAAAAAAAAAAAAAANDYAkAAAAAAAAA +AABgYAgsAQAAAAAAAAAAAAwMgSUAAAAAAAAAAACAgSGwBAAAAAAAAAAAADAwBJYAAAAAAAAAAAAA +BobAEgAAAAAAAAAAAMDAEFgCAAAAAAAAAAAAGBgCSwAAAAAAAAAAAAADQ2AJAAAAAAAAAAAAYGAI +LAEAAAAAAAAAAAAMDIElAAAAAAAAAAAAgIEhsAQAAAAAAAAAAAAwMASWAAAAAAAAAAAAAAaGwBIA +AAAAAAAAAADAwBBYAgAAAAAAAAAAABgYAksAAAAAAAAAAAAAA0NgCQAAAAAAAAAAAGBgCCwBAAAA +AAAAAAAADAyBJQAAAAAAAAAAAICBIbAEAAAAAAAAAAAAMDAElgAAAAAAAAAAAAAGhsASAAAAAAAA +AAAAwMAQWAIAAAAAAAAAAAAYGAJLAAAAAAAAAAAAAANDYAkAAAAAAAAAAABgYAgsAQAAAAAAAAAA +AAwMgSUAAAAAAAAAAACAgSGwBAAAAAAAAAAAADAwBJYAAAAAAAAAAAAABobAEgAAAAAAAAAAAMDA +EFgCAAAAAAAAAAAAGBgCSwAAAAAAAAAAAAADQ2AJAAAAAAAAAAAAYGAILAEAAAAAAAAAAAAMDIEl +AAAAAAAAAAAAgIEhsAQAAAAAAAAAAAAwMASWAAAAAAAAAAAAAAaGwBIAAAAAAAAAAADAwBBYAgAA +AAAAAAAAABgYAksAAAAAAAAAAAAAA0NgCQAAAAAAAAAAAGBgCCwBAAAAAAAAAAAADAyBJQAAAAAA +AAAAAICBIbAEAAAAAAAAAAAAMDAElgAAAAAAAAAAAAAGhsASAAAAAAAAAAAAwMAQWAIAAAAAAAAA +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 +" transform="translate(156, 657)"/> - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +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 +suRsNNQNvLPSLSsUdffHHPzo/F/e9nOv63zsP3/T1xtJ+v13upWr96/+J0kvb3D4z9/yF53h3ryR +1eb3fOvr+r0DAAAAuDsQWAIAAADAHeag1VQuPatBlHVS4jSosjT9n3jRUFiNXs/TJ5rISJIy4bwq +HXvEW8cH2qxXFA5HPX13K4ee85Qauri2JiPp4xs/ZCQpn52XJF0rbgfO6aPrP2gk6Y2LZ06Y/Wvd +6Lf3EvLD/q1fePs3G88l42132oy74quR9Pa1ef2HdwTvRQoAAAAA00RgCQAAAABT9ONr3+sLkNaz +89ot73quGdORJOVjSV0t7o7eEigdtYPIs4urkozaxl+FuRhLq9GsBeZokVhC5UZRRkaH5Ypz/aNn +7T0rl2bcpV1/9S0/bc7PbygVCl7u9WapIUn6zEV3+dNUOKRffOgDRpKeOPPuuzZIu/rd3zz1uf/G +Y3/pNufAorAAAAAA7hwElgAAAADwKvrsxfd4UqILcxsBvfxbVs6lvEuybh8dOD33jg81PxPTYafk +tJe7ZfdmyztcrVfyPCGacvfBXM+ue54btfxLv+ZTKed4LTOrUCjmm/P55RXn+Jcf7e+F+aC7B2az +5477P77xp40kfXjdrv775IXv8SVpf+/P/A3zcxd++I5M2CZNqlgtT2gNHuBz931L4JBGRr//zvdO +fAczqQuSpN988/eYQSj5r9/2bU6p7uDmq9dinnMAAAAAmCYCSwAAAACYorBpSpJ+/pGPm89e/MGJ ++dGtul1luTK3pkJ+RUv5Rd0o3nTav3bjPklSpVNSdOTn3qXdp1Xr2c86nz/vG/vK9k2NxlflRsM5 +bjer2jk61Kh4PKWd+n7gfH/y7HcPDej/aHOprK/tH/5Xn3BOPnfP5HDuzvHip/lP3+TdY/Jfve27 +jCTNpK6NvScRSo1tu0teGAAAAAB4EFgCAAAAwJT97Yvfb1r1LUmSJ7Qckz5dP3hBadX15Z0runDm +Xs3PLTttEUuSwpKk42ZbMlK10dZyYkFzsbzCITu03DraGhox+EFRdXRx9f7AtlareeLnyidXnePD +yguSpGT8xe1pebcGcatzC75rv/LIX72tj/Ov3u6GmjeP3T1Dzchb2SzmTjGa0T9+oz1eqXY7swAA +AACAVw6BJQAAAAC8ihYy82Pbwsl57TXrzvlWec/TfqGQ03GrqQfm7NAvatl7VD69/bzT52x+WZmw +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 +QmCC +" transform="translate(156, 1190)"/> - + - + - + -

      We can see the cool effect that diffusion dampens the noise in [A] but is unable to dampen the noise in [B] which results in a very noisy [C]. The stiff SPDE takes much longer to solve even using high order plus adaptivity because stochastic problems are just that much more difficult (current research topic is to make new algorithms for this!). It gets GPU'd just by using CuArray like before. But there we go: solving systems of stochastic PDEs using high order adaptive algorithms with within-method GPU parallelism. That's gotta be a first? The cool thing is that nobody ever had to implement the GPU-parallelism either, it just exists by virtue of the Julia type system.

      (Note: We can also use one of the SROCK methods for better performance here, but they will require a choice of dt. This is left to the reader to try.)

      Note

      This can take a while to solve! An explicit Runge-Kutta algorithm isn't necessarily great here, though to use a stiff solver on a problem of this size requires once again smartly choosing sparse linear solvers. The high order adaptive method is pretty much necessary though, since something like Euler-Maruyama is simply not stable enough to solve this at a reasonable dt. Also, the current algorithms are not so great at handling this problem. Good thing there's a publication coming along with some new stuff...

      +

      We can see the cool effect that diffusion dampens the noise in [A] but is unable to dampen the noise in [B] which results in a very noisy [C]. The stiff SPDE takes much longer to solve even using high order plus adaptivity because stochastic problems are just that much more difficult (current research topic is to make new algorithms for this!). It gets GPU'd just by using CuArray like before. But there we go: solving systems of stochastic PDEs using high order adaptive algorithms with within-method GPU parallelism. That's gotta be a first? The cool thing is that nobody ever had to implement the GPU-parallelism either, it just exists by virtue of the Julia type system.

      (Note: We can also use one of the SROCK methods for better performance here, but they will require a choice of dt. This is left to the reader to try.)

      Note

      This can take a while to solve! An explicit Runge-Kutta algorithm isn't necessarily great here, though to use a stiff solver on a problem of this size requires once again smartly choosing sparse linear solvers. The high order adaptive method is pretty much necessary though, since something like Euler-Maruyama is simply not stable enough to solve this at a reasonable dt. Also, the current algorithms are not so great at handling this problem. Good thing there's a publication coming along with some new stuff...

      diff --git a/dev/showcase/massively_parallel_gpu/index.html b/dev/showcase/massively_parallel_gpu/index.html index 77e6ff57354..7dd7b2b1710 100644 --- a/dev/showcase/massively_parallel_gpu/index.html +++ b/dev/showcase/massively_parallel_gpu/index.html @@ -27,4 +27,4 @@ sol = solve(monteprob, Tsit5(), EnsembleThreads(), trajectories = 10_000, saveat = 1.0f0)

      EnsembleSolution Solution of length 10000 with uType:
       SciMLBase.ODESolution{Float32, 2, Vector{StaticArraysCore.SVector{3, Float32}}, Nothing, Nothing, Vector{Float32}, Vector{Vector{StaticArraysCore.SVector{3, Float32}}}, SciMLBase.ODEProblem{StaticArraysCore.SVector{3, Float32}, Tuple{Float32, Float32}, false, StaticArraysCore.SVector{3, Float32}, SciMLBase.ODEFunction{false, SciMLBase.AutoSpecialize, typeof(Main.lorenz), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardODEProblem}, OrdinaryDiffEq.Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, OrdinaryDiffEq.InterpolationData{SciMLBase.ODEFunction{false, SciMLBase.AutoSpecialize, typeof(Main.lorenz), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Nothing}, Vector{StaticArraysCore.SVector{3, Float32}}, Vector{Float32}, Vector{Vector{StaticArraysCore.SVector{3, Float32}}}, OrdinaryDiffEq.Tsit5ConstantCache}, DiffEqBase.Stats, Nothing}

      Taking the Ensemble to the GPU

      Now uhh, we just change EnsembleThreads() to EnsembleGPUArray()

      sol = solve(monteprob, Tsit5(), EnsembleGPUArray(CUDA.CUDABackend()), trajectories = 10_000, saveat = 1.0f0)
      EnsembleSolution Solution of length 10000 with uType:
       SciMLBase.ODESolution{Float32, 2, uType, Nothing, Nothing, Vector{Float32}, rateType, SciMLBase.ODEProblem{StaticArraysCore.SVector{3, Float32}, Tuple{Float32, Float32}, false, StaticArraysCore.SVector{3, Float32}, SciMLBase.ODEFunction{false, SciMLBase.AutoSpecialize, typeof(Main.lorenz), LinearAlgebra.UniformScaling{Bool}, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, Nothing, typeof(SciMLBase.DEFAULT_OBSERVED), Nothing, Nothing}, Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, SciMLBase.StandardODEProblem}, OrdinaryDiffEq.Tsit5{typeof(OrdinaryDiffEq.trivial_limiter!), typeof(OrdinaryDiffEq.trivial_limiter!), Static.False}, IType, DiffEqBase.Stats, Nothing} where {uType, rateType, IType}

      Or for a more efficient version, EnsembleGPUKernel(). But that requires special solvers, so we also change to GPUTsit5().

      sol = solve(monteprob, GPUTsit5(), EnsembleGPUKernel(CUDA.CUDABackend()), trajectories = 10_000)
      EnsembleSolution Solution of length 10000 with uType:
      -SciMLBase.ODESolution{Float32, 2, uType, Nothing, Nothing, tType, Nothing, P, A, IType, Nothing, Nothing} where {uType, tType, P, A, IType}

      Okay, so that was anticlimactic, but that's the point: if it were harder than that, it wouldn't be automatic! Now go check out DiffEqGPU.jl's documentation for more details, that's the end of our show.

      +SciMLBase.ODESolution{Float32, 2, uType, Nothing, Nothing, tType, Nothing, P, A, IType, Nothing, Nothing} where {uType, tType, P, A, IType}

      Okay, so that was anticlimactic, but that's the point: if it were harder than that, it wouldn't be automatic! Now go check out DiffEqGPU.jl's documentation for more details, that's the end of our show.

      diff --git a/dev/showcase/missing_physics/index.html b/dev/showcase/missing_physics/index.html index 54925b699f9..3c808bb9c2b 100644 --- a/dev/showcase/missing_physics/index.html +++ b/dev/showcase/missing_physics/index.html @@ -43,95 +43,95 @@ scatter!(t, transpose(Xₙ), color = :red, label = ["Noisy Data" nothing]) - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Definition of the Universal Differential Equation

      Now let's define our UDE. We will use Lux.jl to define the neural network as follows:

      rbf(x) = exp.(-(x .^ 2))
       
       # Multilayer FeedForward
      @@ -285,39 +285,39 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + +

      Next, we compare the original data to the output of the UDE predictor. Note that we can even create more samples from the underlying model by simply adjusting the time steps!

      ## Analysis of the trained network
       # Plot the data and the approximation
       ts = first(solution.t):(mean(diff(solution.t)) / 2):last(solution.t)
      @@ -328,95 +328,95 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Let's see how well the unknown term has been approximated:

      # Ideal unknown interactions of the predictor
       Ȳ = [-p_[2] * (X̂[1, :] .* X̂[2, :])'; p_[3] * (X̂[1, :] .* X̂[2, :])']
       # Neural network guess
      @@ -427,55 +427,55 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      And have a nice look at all the information:

      # Plot the error
       pl_reconstruction_error = plot(ts, norm.(eachcol(Ȳ - Ŷ)), yaxis = :log, xlabel = "t",
                                      ylabel = "L2-Error", label = nothing, color = :red)
      @@ -484,161 +484,161 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + +

      That looks pretty good. And if we are happy with deep learning, we can leave it at that: we have trained a neural network to capture our missing dynamics.

      But...

      Can we also make it print out the LaTeX for what the missing equations were? Find out more after the break!

      Symbolic regression via sparse regression (SINDy based)

      This part of the showcase is still a work in progress... shame on us. But be back in a jiffy and we'll have it done.

      Okay, that was a quick break, and that's good because this next part is pretty cool. Let's use DataDrivenDiffEq.jl to transform our trained neural network from machine learning mumbo jumbo into predictions of missing mechanistic equations. To do this, we first generate a symbolic basis that represents the space of mechanistic functions we believe this neural network should map to. Let's choose a bunch of polynomial functions:

      @variables u[1:2]
       b = polynomial_basis(u, 4)
      @@ -748,55 +748,55 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      We are still a bit off, so we fine tune the parameters by simply minimizing the residuals between the UDE predictor and our recovered parametrized equations:

      function parameter_loss(p)
           Y = reduce(hcat, map(Base.Fix2(nn_eqs, p), eachcol(X̂)))
           sum(abs2, Ŷ .- Y)
      @@ -815,109 +815,109 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      true_prob = ODEProblem(lotka!, u0, t_long, p_)
       true_solution_long = solve(true_prob, Tsit5(), saveat = estimate_long.t)
       plot!(true_solution_long)
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Post Processing and Plots

      c1 = 3 # RGBA(174/255,192/255,201/255,1) # Maroon
       c2 = :orange # RGBA(132/255,159/255,173/255,1) # Red
       c3 = :blue # RGBA(255/255,90/255,0,1) # Orange
      @@ -954,228 +954,228 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + Timeseries of UODE Error - - - - - - + + + + + + x(t) - - + + y(t) - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Neural Network Fit of U2(t) - - - - - - + + + + + + Neural Network - - + + True Missing Term - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + Extrapolated Fit From Short Training Data - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x data - - + + y data - - + + True x(t) - - + + True y(t) - - + + Estimated x(t) - - + + Estimated y(t) - + Training - + Data - + diff --git a/dev/showcase/ode_types/index.html b/dev/showcase/ode_types/index.html index 80ff3f64479..94028c73fda 100644 --- a/dev/showcase/ode_types/index.html +++ b/dev/showcase/ode_types/index.html @@ -160,53 +160,53 @@ plot(sol, lw = 3)

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Measurements.jl: Numbers with Linear Uncertainty Propagation

      The result of a measurement should be given as a number with an attached uncertainty, besides the physical unit, and all operations performed involving the result of the measurement should propagate the uncertainty, taking care of correlation between quantities.

      There is a Julia package for dealing with numbers with uncertainties: Measurements.jl. Thanks to Julia's features, DifferentialEquations.jl easily works together with Measurements.jl out-of-the-box.

      Let's try to automate uncertainty propagation through number types on some classical physics examples!

      Warning about Measurement type

      Before going on with the tutorial, we must point up a subtlety of Measurements.jl that you should be aware of:

      using Measurements
       5.23 ± 0.14 === 5.23 ± 0.14
      false
      (5.23 ± 0.14) - (5.23 ± 0.14)

      \[0.0 \pm 0.2\]

      (5.23 ± 0.14) / (5.23 ± 0.14)

      \[1.0 \pm 0.038\]

      The two numbers above, even though have the same nominal value and the same uncertainties, are actually two different measurements that only by chance share the same figures and their difference and their ratio have a non-zero uncertainty. It is common in physics to get very similar, or even equal, results for a repeated measurement, but the two measurements are not the same thing.

      Instead, if you have one measurement and want to perform some operations involving it, you have to assign it to a variable:

      x = 5.23 ± 0.14
       x === x
      true
      x - x

      \[0.0 \pm 0.0\]

      x / x

      \[1.0 \pm 0.0\]

      With that in mind, let's start using Measurements.jl for realsies.

      Automated UQ on an ODE: Radioactive Decay of Carbon-14

      The rate of decay of carbon-14 is governed by a first order linear ordinary differential equation:

      \[\frac{\mathrm{d}u(t)}{\mathrm{d}t} = -\frac{u(t)}{\tau}\]

      where $\tau$ is the mean lifetime of carbon-14, which is related to the half-life $t_{1/2} = (5730 \pm 40)$ years by the relation $\tau = t_{1/2}/\ln(2)$. Writing this in DifferentialEquations.jl syntax, this looks like:

      # Half-life and mean lifetime of radiocarbon, in years
      @@ -274,139 +274,139 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      The two curves are perfectly superimposed, indicating that the numerical solution matches the analytic one. We can check that also the uncertainties are correctly propagated in the numerical solution:

      println("Quantity of carbon-14 after ", sol.t[11], " years:")
       println("Numerical: ", sol[11])
       println("Analytic:  ", u[11])
      Quantity of carbon-14 after 5207.541628507064 years:
      @@ -479,713 +479,713 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Bingo. Also in this case there is a perfect superimposition between the two curves, including their uncertainties.

      We can also have a look at the difference between the two solutions:

      plot(sol.t, getindex.(sol.u, 2) .- u, label = "")
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Tiny difference on the order of the chosen 1e-6 tolerance.

      Simple pendulum: Arbitrary amplitude

      Now that we know how to solve differential equations involving numbers with uncertainties, we can solve the simple pendulum problem without any approximation. This time, the differential equation to solve is the following:

      \[\ddot{\theta} + \frac{g}{L} \sin(\theta) = 0\]

      That would be done via:

      g = 9.79 ± 0.02; # Gravitational constants
       L = 1.00 ± 0.01; # Length of the pendulum
      @@ -1209,375 +1209,375 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

      Warning about Linear Uncertainty Propagation

      Measurements.jl uses linear uncertainty propagation, which has an error associated with it. MonteCarloMeasurements.jl has a page which showcases where this method can lead to incorrect uncertainty measurements. Thus for more nonlinear use cases, it's suggested that one uses one of the more powerful UQ methods, such as:

      Basically, types can make the algorithm you want to run exceedingly simple to do, but make sure it's the correct algorithm!

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Warning about Linear Uncertainty Propagation

      Measurements.jl uses linear uncertainty propagation, which has an error associated with it. MonteCarloMeasurements.jl has a page which showcases where this method can lead to incorrect uncertainty measurements. Thus for more nonlinear use cases, it's suggested that one uses one of the more powerful UQ methods, such as:

      Basically, types can make the algorithm you want to run exceedingly simple to do, but make sure it's the correct algorithm!

      diff --git a/dev/showcase/optimization_under_uncertainty/index.html b/dev/showcase/optimization_under_uncertainty/index.html index fd5ccb9c424..2c13134e345 100644 --- a/dev/showcase/optimization_under_uncertainty/index.html +++ b/dev/showcase/optimization_under_uncertainty/index.html @@ -25,47 +25,47 @@ plot(sol, vars = (1, 3), label = nothing, xlabel = "x", ylabel = "y")

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + +

      For this particular problem, we wish to measure the impact distance from a point $y=25$ on a wall at $x=25$. So, we introduce an additional callback that terminates the simulation on wall impact.

      stop_condition(u, t, integrator) = u[1] - 25.0
       stop_cb = ContinuousCallback(stop_condition, terminate!)
      @@ -77,49 +77,49 @@
       plot(sol, vars = (1, 3), label = nothing, xlabel = "x", ylabel = "y")
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + +

      To help visualize this problem, we plot as follows, where the star indicates a desired impact location

      rectangle(xc, yc, w, h) = Shape(xc .+ [-w, w, w, -w] ./ 2.0, yc .+ [-h, -h, h, h] ./ 2.0)
       
      @@ -133,52 +133,52 @@
       end
      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Considering Uncertainty

      We now wish to introduce uncertainty in p[2], the coefficient of restitution. This is defined via a continuous univariate distribution from Distributions.jl. We can then run a Monte Carlo simulation of 100 trajectories via the EnsembleProblem interface.

      using Distributions
       
      @@ -201,154 +201,154 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -

      Here, we plot the first 350 Monte Carlo simulations along with the trajectory corresponding to the mean of the distribution (dashed line).

      We now wish to compute the expected squared impact distance from the star. This is called an “observation” of our system or an “observable” of interest.

      We define this observable as

      obs(sol, p) = abs2(sol[3, end] - 25)
      obs (generic function with 1 method)

      With the observable defined, we can compute the expected squared miss distance from our Monte Carlo simulation results as

      mean_ensemble = mean([obs(sol, p) for sol in ensemblesol])
      32.16541746073479

      Alternatively, we can use the Koopman() algorithm in SciMLExpectations.jl to compute this expectation much more efficiently as

      using SciMLExpectations
      +

      Here, we plot the first 350 Monte Carlo simulations along with the trajectory corresponding to the mean of the distribution (dashed line).

      We now wish to compute the expected squared impact distance from the star. This is called an “observation” of our system or an “observable” of interest.

      We define this observable as

      obs(sol, p) = abs2(sol[3, end] - 25)
      obs (generic function with 1 method)

      With the observable defined, we can compute the expected squared miss distance from our Monte Carlo simulation results as

      mean_ensemble = mean([obs(sol, p) for sol in ensemblesol])
      28.499831707748502

      Alternatively, we can use the Koopman() algorithm in SciMLExpectations.jl to compute this expectation much more efficiently as

      using SciMLExpectations
       gd = GenericDistribution(cor_dist)
       h(x, u, p) = u, [p[1]; x[1]]
       sm = SystemMap(prob, Tsit5(), callback = cbs)
      @@ -391,152 +391,152 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Looks pretty good! But, how long did it take? Let's benchmark.

      @time solve(opt_prob, optimizer)
      u: 3-element Vector{Float64}:
        -1.3718308930076236e-8
      @@ -554,52 +554,52 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      We now wish to minimize the same loss function as before, but introduce an inequality constraint such that the solution must have less than a 1% chance of colliding with the wall at $x=20$. This class of probabilistic constraints is called a chance constraint.

      To do this, we first introduce a new callback and solve the system using the previous optimal solution

      constraint_condition(u, t, integrator) = u[1] - constraint[1]
       function constraint_affect!(integrator)
      @@ -627,553 +627,553 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      That doesn't look good!

      We now need a second observable for the system. To compute a probability of impact, we use an indicator function for if a trajectory impacts the wall. In other words, this functions returns 1 if the trajectory hits the wall and 0 otherwise.

      function constraint_obs(sol, p)
           sol((constraint[1] - sol[1, 1]) / sol[2, 1])[3] <= constraint[2] ? one(sol[1, end]) :
      @@ -1220,552 +1220,552 @@ 

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/dev/showcase/pinngpu/index.html b/dev/showcase/pinngpu/index.html index 4d5ec52a1dc..29d359e8ce7 100644 --- a/dev/showcase/pinngpu/index.html +++ b/dev/showcase/pinngpu/index.html @@ -51,18 +51,18 @@ Dense(inner, inner, Lux.σ), Dense(inner, 1)) ps = Lux.setup(Random.default_rng(), chain)[1] -ps = ps |> ComponentArray

      ComponentVector{Float32}(layer_1 = (weight = Float32[0.14366294 0.1317404 -0.05585299; -0.13425063 -0.019459797 0.040910933; … ; -0.26999006 0.22705604 0.07979896; 0.2492138 0.096026234 0.4427908], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_2 = (weight = Float32[-0.08773258 0.12306935 … -0.027097197 0.15145467; 0.11256498 0.06038196 … 0.33870795 -0.3267955; … ; 0.24016993 0.08205853 … 0.3033077 0.19133534; -0.25750688 -0.15013285 … 0.060221236 -0.20149302], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = Float32[-0.03158505 -0.33470252 … -0.15070206 -0.108804345; 0.13533378 0.20211849 … -0.32656857 -0.020607514; … ; -0.049748126 0.08736394 … 0.34309542 0.0201607; 0.2053118 -0.18256788 … 0.009151701 -0.12668496], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_4 = (weight = Float32[-0.11852526 0.27506998 … 0.23429331 -0.22142304; -0.09297011 0.27991375 … -0.2846473 -0.07273727; … ; -0.1912308 0.20498516 … -0.19491398 -0.20236237; -0.26394963 -0.17735365 … 0.0039561316 0.31941748], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_5 = (weight = Float32[-0.17641757 0.050664347 … 0.33342656 -0.2742052], bias = Float32[0.0;;]))

      Step 4: Place it on the GPU.

      Just plop it on that sucker. We must ensure that our initial parameters for the neural network are on the GPU. If that is done, then the internal computations will all take place on the GPU. This is done by using the gpu function on the initial parameters, like:

      ps = ps |> gpu .|> Float64
      ComponentVector{Float64}(layer_1 = (weight = [0.1436629444360733 0.13174040615558624 -0.055852990597486496; -0.13425062596797943 -0.01945979706943035 0.040910933166742325; … ; -0.26999005675315857 0.22705604135990143 0.07979895919561386; 0.2492137998342514 0.0960262343287468 0.44279080629348755], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_2 = (weight = [-0.08773258328437805 0.12306935340166092 … -0.027097197249531746 0.15145467221736908; 0.11256498098373413 0.06038196012377739 … 0.33870795369148254 -0.3267954885959625; … ; 0.2401699274778366 0.08205852657556534 … 0.3033077120780945 0.19133533537387848; -0.2575068771839142 -0.15013284981250763 … 0.06022123619914055 -0.2014930248260498], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = [-0.031585048884153366 -0.3347025215625763 … -0.15070205926895142 -0.10880434513092041; 0.13533377647399902 0.20211848616600037 … -0.3265685737133026 -0.020607514306902885; … ; -0.04974812641739845 0.08736394345760345 … 0.34309542179107666 0.020160699263215065; 0.20531180500984192 -0.18256787955760956 … 0.009151700884103775 -0.12668496370315552], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_4 = (weight = [-0.11852525919675827 0.2750699818134308 … 0.23429331183433533 -0.22142304480075836; -0.092970110476017 0.2799137532711029 … -0.28464728593826294 -0.07273726910352707; … ; -0.19123080372810364 0.20498515665531158 … -0.19491398334503174 -0.20236237347126007; -0.2639496326446533 -0.1773536503314972 … 0.003956131637096405 0.31941747665405273], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_5 = (weight = [-0.17641757428646088 0.05066434666514397 … 0.3334265649318695 -0.27420520782470703], bias = [0.0;;]))

      Step 5: Discretize the PDE via a PINN Training Strategy

      strategy = GridTraining(0.05)
      +ps = ps |> ComponentArray
      ComponentVector{Float32}(layer_1 = (weight = Float32[-0.31617808 -0.3921037 -0.18227473; -0.41564474 0.23504238 -0.1706037; … ; -0.13163793 0.37315753 -0.41529518; 0.3999216 -0.27722833 0.28700396], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_2 = (weight = Float32[-0.18220164 0.118599094 … -0.32671517 0.1852477; -0.25128132 -0.121901646 … -0.33278072 0.10779426; … ; -0.3443845 -0.117905825 … -0.34635115 -0.25579; 0.34388936 0.24829172 … 0.024278957 -0.33954328], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = Float32[0.22687164 0.04679514 … 0.31096128 0.053515002; -0.07185305 0.2204412 … 0.20488733 -0.1407784; … ; 0.078017615 0.06694329 … -0.20048654 0.3055643; 0.19489144 0.28965104 … 0.013487791 -0.06321308], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_4 = (weight = Float32[-0.08118666 0.07674572 … 0.331075 -0.04009502; -0.19807473 0.18006104 … -0.20024504 0.10421441; … ; 0.22831824 0.14321688 … 0.1760507 0.25631267; 0.066266 -0.101036526 … 0.16456763 0.31325588], bias = Float32[0.0; 0.0; … ; 0.0; 0.0;;]), layer_5 = (weight = Float32[0.23935391 0.30278897 … 0.15770146 0.46347758], bias = Float32[0.0;;]))

      Step 4: Place it on the GPU.

      Just plop it on that sucker. We must ensure that our initial parameters for the neural network are on the GPU. If that is done, then the internal computations will all take place on the GPU. This is done by using the gpu function on the initial parameters, like:

      ps = ps |> gpu .|> Float64
      ComponentVector{Float64}(layer_1 = (weight = [-0.3161780834197998 -0.3921037018299103 -0.182274729013443; -0.41564473509788513 0.23504237830638885 -0.1706037074327469; … ; -0.13163793087005615 0.3731575310230255 -0.41529518365859985; 0.39992159605026245 -0.27722832560539246 0.2870039641857147], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_2 = (weight = [-0.18220163881778717 0.11859909445047379 … -0.3267151713371277 0.18524770438671112; -0.2512813210487366 -0.12190164625644684 … -0.33278071880340576 0.10779426246881485; … ; -0.34438449144363403 -0.11790582537651062 … -0.34635114669799805 -0.25578999519348145; 0.34388935565948486 0.2482917159795761 … 0.024278957396745682 -0.33954328298568726], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = [0.22687163949012756 0.04679514095187187 … 0.3109612762928009 0.0535150021314621; -0.07185304909944534 0.22044120728969574 … 0.20488733053207397 -0.14077839255332947; … ; 0.07801761478185654 0.06694328784942627 … -0.20048654079437256 0.3055643141269684; 0.19489143788814545 0.2896510362625122 … 0.013487790711224079 -0.06321308016777039], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_4 = (weight = [-0.08118665963411331 0.07674571871757507 … 0.3310750126838684 -0.040095020085573196; -0.19807472825050354 0.18006104230880737 … -0.20024503767490387 0.10421440750360489; … ; 0.2283182442188263 0.14321687817573547 … 0.17605069279670715 0.25631266832351685; 0.0662660002708435 -0.10103652626276016 … 0.16456763446331024 0.3132558763027191], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_5 = (weight = [0.23935391008853912 0.30278897285461426 … 0.15770146250724792 0.46347758173942566], bias = [0.0;;]))

      Step 5: Discretize the PDE via a PINN Training Strategy

      strategy = GridTraining(0.05)
       discretization = PhysicsInformedNN(chain,
                                          strategy,
                                          init_params = ps)
       prob = discretize(pde_system, discretization)
      OptimizationProblem. In-place: true
      -u0: ComponentVector{Float64}(layer_1 = (weight = [0.1436629444360733 0.13174040615558624 -0.055852990597486496; -0.13425062596797943 -0.01945979706943035 0.040910933166742325; … ; -0.26999005675315857 0.22705604135990143 0.07979895919561386; 0.2492137998342514 0.0960262343287468 0.44279080629348755], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_2 = (weight = [-0.08773258328437805 0.12306935340166092 … -0.027097197249531746 0.15145467221736908; 0.11256498098373413 0.06038196012377739 … 0.33870795369148254 -0.3267954885959625; … ; 0.2401699274778366 0.08205852657556534 … 0.3033077120780945 0.19133533537387848; -0.2575068771839142 -0.15013284981250763 … 0.06022123619914055 -0.2014930248260498], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = [-0.031585048884153366 -0.3347025215625763 … -0.15070205926895142 -0.10880434513092041; 0.13533377647399902 0.20211848616600037 … -0.3265685737133026 -0.020607514306902885; … ; -0.04974812641739845 0.08736394345760345 … 0.34309542179107666 0.020160699263215065; 0.20531180500984192 -0.18256787955760956 … 0.009151700884103775 -0.12668496370315552], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_4 = (weight = [-0.11852525919675827 0.2750699818134308 … 0.23429331183433533 -0.22142304480075836; -0.092970110476017 0.2799137532711029 … -0.28464728593826294 -0.07273726910352707; … ; -0.19123080372810364 0.20498515665531158 … -0.19491398334503174 -0.20236237347126007; -0.2639496326446533 -0.1773536503314972 … 0.003956131637096405 0.31941747665405273], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_5 = (weight = [-0.17641757428646088 0.05066434666514397 … 0.3334265649318695 -0.27420520782470703], bias = [0.0;;]))

      Step 6: Solve the Optimization Problem

      callback = function (p, l)
      +u0: ComponentVector{Float64}(layer_1 = (weight = [-0.3161780834197998 -0.3921037018299103 -0.182274729013443; -0.41564473509788513 0.23504237830638885 -0.1706037074327469; … ; -0.13163793087005615 0.3731575310230255 -0.41529518365859985; 0.39992159605026245 -0.27722832560539246 0.2870039641857147], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_2 = (weight = [-0.18220163881778717 0.11859909445047379 … -0.3267151713371277 0.18524770438671112; -0.2512813210487366 -0.12190164625644684 … -0.33278071880340576 0.10779426246881485; … ; -0.34438449144363403 -0.11790582537651062 … -0.34635114669799805 -0.25578999519348145; 0.34388935565948486 0.2482917159795761 … 0.024278957396745682 -0.33954328298568726], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_3 = (weight = [0.22687163949012756 0.04679514095187187 … 0.3109612762928009 0.0535150021314621; -0.07185304909944534 0.22044120728969574 … 0.20488733053207397 -0.14077839255332947; … ; 0.07801761478185654 0.06694328784942627 … -0.20048654079437256 0.3055643141269684; 0.19489143788814545 0.2896510362625122 … 0.013487790711224079 -0.06321308016777039], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_4 = (weight = [-0.08118665963411331 0.07674571871757507 … 0.3310750126838684 -0.040095020085573196; -0.19807472825050354 0.18006104230880737 … -0.20024503767490387 0.10421440750360489; … ; 0.2283182442188263 0.14321687817573547 … 0.17605069279670715 0.25631266832351685; 0.0662660002708435 -0.10103652626276016 … 0.16456763446331024 0.3132558763027191], bias = [0.0; 0.0; … ; 0.0; 0.0;;]), layer_5 = (weight = [0.23935391008853912 0.30278897285461426 … 0.15770146250724792 0.46347758173942566], bias = [0.0;;]))

      Step 6: Solve the Optimization Problem

      callback = function (p, l)
           println("Current loss is: $l")
           return false
       end
       
      -res = Optimization.solve(prob, Adam(0.01); callback = callback, maxiters = 2500);
      u: ComponentVector{Float64}(layer_1 = (weight = [-2.3611208536665433 1.0727067057586672 0.8007359659443994; -1.4108000658659732 -1.2471692374027132 -1.2833413499028457; … ; 1.3108840846017653 1.4282301427573605 1.560981783786771; 3.094758397278625 1.3992048527916812 1.3278026627647137], bias = [-1.1798377747967612; 1.28477961712476; … ; -1.7192292562498042; -0.19554819124092127;;]), layer_2 = (weight = [-0.28530576633226384 -2.0521885990226503 … 0.7727006619843142 0.8156376177656828; 0.31744493507784743 -2.5369374800611704 … 1.1346215395031807 0.3442991461292763; … ; 0.6820207384530441 -0.263433338916431 … 0.5075464161190212 0.33837856392552457; 0.11671517854531509 -1.7165797219089223 … 0.8793554289999905 0.5110096999785503], bias = [-0.2059443889620551; -0.3933581145024841; … ; 0.37618344094214073; 0.19694776993139415;;]), layer_3 = (weight = [1.0564491467070427 -1.1039026645238466 … -0.876463459743861 1.2631419634749754; 0.77453490732868 0.959505246358055 … -0.6821464725629954 0.791571785641922; … ; 1.3220823388027856 -1.7378322174147671 … -0.4494550952428516 1.9859147640905377; 1.7267273859855805 1.866156553444723 … -1.1226354465233919 0.7421208606079696], bias = [-0.27178684842039663; -0.5877523410221357; … ; -0.14214999047225288; -1.1674586414072246;;]), layer_4 = (weight = [0.2599150512550238 1.1069899836831119 … 1.0923427487503856 0.873645907546741; -3.697308257683669 -2.2515407094569877 … -2.1041774902555423 -1.8663971410171136; … ; -0.564770524228963 -0.8159575451625258 … -1.246339546883386 -1.4511489791125611; 0.09329570783366314 0.8150852562080474 … 0.9412952055463105 1.5027767764304762], bias = [-1.243381956225943; 2.2497209858760185; … ; 1.0397322977287375; -1.0720408762580593;;]), layer_5 = (weight = [-5.067691575030941 6.678361783411242 … 5.5659605576394675 -5.919161297624897], bias = [-0.24590343145850807;;]))

      We then use the remake function to rebuild the PDE problem to start a new optimization at the optimized parameters, and continue with a lower learning rate:

      prob = remake(prob, u0 = res.u)
      -res = Optimization.solve(prob, Adam(0.001); callback = callback, maxiters = 2500);
      u: ComponentVector{Float64}(layer_1 = (weight = [-2.3839271239836544 1.0027018467648423 0.8200508232809499; -1.3746453357498936 -1.244671930747618 -1.2352791539897199; … ; 1.3314550820493019 1.3134226610547566 1.3415426686291267; 2.879923256066002 1.3650307617420405 1.3730167456039473], bias = [-1.1731760476542707; 1.2942094017115724; … ; -1.7880076671092977; -0.16648584256898039;;]), layer_2 = (weight = [-0.2865566471711591 -2.2626391653775015 … 0.8046493753939777 0.8280802883753542; 0.3054079252248476 -2.5521859249449403 … 1.1253051496575754 0.33493697296074526; … ; 0.672240780342483 -0.27216690994305937 … 0.5077827946497561 0.3372494634407261; 0.11498291599877587 -1.7537035443715576 … 0.875414102310281 0.5096145967022013], bias = [-0.19338588961710348; -0.40265024849116077; … ; 0.3751616916317527; 0.1928602384457019;;]), layer_3 = (weight = [1.0164223191891153 -1.1106906697383059 … -0.9050450024105997 1.2528797218032333; 0.7515645311058761 0.9563849025570752 … -0.6791323745712503 0.789348948566292; … ; 1.4174920738399845 -1.7592041986902616 … -0.4288226283960248 2.044440767957345; 1.7134039630433466 1.8253646067948337 … -1.1266922840269005 0.7466038604983087], bias = [-0.25934715080882115; -0.5925984053753952; … ; -0.12825563492650557; -1.1607957717141302;;]), layer_4 = (weight = [0.24661338085793316 1.1256551998239173 … 1.102618697502544 0.8451423027878142; -3.7753306292850515 -2.4259517152346404 … -2.2385642165660706 -2.2207581334446336; … ; -0.5639388424657378 -0.8558320153242313 … -1.2863303065652445 -1.436286559157207; 0.08202824262643774 0.8255766290689897 … 0.9446425452511296 1.4558912476683201], bias = [-1.2526564972915097; 2.333244159298483; … ; 1.0242873614917212; -1.0866802063556982;;]), layer_5 = (weight = [-5.316820407765254 8.276363150019192 … 5.711551360972144 -6.177729999554198], bias = [-0.2729378257075692;;]))

      Step 7: Inspect the PINN's Solution

      Finally, we inspect the solution:

      phi = discretization.phi
      +res = Optimization.solve(prob, Adam(0.01); callback = callback, maxiters = 2500);
      u: ComponentVector{Float64}(layer_1 = (weight = [-1.52277004801135 -0.3294843262169713 -0.5017842443469388; -4.638745340190129 -0.4086296317304504 -0.4998314669408318; … ; 2.370935546012267 0.4976974774725561 0.1409877425198303; -1.384060824233844 -0.47085629979311316 -0.6732343621159045], bias = [1.5074145907518488; 1.1921834268237212; … ; 0.1458005879318607; 4.2442231763909914;;]), layer_2 = (weight = [0.5805067762774608 -1.595702806643934 … -0.5248273404486354 0.4426614338285085; -0.5780035979981911 2.1660316988139847 … -0.13538028819038814 -0.3849549456379454; … ; -0.6823807460038588 -1.7089385596759088 … -0.1650452215596166 -0.3440587979833576; -0.23479502121829118 2.4397085586032325 … 0.054297424960224966 -1.1846863068140152], bias = [0.4236079089655558; 0.039942341870372; … ; 0.049683217337859575; -0.17381080396888185;;]), layer_3 = (weight = [-0.7515798959740055 0.5847303831853568 … 0.6613616803009265 1.4219267935663324; -1.5159685975751267 1.4631073974419775 … 0.3837197232198147 2.4843925244434457; … ; -1.0439508234670618 0.6640232532520371 … 0.11331394347081583 1.9211200969437157; 1.0212109729351893 -0.4540029828083911 … -0.11718139330381713 -1.480255192634305], bias = [-0.29154263405505815; -0.5654634071410065; … ; -0.4263403390958641; 0.349551566373654;;]), layer_4 = (weight = [-0.899561387739085 -1.8386030892034768 … -0.7829496415912722 1.9116777986099458; -1.1098538642664149 -1.4714977270712934 … -1.3662461447271266 1.9501459429412094; … ; -0.7315864839442003 -1.9644966594923772 … -1.0779349606942388 1.9460106514927578; -0.8356170494760036 -1.7332608596317207 … -0.9784395162764131 1.977755277070237], bias = [1.1339996602792959; 1.1018111068768233; … ; 0.9029093557998198; 1.0373855408902686;;]), layer_5 = (weight = [4.929673656398715 5.2871117056927215 … 4.659770902168718 5.846111925118296], bias = [-1.429063891919365;;]))

      We then use the remake function to rebuild the PDE problem to start a new optimization at the optimized parameters, and continue with a lower learning rate:

      prob = remake(prob, u0 = res.u)
      +res = Optimization.solve(prob, Adam(0.001); callback = callback, maxiters = 2500);
      u: ComponentVector{Float64}(layer_1 = (weight = [-1.5583071400333748 -0.31913903027578366 -0.494382180844884; -4.54684407001516 -0.43103542647115667 -0.5096616408107474; … ; 2.3625900346367916 0.482840792024997 0.15435247308007635; -1.3836544106629174 -0.48586694867534547 -0.6944199470702052], bias = [1.5004441173329999; 1.2136664571176519; … ; 0.16900865111672372; 4.249271753691538;;]), layer_2 = (weight = [0.5592743302131582 -1.5357436659908776 … -0.5221066212739106 0.4251506627904489; -0.5319662370305833 2.4842504939011527 … -0.12370577531630216 -0.351123093160157; … ; -0.6027784927596674 -2.1381932851652277 … -0.10015375844492153 -0.16819049690785629; -0.2406611775080439 2.205450888376366 … 0.06345658360949297 -1.1599911253827573], bias = [0.4263604027077998; 0.05005979910911308; … ; 0.10381336692627602; -0.16694011305328235;;]), layer_3 = (weight = [-0.7676943775451408 0.5800616908940515 … 0.653504392488281 1.40461967172209; -1.5165192144380089 1.5317292788312147 … 0.4446860271065466 2.5999669613648857; … ; -1.0527531944352855 0.6554157044144701 … 0.10441884762180192 1.897692412879776; 1.0275995588481368 -0.44797067594921286 … -0.11341032092483137 -1.4712321450161776], bias = [-0.3028135209863708; -0.5572224264155465; … ; -0.4321409228743736; 0.3548506688102517;;]), layer_4 = (weight = [-0.8030685996510523 -1.8974116706615838 … -0.6885635848907508 1.953785697184433; -1.0976939182464027 -1.559086287330587 … -1.3554043955902662 1.9393128187314685; … ; -0.7134328141732991 -2.036618383315411 … -1.0610994214202376 1.9275174782739606; -0.8238899652289758 -1.847485179926339 … -0.9699308127633239 1.9715550458487003], bias = [1.1804297363189495; 1.089071079691602; … ; 0.8833811102225365; 1.0273525257572458;;]), layer_5 = (weight = [5.06642836977785 5.480969238032791 … 4.886422443967772 6.060013176775849], bias = [-1.4969311137347632;;]))

      Step 7: Inspect the PINN's Solution

      Finally, we inspect the solution:

      phi = discretization.phi
       ts, xs, ys = [infimum(d.domain):0.1:supremum(d.domain) for d in domains]
       u_real = [analytic_sol_func(t, x, y) for t in ts for x in xs for y in ys]
       u_predict = [first(Array(phi(gpu([t, x, y]), res.u))) for t in ts for x in xs for y in ys]
      @@ -87,4 +87,4 @@
           gif(anim, "3pde.gif", fps = 10)
       end
       
      -plot_(res)

      3pde

      +plot_(res)

      3pde

      diff --git a/dev/showcase/showcase/index.html b/dev/showcase/showcase/index.html index 9b425d38897..d3bc9ab31fb 100644 --- a/dev/showcase/showcase/index.html +++ b/dev/showcase/showcase/index.html @@ -3,4 +3,4 @@ function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-90474609-3', {'page_path': location.pathname + location.search + location.hash}); -

      The SciML Showcase

      The SciML Showcase is a display of some cool things that can be done by connecting SciML software.

      Note

      The SciML Showcase is not meant to be training/tutorials, but inspirational demonstrations! If you're looking for simple examples to get started with, check out the getting started section.

      Want to see some cool things that you can do with SciML? Check out the following:

      +

      The SciML Showcase

      The SciML Showcase is a display of some cool things that can be done by connecting SciML software.

      Note

      The SciML Showcase is not meant to be training/tutorials, but inspirational demonstrations! If you're looking for simple examples to get started with, check out the getting started section.

      Want to see some cool things that you can do with SciML? Check out the following:

      diff --git a/dev/showcase/symbolic_analysis/index.html b/dev/showcase/symbolic_analysis/index.html index 1666963c516..791e7cfdc22 100644 --- a/dev/showcase/symbolic_analysis/index.html +++ b/dev/showcase/symbolic_analysis/index.html @@ -30,57 +30,57 @@ plot(sol, vars = states(traced_sys))

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Explanation

      Attempting to Solve the Equation

      In this tutorial, we will look at the pendulum system:

      \[\begin{aligned} x^\prime &= v_x\\ v_x^\prime &= Tx\\ @@ -135,57 +135,57 @@

      Explanat plot(sol, vars = states(traced_sys))

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      Note that plotting using states(traced_sys) is done so that any variables which are symbolically eliminated, or any variable reordering done for enhanced parallelism/performance, still show up in the resulting plot and the plot is shown in the same order as the original numerical code.

      Note that we can even go a bit further. If we use the ODAEProblem constructor, we can remove the algebraic equations from the states of the system and fully transform the index-3 DAE into an index-0 ODE, which can be solved via an explicit Runge-Kutta method:

      traced_sys = modelingtoolkitize(pendulum_prob)
       pendulum_sys = structural_simplify(dae_index_lowering(traced_sys))
       prob = ODAEProblem(pendulum_sys, Pair[], tspan)
      @@ -193,57 +193,57 @@ 

      Explanat plot(sol, vars = states(traced_sys))

      - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

      And there you go: this has transformed the model from being too hard to solve with implicit DAE solvers, to something that is easily solved with explicit Runge-Kutta methods for non-stiff equations.

      Parameter Identifiability in ODE Models

      Ordinary differential equations are commonly used for modeling real-world processes. The problem of parameter identifiability is one of the key design challenges for mathematical models. A parameter is said to be identifiable if one can recover its value from experimental data. Structural identifiability is a theoretical property of a model that answers this question. In this tutorial, we will show how to use StructuralIdentifiability.jl with ModelingToolkit.jl to assess identifiability of parameters in ODE models. The theory behind StructuralIdentifiability.jl is presented in paper [4].

      We will start by illustrating local identifiability in which a parameter is known up to finitely many values, and then proceed to determining global identifiability, that is, which parameters can be identified uniquely.

      To install StructuralIdentifiability.jl, simply run

      using Pkg
       Pkg.add("StructuralIdentifiability")

      The package has a standalone data structure for ordinary differential equations, but is also compatible with ODESystem type from ModelingToolkit.jl.

      Local Identifiability

      Input System

      We will consider the following model:

      \[\begin{cases} \frac{d\,x_4}{d\,t} = - \frac{k_5 x_4}{k_6 + x_4},\\ @@ -341,4 +341,4 @@

      Explanat funcs_to_check = to_check, p = 0.9) # Dict{Num, Symbol} with 2 entries: # b => :globally -# c => :globally

      Both parameters b, c are globally identifiable with probability 0.9 in this case.

      +# c => :globally

      Both parameters b, c are globally identifiable with probability 0.9 in this case.