Skip to content

Broken FEEC projections on polar domains#576

Open
alisa-kirkinskaia wants to merge 82 commits intodevelfrom
polar_splines_alisa
Open

Broken FEEC projections on polar domains#576
alisa-kirkinskaia wants to merge 82 commits intodevelfrom
polar_splines_alisa

Conversation

@alisa-kirkinskaia
Copy link
Copy Markdown
Contributor

@alisa-kirkinskaia alisa-kirkinskaia commented Feb 18, 2026

This PR introduces broken FEEC projections for C0 and C1 sequences (conga_projections.py) in 2D. The formulas for the projections can be found here on pages 19-23.

  • Added projections C0PolarProjection_V0, C0PolarProjection_V1, C0PolarProjection_V2 onto C0 sequence, and analogously onto C1 sequence.

  • dot methods of the projections are implemented for parallel execution for arbitrary domain decompositions in the angular and/or radial dimensions.

  • Added unit tests for the projections checking:

    • the projection property P(P(x)) = P(x)
    • tosparse methods against reference matrix operators
    • consistency between dot and tosparse methods
  • Poisson example
    Example of run: mpirun -n 2 python poisson_2d.py -S -n 16 24 -d 2 2 -t disk -D 0.2 -m 'C0conga'
    Exact solution, approximate solution and error plot:

Screenshot 2026-03-24 at 09 32 20
  • TE Maxwell example
    Example of run: mpirun -n 2 python maxwell_2d.py -S -n 16 20 -d 2 2 -T 1 -D 0.2 -s 1
    Plot of exact solution and approximate solution at final time T = 1:
Screenshot 2026-03-24 at 09 50 04

@yguclu yguclu marked this pull request as ready for review March 9, 2026 22:13
@codacy-production
Copy link
Copy Markdown

codacy-production bot commented Mar 9, 2026

Coverage summary from Codacy

See diff coverage on Codacy

Coverage variation Diff coverage
-0.85% 21.05%
Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (16fb9d3) 31788 19587 61.62%
Head commit (23525d0) 64944 (+33156) 39462 (+19875) 60.76% (-0.85%)

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 (#576) 684 144 21.05%

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

@alisa-kirkinskaia alisa-kirkinskaia marked this pull request as draft March 10, 2026 08:02
@alisa-kirkinskaia alisa-kirkinskaia marked this pull request as ready for review March 10, 2026 08:02
@alisa-kirkinskaia alisa-kirkinskaia marked this pull request as draft March 10, 2026 11:15
@alisa-kirkinskaia alisa-kirkinskaia marked this pull request as ready for review March 10, 2026 11:15
@alisa-kirkinskaia alisa-kirkinskaia marked this pull request as draft March 16, 2026 11:28
@alisa-kirkinskaia alisa-kirkinskaia marked this pull request as ready for review March 16, 2026 11:28
@alisa-kirkinskaia alisa-kirkinskaia marked this pull request as draft March 18, 2026 12:11
@alisa-kirkinskaia alisa-kirkinskaia marked this pull request as ready for review March 18, 2026 12:11
@alisa-kirkinskaia alisa-kirkinskaia marked this pull request as draft March 19, 2026 11:12
@alisa-kirkinskaia alisa-kirkinskaia marked this pull request as ready for review March 19, 2026 11:12
Copy link
Copy Markdown
Member

@yguclu yguclu left a comment

Choose a reason for hiding this comment

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

Thanks for this nice work!

I have started reviewing this PR and I have a couple of questions about test_conga_projections.py

# Checking projection property P0(P0(phi)) = P0(phi)
assert np.allclose(P0.dot(y)[:, :], y[:, :], atol=1e-12, rtol=1e-12)

sp_P0 = P0.tosparse()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The tosparse method of a LinearOperator object does not give any guarantee about the sparse format of the returned object, which only needs to be of type scipy.sparse.spmatrix (or even better, scipy.sparse.sparray).

A few lines below you access the attributes row, col, and data, which implies that sp_P0 is of type scipy.sparse.coo_matrix. In order to make sure that the current line is always correct, we need to modify it as follows:

Suggested change
sp_P0 = P0.tosparse()
sp_P0 = P0.tosparse().tocoo()

Since in this case P0.tosparse() already creates a COO matrix, the tocoo() call returns the same object with negligible computational overhead (see here).

FYI, you can check object identity using the is operator,

sp_P0_any = P0.tosparse()      # COO format in this case
sp_P0_coo = sp_P0_any.tocoo()  # no copy is made
assert sp_P0_any is sp_P0_coo  # True

Comment on lines +78 to +87
# gather sparse matrix entries (rows, columns, data) on root process
payload = (sp_P0.row, sp_P0.col, sp_P0.data)
parts = mpi_comm.gather(payload, root=0)

if mpi_comm.rank == 0:

# Concatenate the result of gather (equivalent to summation of local matrices)
rows = np.concatenate([p[0] for p in parts])
cols = np.concatenate([p[1] for p in parts])
data = np.concatenate([p[2] for p in parts])
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Assuming that mpi_comm contains N+1 processes, here we are taking these steps:

  • Gather on process 0 the three-tuples (sp_P0.row, sp_P0.col, sp_P0.data) to obtain
parts = [(r0, c0, d0), (r1, c1, d1), ..., (rN, cN, dN)]
  • Separate parts back into (rows, cols, data):
rows = [*r0, *r1, ..., *rN]
cols = [*c0, *c1, ..., *cN]
data = [*d0, *d1, ..., *dN]

Instead, could we not gather separately rows, cols, and data on process 0? This way we should obtain a NumPy array for each of these without the need to call np.concatenate(). A basic version of the code should read

Suggested change
# gather sparse matrix entries (rows, columns, data) on root process
payload = (sp_P0.row, sp_P0.col, sp_P0.data)
parts = mpi_comm.gather(payload, root=0)
if mpi_comm.rank == 0:
# Concatenate the result of gather (equivalent to summation of local matrices)
rows = np.concatenate([p[0] for p in parts])
cols = np.concatenate([p[1] for p in parts])
data = np.concatenate([p[2] for p in parts])
# gather sparse matrix entries (rows, columns, data) on root process
rows = mpi_comm.gather(sp_P0.row, root=0)
cols = mpi_comm.gather(sp_P0.col, root=0)
data = mpi_comm.gather(sp_P0.data, root=0)
if mpi_comm.rank == 0:

but I believe that Gather (capitalized) should be used for increased efficiency.

P0.dot(x, out=y)

# Checking projection property P0(P0(phi)) = P0(phi)
assert np.allclose(P0.dot(y)[:, :], y[:, :], atol=1e-12, rtol=1e-12)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I have noticed that you use a hard-coded tolerance of 1e-12 at many places in this file. How about defining the constants RTOL and ATOL just once at the beginning of this file, and then using them everywhere? This way it will be very easy to modify one of the two tolerances in the future, if need be

assert np.allclose(y_sp, y.toarray(), atol=1e-12, rtol=1e-12)

if __name__ == '__main__':
test_PolarProjection_V2(1, [8, 10], [2, 2], False) No newline at end of file
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Apparently the newline character is missing at the end of this file

except NameError:
import matplotlib.pyplot as plt
plt.show()
plt.show() No newline at end of file
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please revert this whitespace-only change. It removes the required newline character at the end of file

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.

2 participants