Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose inter-/histopolation matrices in GlobalProjector, add unit tests #347

Open
wants to merge 25 commits into
base: devel
Choose a base branch
from

Conversation

spossann
Copy link
Collaborator

@spossann spossann commented Oct 12, 2023

Addresses issue #346.

The inter-/histopolation matrices are now exposed in GlobalProjector as KroneckerStencilMatrix or BlockLinearOperator (for vector-valued spaces).

The unit tests in feec/tests/test_commuting_projections.py have been enhanced: they now also test the new LinearOperator in GlobalProjector.imat_kronecker by computing its inverse using GMRES and comparing to the original BlockDiagonalSolver solution. 3D tests are commented out for the moment as they take too long (better solution)?

@spossann spossann requested a review from yguclu October 12, 2023 13:42
@spossann
Copy link
Collaborator Author

Hi @yguclu, it seems I cannot see why the latest test failed, do you have an idea? Also, did you have time to think about this PR yet?

psydac/feec/tests/test_commuting_projections.py Outdated Show resolved Hide resolved
psydac/feec/tests/test_commuting_projections.py Outdated Show resolved Hide resolved
@spossann
Copy link
Collaborator Author

Python 3.11 tests passed upon relaunching test, without changes.

@yguclu
Copy link
Member

yguclu commented Dec 5, 2023

@spossann It seems that the code could be simplified with these steps:

  1. Use the function array_to_psydac in module psydac.linalg.utilities to convert the 1D matrices from Numpy arrays to a StencilMatrix format (not distributed);
  2. Create a distributed 3D KroneckerStencilMatrix object from the serial 1D StencilMatrix objects;
  3. If needed, call the method KroneckerStencilMatrix.tostencil() to obtain a distributed 3D StencilMatrix object.

Before making any of these changes, could you please add a parallel test to this PR?

@spossann
Copy link
Collaborator Author

@spossann It seems that the code could be simplified with these steps:

1. Use the function `array_to_psydac` in module `psydac.linalg.utilities` to convert the 1D matrices from Numpy arrays to a `StencilMatrix` format (not distributed);

The function array_to_psydac converts numpy arrays into Stencil/BlockVector only (not Matrix).

spossann and others added 5 commits September 13, 2024 14:48
Co-authored-by: Yaman Güçlü <yaman.guclu@gmail.com>
Change `IdentityLinearOperator` to `IdentityOperator`, and `e0 @ e0` to
`e0.dot(e0)`. Add missing import statement.
…1, this fixes the problem with toarray() which did previously not work for StencilMatrix. Updated indexing in KroneckerStencilMatrix to include shift factors in index calculations. Added back the assert statement in GlobalProjector since the toarray() now works. The kernels still don't work properly for different shifts in the domain and the co-domain, but I believe equivalent changes can be done in the remaining kernels.
yguclu and others added 3 commits October 1, 2024 15:13
- Add compiler flags for GFortran >= 14 on Apple silicon chips
- Add unit test in `test_epyccel_flags.py` to check compiler flags
passed to `epyccel`
- Update GitHub actions used in documentation workflow
NumPy 2.1 deprecates the `newshape` argument of the `reshape` function.
Instead, one should use the positional-only argument `shape`. Every call
in Psydac has been updated accordingly. This closes #432.
Update `apt` index files with `apt-get update` to avoid download error
in CI workflow.
yguclu and others added 6 commits October 1, 2024 15:13
Clarify in the `README.md` file that, although the C backend may be
selected for accelerating the kernel files with Pyccel, this is not
fully working yet. Hence the Fortran backend (which is the default) is
the only one available. A future version of Pyccel will certainly
provide a C backend as capable as the Fortran one. See issue #431.

Co-authored-by: Martin Campos Pinto <campos@ann.jussieu.fr>
The obsolete property `is_block` was never used in Psydac nor in
Struphy, hence we remove it.

---------

Co-authored-by: Yaman Güçlü <yaman.guclu@gmail.com>
Fix the indexing in all kernels in `stencil2coo_kernels.py` so that the
method `toarray` works for `StencilMatrix` objects in 1D/2D/3D with
`shift` larger than 1.

The unit tests for `toarray` in `test_stencil_matrix.py` have been
parametrized to run with `shift` values of 1 and 2.

---------

Co-authored-by: Yaman Güçlü <yaman.guclu@gmail.com>
---------

Co-authored-by: Yaman Güçlü <yaman.guclu@gmail.com>
Comment on lines +172 to +194
# TODO: test takes too long in 3D
#--------------------------
# check BlockLinearOperator
#--------------------------
# build the solver from the LinearOperator
# imat_kronecker_P1 = P1.imat_kronecker
# imat_kronecker_P2 = P2.imat_kronecker
# I1inv = inverse(imat_kronecker_P1, 'gmres', verbose=True)
# I2inv = inverse(imat_kronecker_P2, 'gmres', verbose=True)

# # build the rhs
# P1.func(fun1, fun2, fun3)
# P2.func(cf1, cf2, cf3)

# # solve and compare
# u1vec = u1.coeffs
# u1vec_imat = I1inv.solve(P1._rhs)
# assert np.allclose(u1vec.toarray(), u1vec_imat.toarray(), atol=1e-5)

# u2vec = u2.coeffs
# u2vec_imat = I2inv.solve(P2._rhs)
# assert np.allclose(u2vec.toarray(), u2vec_imat.toarray(), atol=1e-5)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not taking the same approach I suggested in function test_3d_commuting_pro_1?

