Skip to content

Conversation

@yguclu
Copy link
Member

@yguclu yguclu commented Dec 25, 2025

No description provided.

yguclu and others added 30 commits October 14, 2019 19:12
In addition, if 'EvalQuadratureMapping' is called on a vector function
space of 'undefined' kind, we create a temporary scalar function space
of 'H1' kind and assume that all vector components belong to this space.
Clean up installation procedure with pip
This is not needed anymore, because the code that is generated for the
non-periodic case also works for a periodic domain. Moreover, the old
special code was inefficient, not well tested, and it was not working
if the spline degree was not the same along all directions.

To verify that the periodic case is treated properly, a unit test is added:
2D Poisson's equation on a unit circle, with periodic BCs along the theta
direction, homogeneous Dirichlet BC at r=1, and different spline degrees
along r and theta.
Remove obsolete code generation for periodic case.
- This function computes the correct metric determinant to be used for
  integration over a boundary manifold;
- With this function we can correctly assemble boundary integrals also
  in the case where the expression does not contain a NormalVector or
  TangentVector.

TODO: fix calculation of metric determinant in function
      ComputeNormalVector, using the same formula.
So far only 2D Poisson equation on square domain (identity mapping).
Tests only pass if inhomogeneous Neumann BCs are along direction 0,
and fail otherwise. Identified bug in 'compute_normal_vector'.
The normal vector is identified with a dual basis vector of the
coordinate transformation (reversed if needed). Hence it is computed
as a row of the inverse of the Jacobian matrix of the mapping. This
procedure is simple and general, and it applies to domains with any
number of dimensions.

TODO: verify if a normalization is required.
A unique function is now used to define unit tests for the 2D Poisson
equation in a unit square. It handles any combination of homogeneous
and inhomogeneous boundary conditions of Dirichlet or Neumann type.
campospinto and others added 27 commits May 9, 2025 17:19
…493)

Implement `M.dot(u).inner(v)`, or `(M @ u).inner(v)`, without creating a
temporary vector. The result of the dot product is written to a local
work vector stored in the `LinearOperator` object. This work vector is
then used to compute the inner product with the vector `v`. The
subclasses do not need to override this method, unless a more efficient
implementation which avoids writing to the work vector altogether
(reducing memory pressure) is needed.

A unit test is added: function `test_dot_inner` in file
psydac/linalg/tests/test_linalg.py.

Additionally, the helper function `get_StencilVectorSpace` defined in
psydac/linalg/tests/test_linalg.py (only used in the same file and in
test_matrix_free.py) has a new signature and now works in any number of
dimensions.

Fixes #491.
This PR changes the code generation involved in the `discretize`
function to avoid calculating unnecessary derivatives. This allows for
using constant spline (degree 0) discretizations, for which we have to
make a special case in the calculation of ghost regions in
`psydac/linalg/stencil.py`.

Additionally, we add basic unit tests checking discretizations using
zero-degree splines.

This fixes #489 and fixes #307.

On this occasion, we also do small changes in the
`.github/workflows/testing.yml` script as some tests had complications
without them.

---------

Co-authored-by: Yaman Güçlü <[email protected]>
Always use the maximum padding between test and trial spaces in
`allocate_matrices` in `DiscreteBilinearForm`. (Earlier this was not
done in the case of scalar spaces.) Fixes #504.
Pyccel 2.0 was just released, which means some of the kernels in Psydac
need to be updated:

