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

feat(HorizonsStack): Added helper functions to create and repair a H… #109

Merged
merged 3 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion bindings/python/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile bindings/python/requirements.in
# pip-compile --pre bindings/python/requirements.in
#
opengeode-core==14.*,>=14.17.0
# via -r bindings/python/requirements.in
8 changes: 8 additions & 0 deletions bindings/python/src/implicit/representation/core/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ namespace geode
.def( "save_stratigraphic_surfaces",
&save_stratigraphic_surfaces )
.def( "save_stratigraphic_blocks", &save_stratigraphic_blocks )
.def( "horizons_stack_from_name_list_2d",
&horizons_stack_from_name_list< 2 > )
.def( "horizons_stack_from_name_list_3d",
&horizons_stack_from_name_list< 3 > )
.def( "repair_horizon_stack_if_possible_2d",
&repair_horizon_stack_if_possible< 2 > )
.def( "repair_horizon_stack_if_possible_3d",
&repair_horizon_stack_if_possible< 3 > )
.def( "implicit_section_from_cross_section_scalar_field",
[]( CrossSection& model,
absl::string_view attribute_name ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@

#pragma once

#include <absl/types/span.h>

#include <geode/geosciences/implicit/common.h>

namespace geode
{
FORWARD_DECLARATION_DIMENSION_CLASS( HorizonsStack );
ALIAS_2D_AND_3D( HorizonsStack );
class CrossSection;
class StructuralModel;
class ImplicitCrossSection;
Expand Down Expand Up @@ -74,6 +78,19 @@ namespace geode
ImplicitStructuralModel&& implicit_model,
local_index_t implicit_axis );

/*!
* Creates a HorizonsStack from a list of names of Horizons and
* StratigraphicUnits.
*/
template < index_t dimension >
HorizonsStack< dimension > horizons_stack_from_name_list(
absl::Span< const std::string > horizons_names,
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
absl::Span< const std::string > units_names );
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved

template < index_t dimension >
void repair_horizon_stack_if_possible(
HorizonsStack< dimension >& horizon_stack );

std::vector< MeshElement > opengeode_geosciences_implicit_api
invalid_stratigraphic_tetrahedra( const StratigraphicModel& model );
} // namespace detail
Expand Down
125 changes: 125 additions & 0 deletions src/geode/geosciences/implicit/representation/core/detail/helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,32 @@
#include <geode/model/mixin/core/surface.h>

#include <geode/geosciences/implicit/geometry/stratigraphic_point.h>
#include <geode/geosciences/implicit/representation/builder/horizons_stack_builder.h>
#include <geode/geosciences/implicit/representation/builder/implicit_cross_section_builder.h>
#include <geode/geosciences/implicit/representation/builder/implicit_structural_model_builder.h>
#include <geode/geosciences/implicit/representation/builder/stratigraphic_model_builder.h>
#include <geode/geosciences/implicit/representation/core/horizons_stack.h>
#include <geode/geosciences/implicit/representation/core/implicit_cross_section.h>
#include <geode/geosciences/implicit/representation/core/implicit_structural_model.h>
#include <geode/geosciences/implicit/representation/core/stratigraphic_model.h>
#include <geode/geosciences/implicit/representation/core/stratigraphic_section.h>

namespace
{
void check_number_of_horizons_and_stratigraphic_units(
geode::index_t nb_horizons, geode::index_t nb_units )
{
OPENGEODE_EXCEPTION( nb_horizons < nb_units + 2,
"[repair_horizon_stack_if_possible] Too many horizons compared "
"to stratigraphic units (",
nb_horizons, ", should be less than ", nb_units, ")" );
OPENGEODE_EXCEPTION( nb_units < nb_horizons + 2,
"[repair_horizon_stack_if_possible] Too many stratigraphic "
"units compared to horizons (",
nb_units, ", should be less than ", nb_horizons, ")" );
}
} // namespace

namespace geode
{
namespace detail
Expand Down Expand Up @@ -259,6 +277,97 @@ namespace geode
return { std::move( implicit_model ) };
}

template < index_t dimension >
HorizonsStack< dimension > horizons_stack_from_name_list(
absl::Span< const std::string > horizons_names,
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
absl::Span< const std::string > units_names )
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
{
OPENGEODE_EXCEPTION( !horizons_names.empty(),
"[horizons_stack_from_name_list] Cannot create HorizonsStack: "
"horizons_names list is empty." );
const auto nb_horizons = horizons_names.size();
const auto nb_units = units_names.size();
check_number_of_horizons_and_stratigraphic_units(
nb_horizons, nb_units );
HorizonsStack< dimension > stack;
HorizonsStackBuilder< dimension > builder{ stack };
auto current_horizon = builder.add_horizon();
builder.set_horizon_name( current_horizon, horizons_names[0] );
const auto& su_under = builder.add_stratigraphic_unit();
builder.add_horizon_above( stack.horizon( current_horizon ),
stack.stratigraphic_unit( su_under ) );
bool lowest_unit_to_create{ nb_units < nb_horizons };
if( !lowest_unit_to_create )
{
builder.set_stratigraphic_unit_name( su_under, units_names[0] );
}
for( const auto counter : Range{ 1, horizons_names.size() } )
{
const auto& su_above = builder.add_stratigraphic_unit();
builder.set_stratigraphic_unit_name( su_above,
units_names[counter + lowest_unit_to_create ? -1 : 0] );
builder.add_horizon_under( stack.horizon( current_horizon ),
stack.stratigraphic_unit( su_above ) );
current_horizon = builder.add_horizon();
builder.set_horizon_name(
current_horizon, horizons_names[counter] );
builder.add_horizon_above( stack.horizon( current_horizon ),
stack.stratigraphic_unit( su_above ) );
}
const auto& su_above = builder.add_stratigraphic_unit();
builder.add_horizon_under( stack.horizon( current_horizon ),
stack.stratigraphic_unit( su_above ) );
if( nb_units > nb_horizons )
{
builder.set_stratigraphic_unit_name(
su_above, units_names.back() );
}
return stack;
}

template < index_t dimension >
void repair_horizon_stack_if_possible(
HorizonsStack< dimension >& horizon_stack )
{
const auto nb_horizons = horizon_stack.nb_horizons();
check_number_of_horizons_and_stratigraphic_units(
nb_horizons, horizon_stack.nb_stratigraphic_units() );
const auto bottom_horizon = horizon_stack.bottom_horizon();
if( !horizon_stack.under( bottom_horizon ) )
{
HorizonsStackBuilder< dimension > builder{ horizon_stack };
const auto& unit_under = builder.add_stratigraphic_unit();
builder.add_horizon_above(
horizon_stack.horizon( bottom_horizon ),
horizon_stack.stratigraphic_unit( unit_under ) );
}
index_t horizon_counter{ 1 };
auto su_above = horizon_stack.above( bottom_horizon );
absl::optional< uuid > current_horizon = bottom_horizon;
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
while( su_above )
{
current_horizon = horizon_stack.above( su_above.value() );
if( !current_horizon )
{
break;
}
su_above = horizon_stack.above( current_horizon.value() );
horizon_counter++;
}
OPENGEODE_EXCEPTION( horizon_counter == nb_horizons,
"[repair_horizon_stack_if_possible] Missing or wrong "
"above/under relations between horizons and stratigraphic "
"units." );
if( !su_above )
{
HorizonsStackBuilder< dimension > builder{ horizon_stack };
const auto& unit_above = builder.add_stratigraphic_unit();
builder.add_horizon_under(
horizon_stack.horizon( current_horizon.value() ),
horizon_stack.stratigraphic_unit( unit_above ) );
}
}

std::vector< MeshElement > invalid_stratigraphic_tetrahedra(
const StratigraphicModel& implicit_model )
{
Expand Down Expand Up @@ -301,5 +410,21 @@ namespace geode
}
return invalid_tetrahedra;
}

