Code Monkey home page Code Monkey logo

pydgq's Introduction

pydgq

Python dG(q): Solve ordinary differential equation (ODE) systems using the time-discontinuous Galerkin method.

Lorenz attractor, dG(2)

Introduction

This is a Cython-accelerated library that integrates initial value problems (IVPs) of first-order ordinary differential equation (ODE) systems of the form u'(t) = f(u, t).

The main feature of the library is dG(q), i.e. the time-discontinuous Galerkin method using a Lobatto basis (a.k.a. hierarchical polynomial basis). Some classical explicit and implicit integrators (RK4, RK3, RK2, FE, SE, IMR, BE) are also provided, mainly for convenience.

Time-discontinuous Galerkin is a very accurate implicit method that often allows using a rather large timestep. Due to its Galerkin nature, it also models the behavior of the solution inside the timestep (although best accuracy is obtained at the endpoint of the timestep).

Arbitrary polynomial degrees q are supported, but often best results are obtained for q = 1 (dG(1)) or q = 2 (dG(2)). (The example image above has been computed using dG(2). Note the discontinuities at timestep boundaries.)

The focus of this library is on arbitrary nonlinear problems. All implicit methods are implemented using fixed-point (Banach/Picard) iteration, relying on the Picard-Lindelöf theorem (which itself relies on the Banach fixed point theorem).

For supplying the user code implementing the right-hand side (RHS) f(u, t) for a given problem, both Python and Cython interfaces are provided.

For material on the algorithms used, see the user manual.

Usage summary

The user is expected to provide a custom kernel, which computes the RHS f(u, t) for the specific problem to be solved.

The problem is solved by instantiating this custom kernel, and passing the instance to the ivp() function of the pydgq.solver.odesolve module (along with solver options).

Code examples are provided the test subdirectory. For compiling the Cython example, the test subdirectory contains its own setup.py that is only used for this purpose.

Installation

From PyPI

Install as user:

pip install pydgq --user

Install as admin:

sudo pip install pydgq

From GitHub

As user:

git clone https://github.com/Technologicat/pydgq.git
cd pydgq
python setup.py install --user

As admin, change the last command to

sudo python setup.py install

Software architecture

The design of pydgq is based on two main class hierarchies, consisting of Cython extension types (cdef classes):

  • IntegratorBase: interface class for integrator algorithms
    • ExplicitIntegrator: base class for explicit methods, which are implemented in pydgq.solver.explicit:
      • RK4: fourth-order Runge-Kutta
      • RK3: Kutta's third-order method
      • RK2: parametric second-order Runge-Kutta
      • FE: forward Euler (explicit Euler)
      • SE: symplectic Euler, for 2nd-order systems reduced to a twice larger 1st-order system
    • ImplicitIntegrator: base class for implicit methods, which are implemented in pydgq.solver.implicit:
      • IMR: implicit midpoint rule
      • BE: backward Euler (implicit Euler)
      • GalerkinIntegrator: base class for Galerkin methods using a Lobatto basis, which are implemented in pydgq.solver.galerkin:
        • DG: discontinuous Galerkin
        • CG: continuous Galerkin
  • KernelBase: interface class for RHS kernels
    • CythonKernel: base class for kernels implemented in Cython, see pydgq.solver.builtin_kernels for examples (and the test subdirectory for their usage):
      • Linear1stOrderKernel: w' = M w
      • Linear1stOrderKernelWithMassMatrix: A w' = M w
      • Linear2ndOrderKernel: u'' = M0 u + M1 u'
        • solved as a twice larger 1st-order system, by defining v := u', thus obtaining u' = v and v' = M0 u + M1 v
        • the DOF vector is defined as w := (u1, v1, u2, v2, ..., um, vm), where m is the number of DOFs of the original 2nd-order system.
      • Linear2ndOrderKernelWithMassMatrix: M2 u'' = M0 u + M1 u'
        • solved as u' = v and M2 v' = M0 u + M1 v similarly as above
      • CythonKernel acts as a base class for your own Cython-based kernels
    • PythonKernel: base class for kernels implemented in Python

The ivp() function of pydgq.solver.odesolve understands the IntegratorBase and KernelBase interfaces, and acts as the driver routine.

Aliases to primitive data types (to allow precision switching at compile time) are defined in pydgq.solver.types: Python (import), Cython (cimport). The Python-accessible names point to the appropriate NumPy symbols. RTYPE is real, ZTYPE is complex, and DTYPE is an alias representing the problem data type. The corresponding Cython-accessible datatypes have the _t suffix (RTYPE_t, ZTYPE_t, DTYPE_t).

Currently, DTYPE is real, but it is kept conceptually separate from RTYPE so that complex-valued problems can be later supported, if necessary (this requires some changes in the code, especially any calls to dgesv).

Linear and nonlinear problems

The built-in kernels concentrate on linear problems, because for this specific class of problems, it is possible to provide generic pre-built kernels. The provided set of four kernels attempts to cover the most common use cases, especially the case of small-amplitude vibration problems in mechanics, which are of the second order in time, and typically have all three matrices M0, M1 and M2.

The main focus of the library, however, is on solving arbitrary nonlinear problems, and thus no algorithms specific to linear problems have been used. This makes the solver severely suboptimal for linear problems, but significantly increases flexibility.

