Skip to content

Add cell volume and areas#3326

Open
dschwoerer wants to merge 16 commits intonextfrom
cell_area_volume
Open

Add cell volume and areas#3326
dschwoerer wants to merge 16 commits intonextfrom
cell_area_volume

Conversation

@dschwoerer
Copy link
Contributor

@dschwoerer dschwoerer commented Mar 13, 2026

They should make code more readable, and also potentially faster, as now cell_areas at the cell faces can be requested from the coordinates.

This should make the hermes-3 FA operator much more readable, and at the same time also FCI compatible, as the cell areas can be done correctly once for FCI, and then used transparently in user codes. @mikekryjak

Todo:

  • add some tests
  • use in FA operators (needs FA operators from hermes-3)

Information like perpendicular J, Bxyz and g_22 are only known to the
grid generator, but are needed for more correct parallel derivatives
_[A-Z].* is preserved for compilers, thus use _[a-z].*
At this time the parallel transform is not yet set, so isFci() return
false.
@dschwoerer dschwoerer requested a review from ZedThree March 13, 2026 12:41
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

There were too many comments to post at once. Showing the first 25 out of 40. Check the log or trigger a new build to see more.

if (!_jxz_ylow.has_value()) {
_compute_Jxz_cell_faces();
}
return *_jxz_ylow;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

    return *_jxz_ylow;
            ^

if (!_jxz_yhigh.has_value()) {
_compute_Jxz_cell_faces();
}
return *_jxz_yhigh;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

    return *_jxz_yhigh;
            ^

if (!_jxz_centre.has_value()) {
_compute_Jxz_cell_faces();
}
return *_jxz_centre;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

    return *_jxz_centre;
            ^

if (!_jxz_ylow.has_value()) {
_compute_Jxz_cell_faces();
}
return *_jxz_ylow;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

    return *_jxz_ylow;
            ^

if (!_jxz_yhigh.has_value()) {
_compute_Jxz_cell_faces();
}
return *_jxz_yhigh;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

    return *_jxz_yhigh;
            ^

}

private:
mutable std::optional<FieldMetric> _g_22_ylow, _g_22_yhigh;
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "std::optional" is directly included [misc-include-cleaner]

include/bout/coordinates.hxx:40:

+ #include <optional>

const Coordinates::FieldMetric& Coordinates::invSg() const {
if (invSgCache == nullptr) {
auto ptr = std::make_unique<FieldMetric>();
auto ptr = std::make_unique<Coordinates::FieldMetric>();
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "std::make_unique" is directly included [misc-include-cleaner]

    auto ptr = std::make_unique<Coordinates::FieldMetric>();
                    ^

if (_g_22_ylow.has_value()) {
return *_g_22_ylow;
}
_g_22_ylow.emplace(emptyFrom(g_22));
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: no header providing "emptyFrom" is directly included [misc-include-cleaner]

  _g_22_ylow.emplace(emptyFrom(g_22));
                     ^

}
_g_22_ylow.emplace(emptyFrom(g_22));
//_g_22_ylow->setLocation(CELL_YLOW);
auto mesh = Bxy.getMesh();
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: 'auto mesh' can be declared as 'auto *mesh' [readability-qualified-auto]

Suggested change
auto mesh = Bxy.getMesh();
auto *mesh = Bxy.getMesh();

@mikekryjak
Copy link
Contributor

@dschwoerer excellent work, this has been on my wishlist for a very long time. The amount of places we calculate the areas and volumes is considerable, and so is the number of potential mistakes this generates.

I have some questions on what is actually being calculated here. I see there are areas for each side of X, Y and Z. What about parallel areas?

What is Jxz? Is that just J?

Copy link
Member

@ZedThree ZedThree left a comment

Choose a reason for hiding this comment

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

Looks great, thanks @dschwoerer! A couple of suggestions:

Comment on lines +111 to +115
const FieldMetric& Jxz_ylow() const {
if (!_jxz_ylow.has_value()) {
_compute_Jxz_cell_faces();
}
return *_jxz_ylow;
Copy link
Member

Choose a reason for hiding this comment

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

I think this clang-tidy check is unfortunately not clever enough. If _compute_Jxz_cell_faces() returns the computed value, this can actually just be

Suggested change
const FieldMetric& Jxz_ylow() const {
if (!_jxz_ylow.has_value()) {
_compute_Jxz_cell_faces();
}
return *_jxz_ylow;
const FieldMetric& Jxz_ylow() const {
return _jxz_low.value_or(_compute_Jxz_cell_faces());

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately _compute_Jxz_cell_faces() computes 3 different quantities.
We could split up the functions to do that, but that would add even more boiler plate code.

Comment on lines +108 to +109
FieldMetric& g_22_ylow();
FieldMetric& g_22_yhigh();
Copy link
Member

Choose a reason for hiding this comment

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

Probably don't need these overloads?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We probably want to add the cell length, both in the cell centre, as well as at the faces, i.e. the distance between the cell centres.

That would replace g_22 then, right now they are still needed.

@dschwoerer
Copy link
Contributor Author

@dschwoerer excellent work, this has been on my wishlist for a very long time. The amount of places we calculate the areas and volumes is considerable, and so is the number of potential mistakes this generates.

I have some questions on what is actually being calculated here. I see there are areas for each side of X, Y and Z. What about parallel areas?

What do you mean by "parallel" areas? Parallel to what? Or for the parallel slices?

What is Jxz? Is that just J?

No, that is the 2D jacobian in the x-z plane. Probably not needed anymore, we should use the areas directly.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

clang-tidy made some suggestions

// metrics.
auto* mesh = Bxy.getMesh();
ASSERT0(mesh->xstart > 0);
BOUT_FOR(i, _jxz_centre->getRegion("RGN_NOX")) {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

  BOUT_FOR(i, _jxz_centre->getRegion("RGN_NOX")) {
              ^


void Coordinates::_compute_cell_area_y() const {
Jxz();
if (_jxz_centre->isFci()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

  if (_jxz_centre->isFci()) {
      ^

ASSERT2(isUniform(dx, false, "RGN_ALL"));
ASSERT3(isUniform(dz, true, "RGN_ALL"));
ASSERT2(isUniform(dz, false, "RGN_ALL"));
_cell_area_ylow.emplace(*_jxz_ylow * dx * dz);
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

    _cell_area_ylow.emplace(*_jxz_ylow * dx * dz);
                             ^

ASSERT3(isUniform(dz, true, "RGN_ALL"));
ASSERT2(isUniform(dz, false, "RGN_ALL"));
_cell_area_ylow.emplace(*_jxz_ylow * dx * dz);
_cell_area_yhigh.emplace(*_jxz_yhigh * dx * dz);
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

    _cell_area_yhigh.emplace(*_jxz_yhigh * dx * dz);
                              ^

// metrics.
auto* mesh = Bxy.getMesh();
ASSERT0(mesh->ystart > 0);
BOUT_FOR(i, _jxz_centre->getRegion("RGN_NOY")) {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

    BOUT_FOR(i, _jxz_centre->getRegion("RGN_NOY")) {
                ^

// We cannot setLocation, as that would trigger the computation of staggered
// metrics.
//ASSERT0(mesh->zstart > 0);
BOUT_FOR(i, _jxz_centre->getRegion("RGN_NOZ")) {
Copy link
Contributor

Choose a reason for hiding this comment

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

warning: unchecked access to optional value [bugprone-unchecked-optional-access]

  BOUT_FOR(i, _jxz_centre->getRegion("RGN_NOZ")) {
              ^

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.

3 participants