Skip to content

Commit

Permalink
release v1.0.0
Browse files Browse the repository at this point in the history
Release version 1.0.0
  • Loading branch information
n-claes authored Nov 30, 2020
2 parents 2d36897 + bf2b386 commit 1167d3a
Show file tree
Hide file tree
Showing 35 changed files with 3,481 additions and 419 deletions.
42 changes: 42 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
Hi, thanks for the pull request! To make sure everything stays nice and consistent, here is a default template which you can use.
It also includes a checklist of small things that are usually forgotten or overlooked. You may remove parts that are not applicable to the current PR
(including these sentences).

Cheers,

Legolas dev team

## PR description

> fill or delete
## New features

> fill or delete
## Bugfixes

> fill or delete
## Checklist

**Source code stuff**
- [ ] everything is nicely formatted using [Black-like code style](https://black.readthedocs.io/en/stable/the_black_code_style.html)
- [ ] use-statements should use `use mod_xxx, only:` as much as possible
- [ ] things that can go in a separate module, should go in a separate module
- [ ] code additions|changes are also added|changed in the docstrings

**Testing stuff**
- [ ] all tests pass
- [ ] in case of new features, new tests are added

**Website stuff**
- [ ] relevant pages on the website are edited, if relevant
- [ ] on the edited pages, the `last_modified_at` frontmatter key is updated
- [ ] all links render as they should, check through a local `bundle exec jekyll serve` in the `docs` directory
- [ ] additions to the parfile are also added to `parameters_file.md`

**Release stuff**
(only if this is a merge-in-master release)
- [ ] bump version number
- [ ] changelog pages on the website are updated
23 changes: 22 additions & 1 deletion .github/workflows/legolas_core.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ env:
FC: /usr/bin/gfortran-9
PFUNIT_DIR: /home/runner/work/legolas/legolas/tests/core_tests/pFUnit/build/installed
LEGOLASDIR: /home/runner/work/legolas/legolas
ARPACK_ROOT: /home/runner/work/legolas/legolas/tests/arpack-ng

jobs:
tests:
Expand Down Expand Up @@ -48,7 +49,27 @@ jobs:
make -j 2 tests
make -j 2 install
- name: Compilation
- name: Cache ARPACK
id: arpack-cache
uses: actions/cache@v1
with:
path: tests/arpack-ng/
key: ${{ runner.os }}-arpackv2

- name: Build ARPACK
if: steps.arpack-cache.outputs.cache-hit != 'true'
run: |
cd tests
git clone https://github.com/opencollab/arpack-ng.git
cd arpack-ng
mkdir build
mkdir installed
cd build
cmake -DEXAMPLES=OFF -DMPI=OFF -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=../installed ..
make -j 2
sudo make -j 2 install
- name: Build Legolas
run: |
sh setup_tools/buildlegolas.sh
cd tests/core_tests
Expand Down
26 changes: 25 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ if (${Coverage})
set (CMAKE_Fortran_FLAGS "--coverage -o0 -g")
else()
set(CMAKE_Fortran_FLAGS "-fcheck=all -fbounds-check -Wall \
-Wextra -Wconversion -pedantic -fbacktrace")
-Wextra -Wconversion -pedantic -fbacktrace -cpp")
endif()

if (DEFINED ENV{LEGOLASDIR})
Expand Down Expand Up @@ -43,6 +43,30 @@ file(MAKE_DIRECTORY ${OUTPUT})

include(${setup_tools}/findBLAS.cmake)
include(${setup_tools}/findLAPACK.cmake)
# we don't use SCALAPACK or MUMPS at the moment
#include(${setup_tools}/findSCALAPACK.cmake)
#include(${setup_tools}/findMUMPS.cmake)
include(${setup_tools}/findARPACK.cmake)

# for some reason TRUE and FALSE are not expanded to 1 and 0 in the preprocessor,
# so we explicitly do it here
set(_ARPACK_FOUND 0)
set(_PARPACK_FOUND 0)
if (${ARPACK_FOUND})
set(_ARPACK_FOUND 1)
endif()
if (${PARPACK_FOUND})
set(_PARPACK_FOUND 1)
endif()

# add preprocessor directives for optional compilation of submodules,
# depending on packages found
add_definitions(
# -D _SCALAPACK_FOUND=${SCALAPACK_FOUND}
# -D _MUMPS_FOUND=${MUMPS_FOUND}
-D _ARPACK_FOUND=${_ARPACK_FOUND}
-D _PARPACK_FOUND=${_PARPACK_FOUND}
)

# name of library
set(LEGOLASLIB lego)
Expand Down
2 changes: 2 additions & 0 deletions docs/_data/navigation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ leftcontents:
url: /content/general/parameter_file/
- title: "Equilibria"
url: /content/general/equilibria/
- title: "Solvers"
url: /content/general/solvers/
- title: "Running your own setup"
url: /content/general/own_setup/
- title: Data-analysis with Pylbo
Expand Down
11 changes: 11 additions & 0 deletions docs/content/general/parameter_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,17 @@ parameter studies, to prevent having to recompile the submodule over and over ag
| dropoff_edge_dist | real | distance between grid edge and the smoothened profile center | 0.05 |
| dropoff_width | real | sets the width over which the profile is smoothened out | 0.1 |

## solvelist
This namelist includes all solver-related variables. For more information, see [Solvers](../../general/solvers)

| Parameter | Type | Description | Default value |
| :--- | :---: | :---- | :---: |
| solver | string | which solver to use | `"QR-invert"` |
| arpack_mode | string | the mode for ARPACK, only used if `solver="arnoldi"` | `"standard"` |
| number_of_eigenvalues | int | number of eigenvalues to calculate, only used if `solver="arnoldi"` | 10 |
| which eigenvalues | string | which eigenvalues to calculate, only used if `solver="arnoldi"` | `"LM"` |
| maxiter | int | the maximum number of iterations the Arnoldi solver may take, only used if `solver="arnoldi"` | 10N |
| sigma | complex | sigma-value around which to do shift-invert, only for `arpack_mode="shift-invert"` | **NaN** |

## unitslist
This namelist includes all units-related variables.
Expand Down
202 changes: 202 additions & 0 deletions docs/content/general/solvers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
---
title: Solvers
layout: single
classes: wide
sidebar:
nav: "leftcontents"
toc: true
toc_icon: "chevron-circle-down"
last_modified_at: 2020-11-27
---

Legolas has interfaces implemented to various BLAS, LAPACK and ARPACK routines.
Below is an overview of which routines you can call, which problems are supported and how
you can configure the parfile to select the solver you want.
Note that in (most) cases we have a general eigenvalue problem of the form

$$ A\mathbf{x} = \omega B\mathbf{x} $$

where $$A$$ is a non-symmetric and non-Hermitian complex matrix. The $$B$$-matrix is
symmetric, real and positive definite. Both matrices are block-tridiagonal, meaning
they are very sparse.


## QR-invert
{% capture pros %}
**Pros:**
- Fast
- Calculates complete spectrum and eigenfunctions
{% endcapture %}
<div class="notice--success">
{{ pros | markdownify }}
</div>

{% capture cons %}
**Cons:**
- Higher resolution needed to resolve some modes
- Datfiles become very large at high resolution if eigenfunctions are included
{% endcapture %}
<div class="notice--danger">
{{ cons | markdownify }}
</div>

This is the default solver that Legolas uses, which relies on an inversion of the B-matrix to write
the eigenvalue problem in the form

$$ B^{-1}A\mathbf{x} = \omega\mathbf{x}. $$

The LAPACK routine `dgetrf` is used to calculate the LU factorisation of B, followed by a call
to `dgetri` which uses that factorisation to invert the B-matrix.
Finally a call to LAPACK's `zgeev` is made which returns all eigenvalues and optionally
the right eigenvectors.

Note that the B-matrix is always nicely conditioned, such that inverting it does not yield problems.
This solver can be explicitly specified in the `solvelist` through
```fortran
&solvelist
solver = "QR-invert"
/
```
and is called by default if no `solvelist` is supplied.

## QZ-direct
{% capture pros %}
**Pros:**
- No inversion of the B-matrix needed
- Calculates complete spectrum
{% endcapture %}
<div class="notice--success">
{{ pros | markdownify }}
</div>

{% capture cons %}
**Cons:**
- Noticably slower than QR-invert, especially for large matrices
- Higher resolution needed to resolve some modes
- Returns _generalised_ eigenvectors instead of standard ones
{% endcapture %}
<div class="notice--danger">
{{ cons | markdownify }}
</div>

This is a variant of the QR-invert solver, with as main difference that the B-matrix is not inverted
such that the eigenvalue problem is kept in its general form.
The LAPACK routine `zggev` is used to solve the general eigenvalue problem, returning all
eigenvalues and (optionally) the _generalised_ right eigenvectors.

This solver can be specified in the `solvelist` through
```fortran
&solvelist
solver = "QZ-direct"
/
```

## ARPACK Reverse Communication Interface
Legolas has various solvers implemented which interface with the ARPACK package to
solve the eigenvalue problem. ARPACK is a reverse communication interface specifically designed to
solve large-scale, sparse matrix eigenvalue problems, and is hence perfectly suited for Legolas.
ARPACK can run in various modes, most notably a shift-invert method to probe
various parts of the spectrum, only returning eigenvalues of regions you are interested in.

The main difference with the LAPACK solvers is that one can query for only a number of eigenvalues
instead of the full spectrum. This is essentially the Fortran analog of SciPy's
[`eigs`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.sparse.linalg.eigs.html)
method in Python, which is a wrapper to ARPACK in itself.

When using Arnoldi-based solvers the solvelist can be set as follows:
```fortran
&solvelist
solver = "arnoldi"
arpack_mode = "standard" | "general" | "shift-invert"
number_of_eigenvalues = 100
which_eigenvalues = "LM" | "SM" | "LR" | "SR" | "LI" | "SI"
maxiter = 2500
/
```

- `arpack_mode`: which mode to use, see the subsections below.
- `number_of_eigenvalues`: this is an integer denoting the $$k$$ eigenvalues to be computed.
Note that this number (obviously) has to be positive and should be smaller than the dimension of
the eigenvalue problem (that is, `matrix_gridpts`).
- `which_eigenvalues`: denotes the type of eigenvalues that should be calculated
- `"LM"`: eigenvalues with largest magnitude
- `"SM"`: eigenvalues with smallest magnitude
- `"LR"`: eigenvalues with largest real part
- `"SR"`: eigenvalues with smallest real part
- `"LI"`: eigenvalues with largest imaginary part
- `"SI"`: eigenvalues with smallest imaginary part
- `maxiter`: integer which limits the maximum iterations the Arnoldi solver may take when
doing the reverse communication. This defaults to 10 times the size of the eigenvalue problem,
so for 100 gridpoints `maxiter` will be 10 x 100 x 16 = 16000, which is usually more than sufficient.
However, sometimes (especially for small eigenvalues) this may not be enough,
in which case you can increase this number.

If the iterative solver reaches `maxiter`, only a number $$j < k$$ eigenvalues will be converged.
Legolas will notify you how many are converged, and you can still plot these $$j$$ eigenvalues and their eigenfunctions.

Note that ARPACK is better at finding large eigenvalues. We recommend using the shift-invert mode
if you want better performance for smaller eigenvalues. Ideally a combination of both is used, where
one first solves for all eigenvalues using QR-invert or the standard/general Arnoldi solver, locate
spectral regions of interest, and then follow-up with shift-invert at those locations.

### Standard / general mode
{% capture pros %}
**Pros:**
- Calculates only specific eigenvalues and eigenvectors
- Reduced datfile size, only eigenvectors for requested eigenvalues are calculated
{% endcapture %}
<div class="notice--success">
{{ pros | markdownify }}
</div>

{% capture cons %}
**Cons:**
- Fast for the largest eigenvalues (`"LM", "LR", "LI"`), significantly slower for the smaller ones
{% endcapture %}
<div class="notice--danger">
{{ cons | markdownify }}
</div>

_Standard mode_: set `arpack_mode = "standard"`.
This is analogeous to the QR algorithm, inverts the B-matrix and passes the eigenvalue
problem in standard form to the iterative solver.

_General mode_: set `arpack_mode = "general"`.
Solves the eigenvalue problem in its general form, however an inversion of the
B-matrix is still needed. The main difference with the standard mode is that $$B\textbf{x}$$ is also
used during the iteration.

### Shift-invert
{% capture pros %}
**Pros:**
- Ability to probe specific parts of the spectrum by shifting $$\sigma$$
- Better performance for small eigenvalues
{% endcapture %}
<div class="notice--success">
{{ pros | markdownify }}
</div>

{% capture cons %}
**Cons:**
- Method needs an operator $$[A - \sigma B]^{-1}B$$, so the inverse of a complex matrix
{% endcapture %}
<div class="notice--danger">
{{ cons | markdownify }}
</div>
Running ARPACK in shift-invert mode allows one to set a certain shift $$\sigma$$ and calculate
the shifted eigenvalues. Note that for this mode, the setting `which_eigenvalues` in the parfile
refers to the shifted eigenvalues

$$ \dfrac{1}{\omega_i - \sigma} $$

The value of $$\sigma$$ can be specified by adding it to the solvelist, like so
```fortran
&solvelist
sigma = (1.0d0, 0.05d0)
/
```
and should be a complex tuple (standard Fortran notation for complex numbers).
Note that we need the operator $$[A - \sigma B]^{-1}B$$, which implies that $$\sigma$$ can not be zero
in our case, because the matrix A can be singular (no magnetic field, for example) which removes the
guarantee that the system is properly conditioned.

Loading

0 comments on commit 1167d3a

Please sign in to comment.