Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
39756d1
wip
BenPinet Jun 8, 2026
1b18385
wip
BenPinet Jun 9, 2026
df8dc99
wip
BenPinet Jun 12, 2026
cc237e7
wip
BenPinet Jun 12, 2026
c7ecbe2
wip
BenPinet Jun 16, 2026
20de5b0
Merge branch 'next' into feat/add_uuid_to_attribute
BenPinet Jun 16, 2026
6882d5b
wip
BenPinet Jun 16, 2026
6ec0e96
wip
BenPinet Jun 17, 2026
be288e0
wip
BenPinet Jun 19, 2026
88722b2
Merge branch 'next' into feat/add_uuid_to_attribute
BenPinet Jun 19, 2026
19297f1
wip
BenPinet Jun 19, 2026
3f59771
clean
BenPinet Jun 19, 2026
f549b73
fix python
BenPinet Jun 19, 2026
a9482f0
fix tests
BenPinet Jun 19, 2026
23cfdf1
feat(Attributes): add uuid to identify attributes and remove find or …
BenPinet Jun 22, 2026
3194d1b
feat(Attribute): attribute are now identified with uuid.
BenPinet Jun 22, 2026
4a07b92
fixes for geosciences
BenPinet Jun 23, 2026
d174e81
python fixes
BenPinet Jun 23, 2026
740b3e5
fix copy
BenPinet Jun 24, 2026
fe21d43
fix vertices identifier
BenPinet Jun 25, 2026
c794ab8
fix load vertex identifier
BenPinet Jun 26, 2026
bb19da1
opengeode fixes for background
BenPinet Jun 29, 2026
8999c5e
Merge branch 'next' into feat/add_uuid_to_attribute
BenPinet Jun 30, 2026
759e9e0
Merge branch 'next' into feat/add_uuid_to_attribute
BenPinet Jul 8, 2026
d17100b
add id to scalar function
BenPinet Jul 16, 2026
a0660c1
fix compilation
BenPinet Jul 16, 2026
ca65cfd
remove uuid
BenPinet Jul 16, 2026
f33bbb3
Merge branch 'next' into feat/add_uuid_to_attribute
BenPinet Jul 16, 2026
01b9bd7
add python function
BenPinet Jul 16, 2026
d34cbee
fixes
BenPinet Jul 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 59 additions & 21 deletions bindings/python/src/basic/attribute_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,43 +33,79 @@
namespace geode
{
template < typename type >
void python_attribute_class( pybind11::class_< AttributeManager >& manager,

Check warning on line 36 in bindings/python/src/basic/attribute_manager.cpp

View workflow job for this annotation

GitHub Actions / test / tidy

bindings/python/src/basic/attribute_manager.cpp:36:10 [misc-use-internal-linkage]

variable 'python_attribute_class' can be made static or moved into an anonymous namespace to enforce internal linkage

Check warning on line 36 in bindings/python/src/basic/attribute_manager.cpp

View workflow job for this annotation

GitHub Actions / test / tidy

bindings/python/src/basic/attribute_manager.cpp:36:10 [cppcoreguidelines-avoid-non-const-global-variables]

variable 'python_attribute_class' is non-const and globally accessible, consider making it const
const std::string& suffix )
{
const auto read_suffix = absl::StrCat( "find_attribute_", suffix );
manager.def(
read_suffix.c_str(), &AttributeManager::find_attribute< type > );
const auto constant_suffix =
absl::StrCat( "find_or_create_attribute_constant_", suffix );
manager.def( constant_suffix.c_str(),
const auto read_suffix =
absl::StrCat( "find_read_only_attribute_", suffix );
manager.def( read_suffix.c_str(),
&AttributeManager::find_read_only_attribute< type > );
const auto create_constant_suffix =
absl::StrCat( "create_attribute_constant_", suffix );
manager.def( create_constant_suffix.c_str(),
static_cast< geode::uuid ( AttributeManager::* )(
std::string_view, type, AttributeProperties ) >(
&AttributeManager::create_attribute< ConstantAttribute,
type > ) );
manager.def( create_constant_suffix.c_str(),
static_cast< void ( AttributeManager::* )(
std::string_view, const uuid&, type, AttributeProperties ) >(
&AttributeManager::create_attribute< ConstantAttribute,
type > ) );
const auto find_constant_suffix =
absl::StrCat( "find_attribute_constant_", suffix );
manager.def( find_constant_suffix.c_str(),
static_cast< std::shared_ptr< ConstantAttribute< type > > (
AttributeManager::* )( std::string_view, type ) >(
&AttributeManager::find_or_create_attribute< ConstantAttribute,
AttributeManager::* )( const geode::uuid& ) >(
&AttributeManager::find_attribute< ConstantAttribute,
type > ) );
const auto create_variable_suffix =
absl::StrCat( "create_attribute_variable_", suffix );
manager.def( create_variable_suffix.c_str(),
static_cast< geode::uuid ( AttributeManager::* )(
std::string_view, type, AttributeProperties ) >(
&AttributeManager::create_attribute< VariableAttribute,
type > ) );
manager.def( create_variable_suffix.c_str(),
static_cast< void ( AttributeManager::* )(
std::string_view, const uuid&, type, AttributeProperties ) >(
&AttributeManager::create_attribute< VariableAttribute,
type > ) );
const auto variable_suffix =
absl::StrCat( "find_or_create_attribute_variable_", suffix );
manager.def( variable_suffix.c_str(),
const auto find_variable_suffix =
absl::StrCat( "find_attribute_variable_", suffix );
manager.def( find_variable_suffix.c_str(),
static_cast< std::shared_ptr< VariableAttribute< type > > (
AttributeManager::* )( std::string_view, type ) >(
&AttributeManager::find_or_create_attribute< VariableAttribute,
AttributeManager::* )( const geode::uuid& ) >(
&AttributeManager::find_attribute< VariableAttribute,
type > ) );
const auto sparse_suffix =
absl::StrCat( "find_or_create_attribute_sparse_", suffix );
manager.def( sparse_suffix.c_str(),
static_cast< std::shared_ptr< SparseAttribute< type > > (
AttributeManager::* )( std::string_view, type ) >(
&AttributeManager::find_or_create_attribute< SparseAttribute,
const auto create_sparse_suffix =
absl::StrCat( "create_attribute_sparse_", suffix );
manager.def( create_sparse_suffix.c_str(),
static_cast< geode::uuid ( AttributeManager::* )(
std::string_view, type, AttributeProperties ) >(
&AttributeManager::create_attribute< SparseAttribute,
type > ) );
manager.def( create_sparse_suffix.c_str(),
static_cast< void ( AttributeManager::* )(
std::string_view, const uuid&, type, AttributeProperties ) >(
&AttributeManager::create_attribute< SparseAttribute,
type > ) );
const auto find_sparse_suffix =
absl::StrCat( "find_attribute_sparse_", suffix );
manager.def( find_sparse_suffix.c_str(),
static_cast< std::shared_ptr< SparseAttribute< type > > (
AttributeManager::* )( const geode::uuid& ) >(
&AttributeManager::find_attribute< SparseAttribute, type > ) );
}

void define_attribute_manager( pybind11::module& module )

Check warning on line 101 in bindings/python/src/basic/attribute_manager.cpp

View workflow job for this annotation

GitHub Actions / test / tidy

bindings/python/src/basic/attribute_manager.cpp:101:10 [misc-use-internal-linkage]

function 'define_attribute_manager' can be made static or moved into an anonymous namespace to enforce internal linkage
{
pybind11::class_< AttributeManager > manager(
module, "AttributeManager" );
manager.def( pybind11::init<>() )
.def( "find_generic_attribute",
&AttributeManager::find_generic_attribute )
.def( "attribute_names", &AttributeManager::attribute_names )
.def( "attribute_ids", &AttributeManager::attribute_ids )
.def( "attribute_type", &AttributeManager::attribute_type )
.def( "attribute_exists", &AttributeManager::attribute_exists )
.def( "nb_elements", &AttributeManager::nb_elements )
Expand All @@ -80,7 +116,9 @@
.def( "delete_attribute", &AttributeManager::delete_attribute )
.def( "set_attribute_properties",
&AttributeManager::set_attribute_properties )
.def( "delete_elements", &AttributeManager::delete_elements );
.def( "delete_elements", &AttributeManager::delete_elements )
.def( "attribute_ids_matching_name",
&AttributeManager::attribute_ids_matching_name );
python_attribute_class< bool >( manager, "bool" );
python_attribute_class< int >( manager, "int" );
python_attribute_class< unsigned int >( manager, "uint" );
Expand Down
71 changes: 45 additions & 26 deletions bindings/python/tests/basic/test-py-attribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,61 +30,80 @@


def test_constant_attribute(manager):
constant_attribute = manager.find_or_create_attribute_constant_bool(
"bool", True)

attribute = manager.find_attribute_bool("bool")

constant_attribute_id = manager.create_attribute_constant_bool(
"bool", True, basic.AttributeProperties())
constant_attribute = manager.find_attribute_constant_bool(constant_attribute_id)
attribute = manager.find_read_only_attribute_bool(constant_attribute_id)
if not attribute.value(0):
raise ValueError("[Test] Should be equal to True")

constant_attribute.set_value(False)
if attribute.value(12):
raise ValueError("[Test] Should be equal to False")
return constant_attribute_id


def test_int_variable_attribute(manager):
variable_attribute = manager.find_or_create_attribute_variable_int(
"int", 12)
variable_attribute_id = manager.create_attribute_variable_int(
"int", 12,basic.AttributeProperties())
variable_attribute = manager.find_attribute_variable_int(variable_attribute_id)
variable_attribute.set_value(3, 3)
if not variable_attribute.is_genericable():
raise ValueError("[Test] Should be genericable")

manager.set_attribute_properties("int",basic.AttributeProperties(True,True))
manager.set_attribute_properties(variable_attribute_id,basic.AttributeProperties(True,True))
if not variable_attribute.properties().assignable or not variable_attribute.properties().interpolable :
raise ValueError("[Test] Should be assignable and interpolable")

attribute = manager.find_attribute_int("int")
if attribute.value(3) != 3:
find_read_only_attribute = manager.find_read_only_attribute_int(variable_attribute_id)
if variable_attribute.value(3) != 3:
raise ValueError("[Test] Should be equal to 3")
if attribute.value(6) != 12:
if variable_attribute.value(6) != 12:
raise ValueError("[Test] Should be equal to 12")
if find_read_only_attribute.value(3) != 3:
raise ValueError("[Test] Should be equal to 3")
if find_read_only_attribute.value(6) != 12:
raise ValueError("[Test] Should be equal to 12")

variable_attribute.set_value(3, 5)
if attribute.value(3) != 5:
if variable_attribute.value(3) != 5:
raise ValueError("[Test] Should be equal to 5")
if find_read_only_attribute.value(3) != 5:
raise ValueError("[Test] Should be equal to 5")


def test_double_sparse_attribute(manager):
sparse_attribute = manager.find_or_create_attribute_sparse_double(
"double", 12)
sparse_attribute.set_value(3, 3)
sparse_attribute.set_value(7, 7)
sparse_attribute_id = manager.create_attribute_sparse_double(
"double", 12,basic.AttributeProperties())
attribute = manager.find_attribute_sparse_double(sparse_attribute_id)
attribute.set_value(3, 3)
attribute.set_value(7, 7)

attribute = manager.find_attribute_double("double")
find_read_only_attribute = manager.find_read_only_attribute_double(sparse_attribute_id)
if attribute.value(3) != 3:
raise ValueError("[Test] Should be equal to 3")
if attribute.value(6) != 12:
raise ValueError("[Test] Should be equal to 12")
if attribute.value(7) != 7:
raise ValueError("[Test] Should be equal to 7")
if find_read_only_attribute.value(3) != 3:
raise ValueError("[Test] Should be equal to 3")
if find_read_only_attribute.value(6) != 12:
raise ValueError("[Test] Should be equal to 12")
if find_read_only_attribute.value(7) != 7:
raise ValueError("[Test] Should be equal to 7")

sparse_attribute.set_value(3, 5)
attribute.set_value(3, 5)
if attribute.value(3) != 5:
raise ValueError("[Test] Should be equal to 5")
if find_read_only_attribute.value(3) != 5:
raise ValueError("[Test] Should be equal to 5")
return sparse_attribute_id


def test_number_of_attributes(manager, nb):
if len(manager.attribute_names()) != nb:
if len(manager.attribute_ids()) != nb:
raise ValueError(
"[Test] Not the correct number of attributes in the manager")

Expand All @@ -99,8 +118,8 @@ def test_delete_attribute_elements(manager):
"[Test] Two attribute elements should have been removed")


def test_sparse_attribute_after_element_deletion(manager):
sparse_attribute = manager.find_attribute_double("double")
def test_sparse_attribute_after_element_deletion(manager, double_attribute_id):
sparse_attribute = manager.find_read_only_attribute_double(double_attribute_id)
if sparse_attribute.value(0) != 12:
raise ValueError("Element 0 of sparse attribute should be 12 ")
if sparse_attribute.value(5) != 7:
Expand All @@ -114,17 +133,17 @@ def test_sparse_attribute_after_element_deletion(manager):
manager.resize(10)
if manager.nb_elements() != 10:
raise ValueError("[Test] Manager should have 10 elements")
test_constant_attribute(manager)
bool_attribute_id = test_constant_attribute(manager)
test_int_variable_attribute(manager)
test_double_sparse_attribute(manager)
test_double_sparse_attribute(manager)
double_attribute_id = test_double_sparse_attribute(manager)
test_delete_attribute_elements(manager)
test_sparse_attribute_after_element_deletion(manager)
test_sparse_attribute_after_element_deletion(manager,double_attribute_id)
test_number_of_attributes(manager, 4)
manager.delete_attribute(bool_attribute_id)
test_number_of_attributes(manager, 3)
manager.delete_attribute("bool")
test_number_of_attributes(manager, 2)
manager.clear_attributes()
test_number_of_attributes(manager, 2)
test_number_of_attributes(manager, 3)
manager.resize(10)
if manager.nb_elements() != 10:
raise ValueError("[Test] Manager should have 10 elements")
Expand Down
8 changes: 5 additions & 3 deletions bindings/python/tests/mesh/test-py-edged-curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,10 @@ def test_edge_requests(edged_curve, builder):


def test_clone(edged_curve):
attribute = edged_curve.edge_attribute_manager(
).find_or_create_attribute_variable_int("test", 0)
attribute_id = edged_curve.edge_attribute_manager(
).create_attribute_variable_int("test", 0,opengeode_py_basic.AttributeProperties())

attribute = edged_curve.edge_attribute_manager().find_attribute_variable_int(attribute_id)
attribute.set_value(0, 42)

edged_curve2 = edged_curve.clone()
Expand All @@ -133,7 +135,7 @@ def test_clone(edged_curve):
if edged_curve2.nb_edges() != 3:
raise ValueError("[Test] EdgedCurve2 should have 3 edge")

attribute2 = edged_curve2.edge_attribute_manager().find_attribute_int("test")
attribute2 = edged_curve2.edge_attribute_manager().find_read_only_attribute_int(attribute_id)
if attribute2.value(0) != 42:
raise ValueError("[Test] EdgedCurve2 attribute should be 42")

Expand Down
17 changes: 10 additions & 7 deletions bindings/python/tests/mesh/test-py-gradient-computation.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ def test_gradient_grid2D():
builder = mesh.RegularGridBuilder2D.create( grid )
builder.initialize_cartesian_grid( geom.Point2D([ 0, 0 ] ), [ 3, 3 ], 1 )
scalar_function_name = "scalar_function"
attribute = grid.vertex_attribute_manager().find_or_create_attribute_variable_double( scalar_function_name, 0 )
attribute_id = grid.vertex_attribute_manager().create_attribute_variable_double( scalar_function_name, 0,opengeode_py_basic.AttributeProperties() )
attribute = grid.vertex_attribute_manager().find_attribute_variable_double( attribute_id )
attribute.set_value( 1, 1 )
attribute.set_value( 4, 1 )
attribute.set_value( 6, 1 )
Expand All @@ -50,7 +51,7 @@ def test_gradient_grid2D():
attribute.set_value( 13, 2 )
attribute.set_value( 14, 3 )
attribute.set_value( 15, 8 )
gradient_name = mesh.compute_surface_scalar_function_gradient2D( grid, scalar_function_name )
gradient_name = mesh.compute_surface_scalar_function_gradient2D( grid, attribute_id )
print("Gradient attribute name: ", gradient_name)
mesh.save_regular_grid2D( grid, "grid_with_gradient.og_rgd2d" )

Expand Down Expand Up @@ -80,7 +81,8 @@ def test_gradient_triangulated_surface2D():
builder.create_polygon( [ 5, 6, 8 ] )
builder.compute_polygon_adjacencies()
scalar_function_name = "scalar_function"
attribute = surface.vertex_attribute_manager().find_or_create_attribute_variable_double( scalar_function_name, 0 )
attribute_id = surface.vertex_attribute_manager().create_attribute_variable_double( scalar_function_name, 0,opengeode_py_basic.AttributeProperties() )
attribute = surface.vertex_attribute_manager().find_attribute_variable_double( attribute_id )
attribute.set_value( 1, 1 )
attribute.set_value( 2, 1 )
attribute.set_value( 3, 1 )
Expand All @@ -89,7 +91,7 @@ def test_gradient_triangulated_surface2D():
attribute.set_value( 9, 3 )
attribute.set_value( 7, 2 )
attribute.set_value( 8, 2 )
gradient_name = mesh.compute_surface_scalar_function_gradient2D( surface, scalar_function_name )
gradient_name = mesh.compute_surface_scalar_function_gradient2D( surface, attribute_id )
print("Gradient attribute name: ", gradient_name)
mesh.save_triangulated_surface2D( surface, "mesh_with_gradient.og_tsf2d" )

Expand All @@ -98,7 +100,8 @@ def test_gradient_grid3D():
builder = mesh.RegularGridBuilder3D.create( grid )
builder.initialize_cartesian_grid( geom.Point3D([ 0, 0, 0 ]), [ 2, 2, 2 ], 1 )
scalar_function_name = "scalar_function"
attribute = grid.vertex_attribute_manager().find_or_create_attribute_variable_double( scalar_function_name, 0 )
attribute_id = grid.vertex_attribute_manager().create_attribute_variable_double( scalar_function_name, 0,opengeode_py_basic.AttributeProperties() )
attribute = grid.vertex_attribute_manager().find_attribute_variable_double( attribute_id )
attribute.set_value( 4, 1 )
attribute.set_value( 10, 1 )
attribute.set_value( 12, 1 )
Expand All @@ -125,8 +128,8 @@ def test_gradient_grid3D():
attribute.set_value( 20, 3 )
attribute.set_value( 24, 3 )
attribute.set_value( 26, 3 )
gradient_name = mesh.compute_solid_scalar_function_gradient3D( grid, scalar_function_name )
print("Gradient attribute name: ", gradient_name)
gradient_id= mesh.compute_solid_scalar_function_gradient3D( grid, attribute_id )
print("Gradient attribute name: ", gradient_id)
mesh.save_regular_grid3D( grid, "grid_with_gradient.og_rgd3d" )

if __name__ == '__main__':
Expand Down
32 changes: 20 additions & 12 deletions bindings/python/tests/mesh/test-py-light-regular-grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,22 +287,26 @@ def test_closest_vertex(grid):


def test_attribute_3d(grid):
attribute = grid.cell_attribute_manager().find_or_create_attribute_variable_double(
"toto", -1
attribute_id = grid.cell_attribute_manager().create_attribute_variable_double(
"toto", -1,geode.AttributeProperties()
)
attribute = grid.cell_attribute_manager().find_attribute_variable_double(attribute_id)
attribute.set_value(10, 10)
attribute = grid.cell_attribute_manager().find_attribute_double("toto")
attribute = grid.cell_attribute_manager().find_read_only_attribute_double(attribute_id)
if attribute.value(0) != -1:
raise ValueError("[Test] Wrong attribute value")
if attribute.value(10) != 10:
raise ValueError("[Test] Wrong attribute value")
if attribute.value(grid.nb_cells() - 1) != -1:
raise ValueError("[Test] Wrong attribute value")
attribute = (
grid.grid_vertex_attribute_manager().find_or_create_attribute_variable_double(
"toto_vertex", 1
attribute_id = (
grid.grid_vertex_attribute_manager().create_attribute_variable_double(
"toto_vertex", 1,geode.AttributeProperties()
)
)
attribute = grid.grid_vertex_attribute_manager().find_attribute_variable_double(
attribute_id
)
attribute.set_value(10, 10)
if attribute.value(0) != 1:
raise ValueError("[Test] Wrong attribute value")
Expand All @@ -314,22 +318,26 @@ def test_attribute_3d(grid):

def test_attribute_2d():
grid = mesh.LightRegularGrid2D(geom.Point2D([1.5, 0]), [5, 10], [1.0, 2.0])
attribute = grid.cell_attribute_manager().find_or_create_attribute_variable_double(
"toto", -1
attribute_id = grid.cell_attribute_manager().create_attribute_variable_double(
"toto", -1,geode.AttributeProperties()
)
attribute = grid.cell_attribute_manager().find_attribute_variable_double(attribute_id)
attribute.set_value(10, 10)
attribute = grid.cell_attribute_manager().find_attribute_double("toto")
attribute = grid.cell_attribute_manager().find_read_only_attribute_double(attribute_id)
if attribute.value(0) != -1:
raise ValueError("[Test] Wrong attribute value")
if attribute.value(10) != 10:
raise ValueError("[Test] Wrong attribute value")
if attribute.value(grid.nb_cells() - 1) != -1:
raise ValueError("[Test] Wrong attribute value")
attribute = (
grid.grid_vertex_attribute_manager().find_or_create_attribute_variable_double(
"toto_vertex", 1
attribute_id = (
grid.grid_vertex_attribute_manager().create_attribute_variable_double(
"toto_vertex", 1,geode.AttributeProperties()
)
)
attribute = grid.grid_vertex_attribute_manager().find_attribute_variable_double(
attribute_id
)
attribute.set_value(10, 10)
if attribute.value(0) != 1:
raise ValueError("[Test] Wrong attribute value")
Expand Down
Loading
Loading