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

Print global number of cells and dofs #1865

Open
wants to merge 10 commits into
base: main
Choose a base branch
from

Conversation

benegee
Copy link
Contributor

@benegee benegee commented Mar 7, 2024

Resolves #1616

Copy link
Contributor

github-actions bot commented Mar 7, 2024

Review checklist

This checklist is meant to assist creators of PRs (to let them know what reviewers will typically look for) and reviewers (to guide them in a structured review process). Items do not need to be checked explicitly for a PR to be eligible for merging.

Purpose and scope

  • The PR has a single goal that is clear from the PR title and/or description.
  • All code changes represent a single set of modifications that logically belong together.
  • No more than 500 lines of code are changed or there is no obvious way to split the PR into multiple PRs.

Code quality

  • The code can be understood easily.
  • Newly introduced names for variables etc. are self-descriptive and consistent with existing naming conventions.
  • There are no redundancies that can be removed by simple modularization/refactoring.
  • There are no leftover debug statements or commented code sections.
  • The code adheres to our conventions and style guide, and to the Julia guidelines.

Documentation

  • New functions and types are documented with a docstring or top-level comment.
  • Relevant publications are referenced in docstrings (see example for formatting).
  • Inline comments are used to document longer or unusual code sections.
  • Comments describe intent ("why?") and not just functionality ("what?").
  • If the PR introduces a significant change or new feature, it is documented in NEWS.md.

Testing

  • The PR passes all tests.
  • New or modified lines of code are covered by tests.
  • New or modified tests run in less then 10 seconds.

Performance

  • There are no type instabilities or memory allocations in performance-critical parts.
  • If the PR intent is to improve performance, before/after time measurements are posted in the PR.

Verification

  • The correctness of the code was verified using appropriate tests.
  • If new equations/methods are added, a convergence test has been run and the results
    are posted in the PR.

Created with ❤️ by the Trixi.jl community.

Copy link

codecov bot commented Mar 7, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.12%. Comparing base (909abb4) to head (a158728).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1865      +/-   ##
==========================================
- Coverage   96.30%   96.12%   -0.19%     
==========================================
  Files         440      440              
  Lines       35793    35800       +7     