Comment on lines +263 to +284
# TODO: test takes too long in 3D
#--------------------------
# check BlockLinearOperator
#--------------------------
# build the solver from the LinearOperator
# imat_kronecker_P2 = P2.imat_kronecker
# imat_kronecker_P3 = P3.imat_kronecker
# I2inv = inverse(imat_kronecker_P2, 'gmres', verbose=True)
# I3inv = inverse(imat_kronecker_P3, 'gmres', verbose=True)

# # build the rhs
# P2.func(fun1, fun2, fun3)
# P3.func(difun)

# # solve and compare
# u2vec = u2.coeffs
# u2vec_imat = I2inv.solve(P2._rhs)
# assert np.allclose(u2vec.toarray(), u2vec_imat.toarray(), atol=1e-5)

# u3vec = u3.coeffs
# u3vec_imat = I3inv.solve(P3._rhs)
# assert np.allclose(u3vec.toarray(), u3vec_imat.toarray(), atol=1e-5)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not taking the same approach I suggested in function test_3d_commuting_pro_1?

Comment on lines +343 to +363
#--------------------------
# check BlockLinearOperator
#--------------------------
# build the solver from the LinearOperator
imat_kronecker_P0 = P0.imat_kronecker
imat_kronecker_P1 = P1.imat_kronecker
I0inv = inverse(imat_kronecker_P0, 'gmres', verbose=True)
I1inv = inverse(imat_kronecker_P1, 'gmres', verbose=True)

# build the rhs
P0.func(fun1)
P1.func(D1fun1, D2fun1)

# solve and compare
u0vec = u0.coeffs
u0vec_imat = I0inv.solve(P0._rhs)
assert np.allclose(u0vec.toarray(), u0vec_imat.toarray(), atol=1e-5)

u1vec = u1.coeffs
u1vec_imat = I1inv.solve(P1._rhs)
assert np.allclose(u1vec.toarray(), u1vec_imat.toarray(), atol=1e-5)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above

Comment on lines +422 to +442
#--------------------------
# check BlockLinearOperator
#--------------------------
# build the solver from the LinearOperator
imat_kronecker_P0 = P0.imat_kronecker
imat_kronecker_P1 = P1.imat_kronecker
I0inv = inverse(imat_kronecker_P0, 'gmres', verbose=True)
I1inv = inverse(imat_kronecker_P1, 'gmres', verbose=True)

# build the rhs
P0.func(fun1)
P1.func(D2fun1, D1fun1)

# solve and compare
u0vec = u0.coeffs
u0vec_imat = I0inv.solve(P0._rhs)
assert np.allclose(u0vec.toarray(), u0vec_imat.toarray(), atol=1e-5)

u1vec = u1.coeffs
u1vec_imat = I1inv.solve(P1._rhs)
assert np.allclose(u1vec.toarray(), u1vec_imat.toarray(), atol=1e-5)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above

Comment on lines +508 to +528
#--------------------------
# check BlockLinearOperator
#--------------------------
# build the solver from the LinearOperator
imat_kronecker_P2 = P2.imat_kronecker
imat_kronecker_P3 = P3.imat_kronecker
I2inv = inverse(imat_kronecker_P2, 'gmres', verbose=True)
I3inv = inverse(imat_kronecker_P3, 'gmres', verbose=True)

# build the rhs
P2.func(fun1, fun2)
P3.func(difun)

# solve and compare
u2vec = u2.coeffs
u2vec_imat = I2inv.solve(P2._rhs)
assert np.allclose(u2vec.toarray(), u2vec_imat.toarray(), atol=1e-5)

u3vec = u3.coeffs
u3vec_imat = I3inv.solve(P3._rhs)
assert np.allclose(u3vec.toarray(), u3vec_imat.toarray(), atol=1e-5)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above

Comment on lines +594 to +614
#--------------------------
# check BlockLinearOperator
#--------------------------
# build the solver from the LinearOperator
imat_kronecker_P1 = P1.imat_kronecker
imat_kronecker_P2 = P2.imat_kronecker
I1inv = inverse(imat_kronecker_P1, 'gmres', verbose=True)
I2inv = inverse(imat_kronecker_P2, 'gmres', verbose=True)

# build the rhs
P1.func(fun1, fun2)
P2.func(difun)

# solve and compare
u1vec = u1.coeffs
u1vec_imat = I1inv.solve(P1._rhs)
assert np.allclose(u1vec.toarray(), u1vec_imat.toarray(), atol=1e-5)

u2vec = u2.coeffs
u2vec_imat = I2inv.solve(P2._rhs)
assert np.allclose(u2vec.toarray(), u2vec_imat.toarray(), atol=1e-5)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above

Comment on lines +667 to +687
#--------------------------
# check BlockLinearOperator
#--------------------------
# build the solver from the LinearOperator
imat_kronecker_P0 = P0.imat_kronecker
imat_kronecker_P1 = P1.imat_kronecker
I0inv = inverse(imat_kronecker_P0, 'gmres', verbose=True)
I1inv = inverse(imat_kronecker_P1, 'gmres', verbose=True)

# build the rhs
P0.func(fun1)
P1.func(Dfun1)

# solve and compare
u0vec = u0.coeffs
u0vec_imat = I0inv.solve(P0._rhs)
assert np.allclose(u0vec.toarray(), u0vec_imat.toarray(), atol=1e-5)

u1vec = u1.coeffs
u1vec_imat = I1inv.solve(P1._rhs)
assert np.allclose(u1vec.toarray(), u1vec_imat.toarray(), atol=1e-5)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above

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.

5 participants