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

CLN: refactor C++/pybind11 single variables to structs #1294

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jcrivenaes
Copy link
Collaborator

@jcrivenaes jcrivenaes commented Jan 16, 2025

Resolves #1295

Before we transfer more code from C/swig or make too much new code in the C++/pybind11 domain, a refactoring to structs which provide simple "shadow classes" for most important attributes from e.g RegularSurface() and Grid() is done.

It should give an easier to read and a more maintainable code, although I would think that further improvements are possible (perhaps doing it step-wise). In general C++ struct what applied instead of class at this stage, but it should be fairly simple to convert the structs to classes in a later stage, if needed.

Although many files are changed (due to massive dependencies), the PR shall not change any current functionality for the end user. In terms of CPU speed, a coarse comparison indicates no significant changes in on the overall test suite.

@jcrivenaes jcrivenaes marked this pull request as draft January 16, 2025 14:35
@codecov-commenter
Copy link

codecov-commenter commented Jan 17, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 81.12%. Comparing base (0375fed) to head (7d0d54e).
Report is 66 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1294      +/-   ##
==========================================
+ Coverage   80.02%   81.12%   +1.09%     
==========================================
  Files          98       94       -4     
  Lines       13680    12481    -1199     
  Branches     2203     1882     -321     
==========================================
- Hits        10948    10125     -823     
+ Misses       1999     1692     -307     
+ Partials      733      664      -69     

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

@jcrivenaes jcrivenaes force-pushed the testing-shadow-classes-cpp branch 4 times, most recently from 21152af to 4e86605 Compare January 23, 2025 06:37
@jcrivenaes jcrivenaes force-pushed the testing-shadow-classes-cpp branch from 4e86605 to 7d0d54e Compare January 23, 2025 07:53
@@ -41,7 +41,7 @@ BreakBeforeBraces: Mozilla
BreakBeforeInheritanceComma: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakConstructorInitializers: AfterColon
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The appearance of simple constructors did not look good with former setting:
Before:

    Point()
      : x(0)
      , y(0)
      , z(0)
    {
    }

After:
Point() : x(0), y(0), z(0) {}

const double bot_yinc,
const double bot_rotation,
const py::array_t<double> &bot_values);
get_gridprop_value_between_surfaces(const Grid &grd,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

An example when the function signature gets much shorter and easier to maintain

Comment on lines +221 to +224
if num_threads < available_threads / 2:
assert np.array_equal(top, keep_top_store["keep_top"]), (
f"Mismatch with {num_threads} threads"
)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Adjusted this test as it is flaky depending on the actual threads available (consider this is a "hot-fix"; a deeper understanding of cause of flakiness should be considered, but with rather low-priority)

@jcrivenaes jcrivenaes changed the title WIP: refactor C++/pybind11 single variables to structs CLN: refactor C++/pybind11 single variables to structs Jan 23, 2025
@jcrivenaes jcrivenaes marked this pull request as ready for review January 23, 2025 08:22
@jcrivenaes jcrivenaes requested a review from mferrera January 23, 2025 08:22
@ErichSuter ErichSuter self-requested a review January 23, 2025 08:59
{ corners.lower_se.x, corners.lower_se.y, corners.lower_se.z },
{ corners.lower_nw.x, corners.lower_nw.y, corners.lower_nw.z },
{ corners.lower_ne.x, corners.lower_ne.y, corners.lower_ne.z } }
};
Copy link
Contributor

@ErichSuter ErichSuter Jan 23, 2025

Choose a reason for hiding this comment

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

Don't know if it is important, but for clarity it could be an idea to implement an iterator over the corners in CellCorners (I assume that is possible in C++). It could consist of two iterators for the top and base quadrilaterals (I noticed that somewhere else an anti-clockwise ordering was used).
But that is pretty much what CellCorners.arrange_corners() does😊

c2 = [100.0, 50.0, 0.0]
c3 = [75.0, 100.0, 0.0]
c4 = [100.0, 100.0, 0.55]
"""Test the interpolate_z_4p_regular function, which returns a float from C++."""
Copy link
Contributor

Choose a reason for hiding this comment

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

Personally, I like these kinds of drawings directly in the code 😉

Copy link
Contributor

@ErichSuter ErichSuter left a comment

Choose a reason for hiding this comment

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

Some really nice object-oriented clean-up here, far easier to read, debug, apply, and to add new functionalities. Good to go from my side 👍

Copy link
Collaborator

@mferrera mferrera left a comment

Choose a reason for hiding this comment

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

Much nicer function signatures. A lot of progress toward the C++ representation of these objects. Nice work

m_cube.def("cube_stats_along_z", &cube_stats_along_z,
"Compute various statistics for cube along the Z axis, returning maps.");
py::class_<Cube>(m_cube, "Cube")
.def(py::init<>())
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
.def(py::init<>())

Is there a use case for the default constructor here? (It would allow making a C++ cube like _internal.cube.Cube()). Probably we don't want this since empty constructors were deprecated anyway, and should expect its made from the Python object only. Unless of course it breaks something when removed..

Comment on lines +52 to +67
struct Points // placeholder. Consider naming it PointSet for clarity
{
std::vector<Point> points;

// Default constructor
Points() = default;

// Constructor that takes a vector of points
Points(const std::vector<Point> &points) : points(points) {}

// Method to add a point to the points
void add_point(const Point &point) { points.push_back(point); }

// Method to get the number of points
size_t size() const { return points.size(); }
}; // struct Points
Copy link
Collaborator

Choose a reason for hiding this comment

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

Consider removing and adding when it's being used (i.e. don't add dead code)

Comment on lines +100 to +117
struct Polygons // placeholder. Consider naming it PolygonSet for clarity
{
std::vector<Polygon> polygons;
std::vector<int> ids;

// Default constructor
Polygons() = default;

// Method to add a polygon with an ID
void add_polygon(const Polygon &polygon, int id)
{
polygons.push_back(polygon);
ids.push_back(id);
}

// Method to get the number of polygons
size_t size() const { return polygons.size(); };
}; // struct Pol
Copy link
Collaborator

Choose a reason for hiding this comment

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

Consider removing and adding when it's being used (i.e. don't add dead code)

@@ -0,0 +1,337 @@
// separate header file for structs etc used in xtgeo to avoid circular dependencies
Copy link
Collaborator

Choose a reason for hiding this comment

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

A bit worried this header becomes a kitchen sink

Comment on lines +73 to +74
// Default constructor
Polygon() = default;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is a default constructor Polygon() needed here? Could set it to delete if it should always be created with an array

Comment on lines -512 to +534
assert grd.dimensions == bulkvol.dimensions
assert np.allclose(cellvol_rms.values, bulkvol.values)
# assert grd.dimensions == bulkvol.dimensions
# assert np.allclose(cellvol_rms.values, bulkvol.values)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Still meant to be commented out?

Comment on lines +519 to +522
print(bulkvol.values.size)
for i, val in enumerate(bulkvol.values.flatten().tolist()):
print(i, val)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Debugging prints?

assert isinstance(corners, list)
print(corners)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Debug print?

Comment on lines -61 to -62
volume = _internal.geometry.hexahedron_volume(corners, prec)
assert volume == pytest.approx(468.75, rel=1e-3) # 468.75 is RMS' value
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is the volume check no longer relevant?

Comment on lines +258 to +259
// Constructor that takes a Python object and a metadata_only flag
RegularSurface(const py::object &rs, bool metadata_only = false)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm a bit confused about metadata only, maybe because of thinking so much about dataio... it's meant just to take fields but not the full value-data?

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.

Change structure in C++ to apply structs or classes with interface to python
4 participants