Be aware that due to this choice of approach, the usual stability results for integrators for linear problems do not apply. For example, BE is no longer stable at any timestep size, because for large enough dt, contractivity in the Banach/Picard iteration is lost. (The standard results are based on classical von Neumann stability analysis; without modifications, these arguments are not applicable to the algorithm based on Banach/Picard iteration.)

Lobatto basis functions / precalculation

The numerical evaluation of the Lobatto basis functions is numerically highly sensitive to catastrophic cancellation (see the user manual); IEEE-754 double precision is insufficient to compute the intermediate results. To work around this issue, the basis functions are pre-evaluated once, by the module pydgq.utils.precalc, using higher precision in software (via sympy.mpmath).

The precalculation can be run again by running the module as the main program, e.g. python -m pydgq.utils.precalc. The module has some command-line options; use the standard --help option to see them.

The precalc module stores the values of the basis functions (at quadrature points and at visualization points, both on the reference element [-1,1]) into a binary data file called pydgq_data.bin, by pickling the computed np.ndarray objects.

A data file with default precalc settings, that works at least with the x86_64 architecture, is installed by setup.py as pydgq/pydgq_data.bin (for the code to access via pkg_resources).

At install time, setup.py expects to find, in the source tree, the data file to be installed as pydgq/pydgq_data_VV.bin, where VV is either 27 or 34, depending on whether setup.py is running under Python 2.7 or Python 3. It will create a symlink pydgq/pydgq_data.bin pointing the correct version of the file, install the package, and then delete the symlink. When generating an sdist, the distribution will contain both of the actual data files, and no symlink.

The data files provided with the sources have been generated using the default settings of pydgq.utils.precalc (q = 10, nx = 101).

When running the solver, to use Galerkin methods, pydgq.solver.galerkin.init() must be called before calling pydgq.solver.odesolve.ivp().

Data file location

During pydgq.solver.galerkin.init(), the solver attempts to load pydgq_data.bin from these locations, in this order:

  1. ./pydgq_data.bin (local override),
  2. ~/.config/pydgq/pydgq_data.bin (user override),
  3. pydgq package, via pkg_resources (likely installed in /usr/local/lib/python3.4/dist-packages/pydgq... or similar).

If all three steps fail, IOError is raised.

Dependencies

License

BSD. Copyright 2016-2017 Juha Jeronen and University of Jyväskylä.

Acknowledgement

This work was financially supported by the Jenny and Antti Wihuri Foundation.

pydgq's People

Contributors

technologicat avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

pydgq's Issues

Add convergence tolerance setting

Currently, pydgq considers an iteration complete once all bits of the double-precision 64-bit float agree.

While this is useful for very sensitive equations (e.g. those in undamped vibration problems), for other real-world use a convergence tolerance setting would be useful.

  • Maybe options for absolute and relative.
  • Maybe default to 1e-6.
  • Let the user specify 0 to use the old behavior.

Add Newton-Raphson iteration

Currently, pydgq only supports Picard (fixed-point) iteration in all implicit solvers (including the Galerkin solvers). This is the simplest thing that works, but the convergence rate is linear (constant number of added correct bits per iteration).

Newton-Raphson would be a useful option to have for improving performance, because it converges quadratically (number of correct bits doubled per iteration).

  • To make it easy to use, approximate the Jacobian with finite differences, to avoid the need for the user to provide a function for the Jacobian to be able to use Newton iteration.
  • Allow the user to optionally provide such a function, if they prefer.
  • The Right Thing for producing a Jacobian automatically is (forward-mode) automatic differentiation, but in a low-level language such as Cython this is not easy (if at all possible) to make conform to the same interface as standard double-precision floats.
  • Maybe optionally also allow a mixed scheme which starts by a user-configurable number of Picard iterations, then switches to Newton. This can sometimes help convergence (if the final value from the previous timestep is outside the basin of attraction of the Newton method; Picard is not that sensitive to the initial value).

pydgq_data.bin not found after pip3 install

When pydgq is installed under Python 3.6, both data files pydgq_data_27.bin (old, for Python 2.7) and pydgq_data_34.bin (compatible with 3.4 and later, tested also in 3.6) get installed under their own names, but the symlink (that should point to the correct version) fails to install.

Solution: drop Python 2.7 support in the next release, so we need only one universal data file for Python 3.x.

Workaround: meanwhile, go to your site-packages/pydgq in a terminal, and install the symlink manually. Assuming pydgq was installed with pip3 install pydgq --user under Python 3.6, the full path is ~/.local/lib/python3.6/site-packages/pydgq. Once there, ln -s pydgq_data_34.bin pydgq_data.bin. Or if using Windows, just copy the file.

Update contact email

The contact email in setup.py is outdated. PyPI uses it to provide the link to email the maintainer. Update it for the next release.

Drop support for Python 2.7

Python 2.7 will be out of support January 1, 2020.

Dropping support for it allows a simple solution for #1.

A possibly incomplete list of things to remember:

  • Update metadata in setup.py.
  • Update GitHub tags.
  • Update hashbangs.
  • Drop runtests2.sh.
  • Consider migrating runtests3.sh into a runtests.py. Shell? Where we're going, we need no shell.
    • Unpythonic has a template for this.
    • Or could just use unittest from the stdlib.
    • pytest would be even nicer, but introduces a dependency.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.