- Remove the `template` decorator (see
pyccel/pyccel#2331)
   * Add `T` as `TypeVar` 
   * Specify `T`, `T[:]`, `T[:,:]`, ... in function arguments.
- Replace `@types` decorators (see
pyccel/pyccel#2329)
- Replace `const` with `Final` (see
pyccel/pyccel#2340)

Further changes:

- Update import path for `epyccel` (fixes #426)
- Update arguments to `epyccel` (see
pyccel/pyccel#2348):
    * Rename `fflags` to `flags`
    * Replace `accelerators` list with `openmp` bool
- Require Pyccel >= 2.0.1 (fixes #471)

---------

Co-authored-by: Yaman Güçlü <[email protected]>
Co-authored-by: Elena Moral Sánchez <[email protected]>
Co-authored-by: Emily Bourne <[email protected]>
Recently the installation of `h5py` in parallel mode (i.e. with MPI
support through `mpi4py`) seems to have been simplified. This may be due
to the recent move of `mpi4py` to wheels, or other factors. Therefore we
can now simplify our installation procedure as follows:
```sh
pip install h5py --no-cache-dir --no-binary h5py
pip install .[test]
```

We update here the CI workflows and completely rewrite our README file.

**Commit summary**

- Completely rewrite `README.md`:
   * Expand initial description
   * Add Citing and Contributing sections
   * Shorten Installation section
   * Reorganize documentation sections
* Move detailed installation instructions to separate file
`docs/installation.md`
   * Move mesh generation to separate file `docs/psydac-mesh.md`
- Add BibTeX file `CITING.bib` with citation of 2022 ECCOMAS proceedings
- Remove obsolete files `requirements.txt` and `requirements_extra.txt`
- Rename (and move) `docs_requirements.txt` as `docs/requirements.txt`
- Update installation procedure in `testing` CI workflow
- Change name in `testing` workflow from "Run tests" to "Unit tests"
- Modify `testing` and `documentation` workflows so that they only run
when needed
- Allow running workflows manually
- Fix broken CI badge in `README.md`
This PR implements the sum factorization algorithm as shown in **Sum
factorization techniques in Isogeometric Analysis** by Andrea Bressan &
Stefan Takacs for **bilinear forms on 3D volumes**.

The old element-by-element assembly can still be employed by passing a
corresponding flag
```python
# a some BilinearForm
a_h = discretize(a, domain_h, (Vh, Vh), backend=backend, sum_factorization=False)
```

Currently, the new generated code does not make use of OpenMP.

Main changes
--------------
- Write new module `psydac.api.fem_common` which:
   * Contains the old functions previously in module `psydac.api.fem`.
* Has functions `construct_test_space_arguments` and
`construct_trial_space_arguments` returning also the multiplicity.
* Has new functions `compute_max_nderiv`, `compute_imports`,
`compute_free_arguments`.
- Move `DiscreteSumForm` to a new module `psydac.api.fem_sum_form`.
- Create a new module `psydac.api.fem_bilinear_form` which only contains
one new class `DiscreteBilinearForm`. The new module shows all imports
clearly. The new class:
* Generates the code to assemble the given discrete bilinear form into a
matrix (a `BlockLinearOperator` object of `StencilMatrix` objects, or
just a single `StencilMatrix` object), using sum factorization.
* Does not inherit from `BasicDiscrete` (and hence `BasicCodeGen`).
Accordingly, no PSYDAC abstract syntax tree (an object representing a
function, of class `DefNode`) is created by the constructor of `AST`,
which stores it in its `expr` attribute. (Both classes `DefNode` and
`AST` are defined in module `psydac.api.ast.fem`.)
* Does not create a `Parser` object from `psydac.api.ast.parser`, which
used to convert a PSYDAC `DefNode` to an old-Pyccel `FunctionDef` from
`psydac.pyccel.ast.core`.
* Does not generate the old assembly Python code (in the form of a
string) using the function `pycode` from
`psydac.pyccel.codegen.printing.pycode`.
- Add a new unit test file
`api/tests/test_sum_factorization_assembly_3d`.
- Modify function `discretize` in module `psydac.api.discretization` so
that, given a bilinear form in 3D and not asking for OpenMP support, it
creates an object of type `DiscreteBilinearForm` from module
`psydac.api.fem_bilinear_form`. In all other cases, or if
`sum_factorization=False`, it creates an object of namesake type from
the old module `psydac.api.fem`.

Other changes
--------------
- Expand docstring of class `AST` in module `psydac.api.ast.fem`.
- Expand docstrings of function `parse` and class `Parser` in module
`psydac.api.ast.parser`. Clean up `Parser.__init__`.
- Minor cleanup in class `BasicCodeGen` in module `psydac.api.basic`.
- Generate random filenames using `random.choice()` instead of
`random.SystemRandom().choice()`.

Unrelated to matrix assembly:
- Add method `set_scalar` to `ScaledLinearOperator`.
- Reimplement method `idot` of `LinearOperator` using local storage.
This avoids creating unnecessary temporary vectors (especially
beneficial for the method `dot` of `SumLinearOperator`).

---------

Co-authored-by: Yaman Güçlü <[email protected]>
Co-authored-by: elmosa <[email protected]>
### Commit summary

- Fix #461 : Move contents of `psydac/feec/multipatch/api.py` to
`psydac/api/feec.py` and `psydac/api/discretization.py`.
- Remove old code from `psydac/feec/multipatch/operators.py` and
replace it by the contents in
`psydac/feec/multipatch/non_matching_operators.py` to make the structure
more clear.
- Fix #463 
- Fix #272 : keep the `FEMLinearOperator` as a more light-weight class
that encapsulates a `LinearOperator` and has a `apply` and `__call__`
function to make it act on a `FEMField`. Remove duplicated code with
`LinearOperator`. Make operators in `psydac/feec` subclasses of
`LinearOperator`.
- Fix #462: Add conforming projections and Hodge operators to
single-patch `DiscreteDeRham`
- Add single-patch test for the conforming projectors
- Adapt all the tests/files to the new notations. For the single patch
cases mostly renaming `derham_h.derivatives` to `derham_h.derivatives()`
and `derham_h.derivatives_as_matrices` to
`derham_h.derivatives(kind='linop')`
- Merge single-patch and multi-patch operators to the same file if it
makes things clearer. Take Hodge and conforming projection operators out
of the multipatch subdirectory.
- Fix #409 : the global projector interface in DiscreteDeRhamMultipatch
- Fix #331. 
- Add a `SparseMatrixLinearOperator` in `psydac/linalg/sparse.py` to use
a sparse matrix as a `LinearOperator`. This is needed for the conforming
projections.
- Rename `GlobalProjectors` to `GlobalGeometricProjectors`


### Notes

With the current changes, we get all FEEC operators directly from the
discrete de Rham object. Further, the same code also runs if the
domain is a single patch.

---------

Co-authored-by: Yaman Güçlü <[email protected]>
Add the optional parameter `mpi_dims_mask` to the constructor of class
`Geometry`, as well as its class methods `from_discrete_mapping` and
`from_topological_domain`. Add unit tests to verify that the domain is
correctly decomposed.

---------

Co-authored-by: Alisa Kirkinskaia <[email protected]>
Co-authored-by: Alisa Kirkinskaia <[email protected]>
Fix `examples/poisson_2d_mapping.py`:

- Use renamed method `get_assembly_grids` (formerly
`get_quadrature_grids`) of class `TensorFemSpace`
- Add missing definition of `Vnew` variable in the case of distributed
visualization
- Avoid string warnings
Fix bug in method `plot_2d_decomposition` of `TensorFemSpace`, which was
failing when run in parallel with a distributed spline mapping.

- Create a new test file `psydac/fem/tests/test_tensor.py` with a unit
test which fails on the `devel` branch. This compares the generated PNG
images with "reference" ones which are known to be correct, within a 2 %
relative tolerance on each of the RGB channels.
- Only evaluate mapping in local subdomain owned by process
- Gather global mapping information on root process
- Add optional parameters `fig`, `ax`, and `mpi_root`
- Add docstring
- Update `examples/poisson_2d_mapping.py` to pass the correct mapping
(i.e. also a distributed spline mapping if that is used in the
computations) to `plot_2d_decomposition`.
Add a NOTE block with the meaning of the PSYDAC acronym, as well as its
pronounciation.
We implement the class `DirichletProjector` and
`MultipatchDirichletProjector` and include tests.

DirichletProjector
---------------------------
is a subclass of `LinearOperator`. Projects coefficients of functions
belonging to a `fem_space` of `space_kind` $\in$ `{"h1", "hcurl",
"hdiv", "l2"}` to coefficients of functions satisfying the corresponding
homogeneous Dirichlet boundary conditions. These projectors **respect
periodicity**, i.e., coefficients corresponding to "periodic boundaries"
**will not be changed**.

Take for example the constant function $f(x, y) = 1$ on an Annulus.
```python
P0, _, _ = derham_h.projectors()
f        = lambda x, y : 1
F        = P0(f)
plot_field_2d(fem_field=F, domain=domain, N_vis=100, cmap='plasma')
```
See [image](https://github.com/user-attachments/assets/83dc42c6-5ecc-46ae-a0a0-6ceae85526fe).

Applying the `DirichletProjector` sets correctly only the DOFs to 0 that
belong to basis functions that are different from 0 on the
"x1-direction-boundary".

```python
DP0, _ = derham_h.dirichlet_projectors(kind='linop')
F_dp   = FemField(derham_h.V0, DP0 @ F.coeffs)
plot_field_2d(fem_field=F_dp, domain=domain, N_vis=100, cmap='plasma')
```
See [image](https://github.com/user-attachments/assets/a117c5c6-8379-4bcf-b8a8-71e59d2d0eeb).

Usage
---------
Obtain these projectors in the **FEEC context** directly from a
`DiscreteDeRham` object
```python
DP0, DP1 = derham_h.dirichlet_projectors(kind='linop') # in 1D
DP0, DP1, DP2 = derham_h.dirichlet_projectors(kind='linop') # in 2D
DP0, DP1, DP2, DP3 = derham_h.dirichlet_projectors(kind='linop') # in 3D
```
The last projector is simply an `IdentityOperator`.

When instead working with **FEM** objects only: 
```python
from psydac.fem.projectors import DirichletProjector

# working with a space that has a kind
V   = ScalarFunctionSpace('V', domain, kind='h1')
Vh  = discretize(V, domain_h, degree=degree)
DP  = DirichletProjector(Vh)

# working with a space that has no kind
V   = VectorFunctionSpace('V', domain)
Vh  = discretize(V, domain_h, degree=degree)
DP  = DirichletProjector(Vh, kind='hcurl') # or 'hdiv'
```

Similarity with `conforming_projectors`
--------------------------------------------------------
Identical to `derham_h.conforming_projectors(kind='linop', hom_bc=True)`
**on a single-patch**.
On **multi-patch** domains, `derham_h.conforming_projectors` also affect
the solution at the **interfaces** between patches, as required by the
broken-FEEC theory. If required, they have the additional ability to
preserve moments of the solution.
Unfortunately, the conforming projectors are only implemented in 2D.

---------

Co-authored-by: Frederik Schnack <[email protected]>
- Move the script `psydac_accelerate.py` to the function `main` in the new module `psydac/cmd/accelerate.py`
- Define a `psydac-accelerate` executable in file `pyproject.toml`
- Update instructions in `README.md`
- Ignore Bandit warnings about `subprocess` import and calls

Fixes #511.

---------

Co-authored-by: Yaman Güçlü <[email protected]>
- Remove the ancient documentation folder `doc`
- Remove the old CI configuration file `.travis.yml`
- Remove the outdated `TODO.rst`

This fixes #496.

---------

Co-authored-by: Yaman Güçlü <[email protected]>
We add a `diagonal(self, inverse=False, sqrt=False, out=None)` method to
the class `KroneckerStencilMatrix`.
Additionally, we fix the `diagonal` method of `StencilDiagonalMatrix`,
both making it run in general, and also allowing for the kwarg `sqrt`
which had been missing until now.

This method comes in handy for the computation of the yet to be
implemented LST preconditioners.
For the computation of these, we compute 1D mass matrices which are the
building blocks of 2D or 3D logical mass matrices. Additionally, we
compute the diagonal of said 2D or 3D logical mass matrix.
Thus, instead of having to assemble the entire 2D or 3D mass matrix, we
can build them as `KroneckerStencilMatrices`, which is much cheaper, and
then obtain the diagonal.

This feature reduces the runtime of a yet to be implemented LST
preconditioner test from 2 minutes down to 20 seconds.

A very fast test for this new method is included in this PR.
- Create `script/` folder for maintenance scripts
- Create `script/add_header.py` for adding a license header to the top
of every Python file
- Apply script to `examples/`, `mesh/`, `performance/`, and `psydac/`
folders
- Remove obsolete header lines (e.g. `# coding utf-8`, `#!
/usr/bin/python`, `# Copyright ...`) from all Python files
- Clean up imports in several modules across the library

---------

Co-authored-by: Frederik Schnack <[email protected]>
Add logo for README and documentation. Fixes #534.

- Add `docs/logo/` folder with three SVG images:
   * `psydac_platypus.svg` with the PSYDAC platypus logo
   * `psydac_banner.svg` with a long banner (text + logo) for the README
* `psydac_square.svg` with a compact square banner (text + logo) for use
in presentations with a white background
- Include contents of `README.md` in generated documentation
- Use absolute paths in `README.md` for correct linking
- Add `myst-parser` to documentation requirements
- Fix instructions in "Building the Docs" section
- Remove useless links from bottom of main page in documentation
(already present on the top)
- Add square PSYDAC logo to header in documentation page
- Improve layout of documentation page
Implement preconditioners for mass matrices as proposed by Loli, Sangalli &
Tani in 2022 [Easy and efficient preconditioning of the isogeometric mass
matrix](https://doi.org/10.1016/j.camwa.2020.12.009). Fixes #525.

* Add `construct_LST_preconditioner()` to `psydac.fem.lst_preconditioner`.
  This creates the preconditioner for a single mass matrix, with or without
  Dirichlet boundary conditions, in the form of a `LinearOperator`. It uses
  `@functools.lru_cache` to avoid expensive recalculations.

* Add method `LST_preconditioners` to class `DiscreteDeRham`. This calls
  `construct_LST_preconditioner()` to create preconditioners for multiple mass
  matrices.

* Move functions `to_bnd` and `matrix_to_bandsolver` from test module
  `test_kron_direct_solver` to library module `psydac.linalg.direct_solvers`.

* Convert `matrix_to_bandsolver` into `BandedSolver.from_stencil_mat_1d`.

* Provide example in `examples/vector_potential_3d.py`.

* Provide test `linalg/tests/test_solvers.py::test_LST_preconditioner` with
  extensive information about the efficiency of the implementation.

---------

Co-authored-by: Yaman Güçlü <[email protected]>
Refactor the linear solvers to have the preconditioner baked in the same
class. The preconditioner is now a parameter to the constructor of the
solver class, so there is no need to have a different class for the
preconditioned solvers. Fixes #469 and #556.

**Commit Summary**

- Merge `PConjugateGradient` into `ConjugateGradient`
- Merge `PBiConjugateGradientStabilized` into
`BiConjugateGradientStabilized`
- Rename confusing property `linop` of `InverseLinearOperator` as
`fwd_linop`
- Accept any capitalization in solver names (hence one can pass `'CG'`,
`'BiCG'`, `'GMRES'`, etc.)
- Relax too strict complex assertion in `ScaledLinearOperator`
- Raise a `Warning` when using LSMR or BiCG solvers with complex
matrices
- Improve unit tests

---------

Co-authored-by: Yaman Güçlü <[email protected]>
Co-authored-by: Martin Campos Pinto <[email protected]>
- Do not remove `sum_factorization` argument from auxiliary equation for
L2 boundary projection
- Do not use sum factorization for assembly over 3D multi-patch domains
(see issue #545)
- Make 2D plots work for multi-patch domains
- Set correct multipatch FEM space type on disconnected multipatch
domains (fix #552)
- Raise a warning when discretizing a multipatch domain with a periodic
flag (fix #551)

---------

Co-authored-by: Martin Campos Pinto <[email protected]>
Co-authored-by: Martin Campos Pinto <[email protected]>
Make the necessary changes for being able to upload the `psydac` package
to PyPI through a CI workflow:

* Add actions `ubuntu_install` and `macos_install` for installation of
non-Python dependencies
* Require Python >= 3.10 (3.9 is no longer supported). Run tests with
Python 3.14, too
* Require Pyccel >= 2.1.0 and use its new subcommands
* Update PETSc version to 3.24.2
* Add `igakit` as a `git` submodule
* Use `meson-python` as build backend to bundle `igakit` into `psydac`
for publishing to PyPI
* Remove `setup.py` after dropping `setuptools` build backend
* Write PSYDAC in all caps across the whole repository
* Avoid version duplication: have `psydac/version.py` read value from
`pyproject.toml`
* Update instructions for editable install: flag `--no-build-isolation`
should be given to `pip`
* Do not require `wheel` and `numpy` for building
* Add `deploy_check` workflow which uploads PSYDAC to TestPyPI from a
pull request into the `main` branch
* Add `deploy` workflow which uploads PSYDAC to PyPI after a merge into
the `main` branch

---------

Co-authored-by: Emily Bourne <[email protected]>
Avoid failures in the new 3D assembly algorithm based on sum
factorization:

* Do not use it on boundaries and interfaces
* Initialize `self._func` to `None`
* Handle complex quantities
- Reorganize the `examples` directory
- Add Jupyter notebooks to `examples/notebooks/` folder:
  . Define an equation symbolically, discretize it, compute some error
norms, plot solution and error – Poisson 2D on a square with “Collela”
mapping
  . FEEC API multipatch – Maxwell 2D time harmonic
  . FEM example: L2 projection
  . 3D example with VTK and Paraview
  . Get eigenvalues (FEEC) with SciPy (serial) 
  . Get eigenvalues with PETSc + SLEPc (parallel)
  . FEEC 3D vector potential
- Make the notebooks run by the documentation CI, so any errors lead to a
failing build of the documentation

Fixes #170.

---------

Co-authored-by: Martin Campos Pinto <[email protected]>
Co-authored-by: elmosa <[email protected]>
Co-authored-by: Yaman Güçlü <[email protected]>
Co-authored-by: jowezarek <[email protected]>
@codacy-production
Copy link

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
Report missing for 1de2c601
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (1de2c60) Report Missing Report Missing Report Missing
Head commit (d2d673a) 31764 18826 59.27%

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#560) 0 0 ∅ (not applicable)

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

See your quality gate settings    Change summary preferences

Footnotes

  1. Codacy didn't receive coverage data for the commit, or there was an error processing the received data. Check your integration for errors and validate that your coverage setup is correct.

@yguclu
Copy link
Member Author

yguclu commented Dec 28, 2025

Moving to PR #561 with a dedicated release branch (starting as a copy of devel), because devel branch cannot be directly updated

@yguclu yguclu closed this Dec 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.