==========================================
- Hits        34470    34410      -60     
- Misses       1323     1390      +67     
Flag Coverage Δ
unittests 96.12% <100.00%> (-0.19%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

benegee and others added 2 commits March 7, 2024 17:56
ncells was used elsewhere and has to be the local number
@benegee benegee marked this pull request as ready for review March 7, 2024 16:57
Copy link
Member

@ranocha ranocha left a comment

Choose a reason for hiding this comment

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

Thanks! In #1616, you mentioned that the analysis callback also prints only the local information. Does this PR fix this as well?

src/semidiscretization/semidiscretization.jl Outdated Show resolved Hide resolved
Comment on lines 28 to 34
"""
ndofsglobal(mesh, solver, cache)

Return the global number of degrees of freedom associated with each scalar variable.
Defaults to ndofs when there is no special implementation for parallel computations.
"""
@inline function ndofsglobal(mesh, solver, cache)
Copy link
Member

@ranocha ranocha Mar 8, 2024

Choose a reason for hiding this comment

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

Suggested change
"""
ndofsglobal(mesh, solver, cache)
Return the global number of degrees of freedom associated with each scalar variable.
Defaults to ndofs when there is no special implementation for parallel computations.
"""
@inline function ndofsglobal(mesh, solver, cache)
"""
ndofsglobal(mesh, solver, cache)
Return the global number of degrees of freedom associated with each scalar variable.
Defaults to [`ndofs`](@ref) when there is no special implementation for
MPI-parallel computations.
"""
@inline function ndofsglobal(mesh, solver, cache)

But I'm not sure whether we should better turn this into a comment to avoid making this part of our official API. From my point of view, the methods accepting a semidiscretization are fine but this one is more like an implementation detail.

Copy link
Contributor Author

@benegee benegee Mar 8, 2024

Choose a reason for hiding this comment

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

I am not sure about it.

My concern was that with ndofsglobal(semi::AbstractSemidiscretization) introduced above ndofsglobal(mesh, solver, cache) might get called with some mesh, solver, cache combinations for which it does not exist.

If I see it correctly, there is only
@inline function ndofsglobal(mesh, dg::DG, cache) in dg.jl.

Copy link
Member

Choose a reason for hiding this comment

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

What's you opinion, @sloede?

Copy link
Member

Choose a reason for hiding this comment

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

I'd consider it an implementation detail as well.

However, does it really need a fallback? Or, alternatively, could we check for mpi_isparallel() == 0 and otherwise error, such that a user cannot accidentally use that with a non-parallelized mesh?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd consider it an implementation detail as well.

Ok! However I am afraid I do not understand what this implies.

However, does it really need a fallback?

I added ndofsglobal(semi) to semidiscretization_hyperbolic.jl, which calls ndofsglobal(mesh, solver, cache). So when solver is not DG there should be a MethodError, shouldn't there?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, the docstring! Thanks!

The problem is that I added ndofsglobal to
function Base.show
with the idea that always the global number of dofs gets printed, with ndofs as fallback in case there in no ndofsglobal.

An alternative could be to introduce a separate function just for printing, say print_ndofs, which would then check for mpi_isparallel() or have a default fallback.

Copy link
Member

Choose a reason for hiding this comment

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

Is this resolved after b883b3a?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It resolves the API thing:

Our current policy was that if it has a docstring, we consider it part of our API and then changing its API or its behavior would be a breaking change. Thus we don't add docstring to purely internal functions.

Otherwise this PR got stuck on the question of how to print the global number of dofs on Trixi's startup screen for a mesh which does not have a parallel implementation and thus nothing like ndofsglobal .

Copy link
Member

Choose a reason for hiding this comment

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

I'm a little confused and can't wrap my head around all the implications. Instead of writing back and forth, can we maybe discuss this at the next meeting (if that's not too late for you @benegee)?

Copy link
Member

Choose a reason for hiding this comment

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

Would it be a safe way out of this if we were to implement a fallback that checks mpi_isparallel() and errors if it is true? That is, if someone implements a mesh that is running in parallel but does not implement this function gets it thrown in the face?

@DanielDoehring DanielDoehring added the parallelization Related to MPI, threading, tasks etc. label Mar 12, 2024
@JoshuaLampert
Copy link
Member

What about other mesh types like the TreeMesh? Does it print the local or global number of cells (see here)?

@ranocha
Copy link
Member

ranocha commented Mar 25, 2024

The TreeMesh replicates all cell info on all ranks. Thus, it prints the global info.

@ranocha ranocha requested a review from sloede March 26, 2024 11:24
@sloede
Copy link
Member

sloede commented May 10, 2024

@benegee Please note that you should also adapt the output of the AMR output, probably in these three functions:

function print_amr_information(callbacks, mesh, solver, cache)

function print_amr_information(callbacks, mesh::P4estMesh, solver, cache)

function print_amr_information(callbacks, mesh::T8codeMesh, solver, cache)

Otherwise we get a global element count but only rank-0 information on AMR, which is bound to cause confusion IMHO

@benegee
Copy link
Contributor Author

benegee commented May 10, 2024

True! I realized this in the meantime as well, but have not finished the MPI syncing of element counts.

@sloede
Copy link
Member

sloede commented May 10, 2024

True! I realized this in the meantime as well, but have not finished the MPI syncing of element counts.

Optimally, you'll use an implementation that only requires a single additional MPI_Reduce call.

@@ -105,7 +106,7 @@ function Base.show(io::IO, ::MIME"text/plain", mesh::P4estMesh)
else
setup = [
"#trees" => ntrees(mesh),
Copy link
Member

Choose a reason for hiding this comment

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

Is the number of trees a local or a global information? If local --> please change to global

@@ -91,7 +92,7 @@ function Base.show(io::IO, ::MIME"text/plain", mesh::T8codeMesh)
else
setup = [
"#trees" => ntrees(mesh),
Copy link
Member

Choose a reason for hiding this comment

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

Same here

@@ -310,7 +310,7 @@ function (analysis_callback::AnalysisCallback)(u_ode, du_ode, integrator, semi)
mpi_println(" " * " " *
" " *
" PID: " * @sprintf("%10.8e s", performance_index))
mpi_println(" #DOFs per field:" * @sprintf("% 14d", ndofs(semi)) *
mpi_println(" #DOFs per field:" * @sprintf("% 14d", ndofsglobal(semi)) *
Copy link
Member

Choose a reason for hiding this comment

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

Please check (if not yet done) that all other values that are printed by the analysis callback are also for the global problem and not rank local, otherwise people (especially me 😅) will get confused

"""
ndofsglobal(semi::AbstractSemidiscretization)

Return the global number of degrees of freedom associated with each scalar variable.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Return the global number of degrees of freedom associated with each scalar variable.
Return the global number of degrees of freedom associated with each scalar variable across all MPI ranks.

Just to clarify what is meant by "global"

Comment on lines +126 to +128
@inline function ndofsglobal(semi::SemidiscretizationCoupled)
sum(ndofsglobal, semi.semis)
end
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
@inline function ndofsglobal(semi::SemidiscretizationCoupled)
sum(ndofsglobal, semi.semis)
end
"""
ndofsglobal(semi::SemidiscretizationCoupled)
Return the global number of degrees of freedom associated with each scalar variable across all MPI ranks, and summed up over all coupled systems.
This is the same as [`ndofs`](@ref) for simulations running in serial or
parallelized via threads. It will in general be different for simulations
running in parallel with MPI.
"""
@inline function ndofsglobal(semi::SemidiscretizationCoupled)
sum(ndofsglobal, semi.semis)
end

@@ -314,7 +314,7 @@ function Base.show(io::IO, ::MIME"text/plain", semi::SemidiscretizationHyperboli

summary_line(io, "source terms", semi.source_terms)
summary_line(io, "solver", semi.solver |> typeof |> nameof)
summary_line(io, "total #DOFs per field", ndofs(semi))
summary_line(io, "total #DOFs per field", ndofsglobal(semi))
Copy link
Member

Choose a reason for hiding this comment

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

Please also make sure here that there are no rank-local quantities printed here

Comment on lines 28 to 34
"""
ndofsglobal(mesh, solver, cache)

Return the global number of degrees of freedom associated with each scalar variable.
Defaults to ndofs when there is no special implementation for parallel computations.
"""
@inline function ndofsglobal(mesh, solver, cache)
Copy link
Member

Choose a reason for hiding this comment

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

Would it be a safe way out of this if we were to implement a fallback that checks mpi_isparallel() and errors if it is true? That is, if someone implements a mesh that is running in parallel but does not implement this function gets it thrown in the face?

src/semidiscretization/semidiscretization.jl Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
parallelization Related to MPI, threading, tasks etc.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Trixi displays local, and not global, number of elements / DOFs
5 participants