Skip to content

Commit

Permalink
Merge pull request #109 from Geode-solutions/feat/helpers_to_create_a…
Browse files Browse the repository at this point in the history
…nd_repair_horizons_stack

feat(HorizonsStack): Added helper functions to create and repair a H…
  • Loading branch information
panquez authored Mar 22, 2024
2 parents 050dde0 + 0c88339 commit 45b866a
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 3 deletions.
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,
absl::Span< const std::string > units_names );

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,
absl::Span< const std::string > units_names )
{
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;
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" };
std::array< std::string, 3 > units_list{ "su1", "su2", "su3" };
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

0 comments on commit 45b866a

Please sign in to comment.