template HorizonsStack< 2 > opengeode_geosciences_implicit_api
horizons_stack_from_name_list< 2 >(
absl::Span< const std::string > horizons_names,
absl::Span< const std::string > units_names );
template HorizonsStack< 3 > opengeode_geosciences_implicit_api
horizons_stack_from_name_list< 3 >(
absl::Span< const std::string > horizons_names,
absl::Span< const std::string > units_names );

template void opengeode_geosciences_implicit_api
repair_horizon_stack_if_possible< 2 >(
HorizonsStack< 2 >& horizon_stack );
template void opengeode_geosciences_implicit_api
repair_horizon_stack_if_possible< 3 >(
HorizonsStack< 3 >& horizon_stack );
} // namespace detail
} // namespace geode
44 changes: 42 additions & 2 deletions tests/implicit/test-horizons-stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <geode/basic/logger.h>

#include <geode/geosciences/implicit/representation/builder/horizons_stack_builder.h>
#include <geode/geosciences/implicit/representation/core/detail/helpers.h>
#include <geode/geosciences/implicit/representation/core/horizons_stack.h>
#include <geode/geosciences/implicit/representation/io/horizons_stack_input.h>
#include <geode/geosciences/implicit/representation/io/horizons_stack_output.h>
Expand All @@ -44,9 +45,9 @@ void test_horizons_stack()
const geode::uuid unit1{};
stack_builder.add_stratigraphic_unit( unit1 );
OPENGEODE_EXCEPTION( horizons_stack.nb_horizons() == 3,
"[Test] Stratigraphic Units Stack should have 3 horizons." );
"[Test] Horizons Stack should have 3 horizons." );
OPENGEODE_EXCEPTION( horizons_stack.nb_stratigraphic_units() == 2,
"[Test] Stratigraphic Units Stack should have 2 Stratigraphic Units." );
"[Test] Horizons Stack should have 2 Stratigraphic Units." );
stack_builder.add_horizon_under( horizons_stack.horizon( hor0 ),
horizons_stack.stratigraphic_unit( unit0 ) );
stack_builder.add_horizon_above( horizons_stack.horizon( hor1 ),
Expand Down Expand Up @@ -78,12 +79,51 @@ void test_horizons_stack()
== insertion_info.new_horizon_id,
"[Test] New horizon should be found from horizon 1." );

geode::detail::repair_horizon_stack_if_possible( horizons_stack );
OPENGEODE_EXCEPTION( horizons_stack.nb_horizons() == 4,
"[Test] Horizons Stack should have 4 horizons after repair." );
OPENGEODE_EXCEPTION( horizons_stack.nb_stratigraphic_units() == 5,
"[Test] Horizons Stack should have 5 Stratigraphic Units after "
"repair." );
for( const auto& horizon : horizons_stack.horizons() )
{
const auto& horizon_id = horizon.id();
OPENGEODE_EXCEPTION( horizons_stack.above( horizon_id ),
"[Test] Horizon should have a unit above." );
OPENGEODE_EXCEPTION( horizons_stack.under( horizon_id ),
"[Test] Horizon should have a unit under." );
}

const auto stack_path = absl::StrCat( "test_HorizonStack.",
geode::HorizonsStack3D::native_extension_static() );
geode::save_horizons_stack( horizons_stack, stack_path );
auto reloaded_stack = geode::load_horizons_stack< 3 >( stack_path );
}

void test_create_horizons_stack()
{
std::array< std::string, 4 > horizons_list{ "h1", "h2", "h3", "h4" };
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
std::array< std::string, 3 > units_list{ "su1", "su2", "su3" };
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
MelchiorSchuh marked this conversation as resolved.
Show resolved Hide resolved
const auto horizons_stack =
geode::detail::horizons_stack_from_name_list< 2 >(
horizons_list, units_list );
OPENGEODE_EXCEPTION( horizons_stack.nb_horizons() == 3,
"[Test] Created Horizons Stack should have 4 horizons." );
OPENGEODE_EXCEPTION( horizons_stack.nb_stratigraphic_units() == 5,
"[Test] Created Horizons Stack should have 5 Stratigraphic Units." );
const auto bot_horizon = horizons_stack.bottom_horizon();
OPENGEODE_EXCEPTION(
horizons_stack.horizon( bot_horizon ).name() == horizons_list[0],
"[Test] Wrong name for bottom horizon." );
OPENGEODE_EXCEPTION(
horizons_stack
.stratigraphic_unit(
horizons_stack.above( bot_horizon ).value() )
.name()
== units_list[0],
"[Test] Wrong name for unit above bottom horizon." );
}

int main()
{
try
Expand Down
Loading