Skip to content
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
3 changes: 2 additions & 1 deletion src/core/fem/src/discretization/4C_fem_discretization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ void Core::FE::Discretization::fill_from_mesh(const IO::MeshInput::Mesh<3>& mesh

// Currently, we always require a user element
FOUR_C_ASSERT_ALWAYS(user_element,
"Need a user element for element ID {} in block with ID {}.", ele_count, block.id());
"Need a user element for element ID {} in element block {} with cell type {}.",
ele_count, block.label(), block.cell_type());
Comment thread
rjoussen marked this conversation as resolved.

add_element(user_element);
ele_count++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,10 +242,11 @@ void Core::FE::DiscretizationBuilder<dim>::build(Discretization& discretization,
{
if (!cell_blocks.contains(cell_type))
{
cell_blocks.emplace(cell_type, IO::MeshInput::CellBlock<dim>(cell_type));
const auto block_id = static_cast<IO::MeshInput::ExternalIdType>(cell_blocks.size());
cell_blocks.emplace(
cell_type, IO::MeshInput::CellBlock<dim>(block_id, cell_type,
"auto_clustered_group_for_" + cell_type_to_string(cell_type)));
cell_blocks.at(cell_type).external_ids_.emplace();
cell_blocks.at(cell_type).name.emplace(
"auto_clustered_block_for_" + cell_type_to_string(cell_type));
}
return cell_blocks.at(cell_type);
};
Expand All @@ -260,11 +261,9 @@ void Core::FE::DiscretizationBuilder<dim>::build(Discretization& discretization,
if (elem.user_element) user_elements.emplace(eid, elem.user_element);
}

int cell_block_index = 0;
for (auto&& [cell_type, cell_block] : cell_blocks)
{
mesh.cell_blocks.emplace(cell_block_index, std::move(cell_block));
cell_block_index++;
mesh.cell_blocks.push_back(std::move(cell_block));
}
assert_valid(mesh);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,33 +30,44 @@ const Core::IO::InputSpec& Core::Elements::ElementDefinition::get(
return it2->second;
}

std::tuple<std::string, Core::FE::CellType, Core::IO::InputParameterContainer>
std::pair<std::string, std::map<Core::FE::CellType, Core::IO::InputParameterContainer>>
Core::Elements::ElementDefinition::unpack_element_data(
const Core::IO::InputParameterContainer& data) const
{
const auto& [element_name, element_group] =
data.exactly_one_group(definitions | std::views::keys);

const auto& cell_specs = definitions.at(element_name);
const auto& [cell_type_name, specific_data] = element_group.exactly_one_group(
cell_specs | std::views::keys | std::views::transform(Core::FE::cell_type_to_string));
std::map<Core::FE::CellType, Core::IO::InputParameterContainer> data_by_cell_type;
for (const auto& [cell_type, spec] : definitions.at(element_name))
{
const auto cell_type_name = Core::FE::cell_type_to_string(cell_type);
if (element_group.has_group(cell_type_name))
data_by_cell_type.emplace(cell_type, element_group.group(cell_type_name));
}

return {element_name, Core::FE::string_to_cell_type(std::string(cell_type_name)), specific_data};
FOUR_C_ASSERT_ALWAYS(!data_by_cell_type.empty(),
"Element definition for '{}' must contain at least one cell type group.", element_name);
return {element_name, std::move(data_by_cell_type)};
}


Core::IO::InputSpec Core::Elements::ElementDefinition::element_data_spec() const
Core::IO::InputSpec Core::Elements::ElementDefinition::element_data_spec(
CellTypeGrouping cell_type_grouping) const
{
using namespace Core::IO::InputSpecBuilders;
std::vector<Core::IO::InputSpec> element_choices;
for (const auto& [element, cell_specs] : definitions)
for (const auto& [element_name, cell_specs] : definitions)
{
std::vector<Core::IO::InputSpec> cell_specs_choices;
for (const auto& [cell_type, spec] : cell_specs)
{
cell_specs_choices.emplace_back(group(Core::FE::cell_type_to_string(cell_type), {spec}));
cell_specs_choices.emplace_back(group(Core::FE::cell_type_to_string(cell_type), {spec},
{.required = (cell_type_grouping == CellTypeGrouping::one_of)}));
}
element_choices.emplace_back(group(element, {one_of(std::move(cell_specs_choices))}));
element_choices.emplace_back(
group(element_name, {(cell_type_grouping == CellTypeGrouping::one_of)
? one_of(std::move(cell_specs_choices))
: all_of(std::move(cell_specs_choices))}));
}
return one_of(std::move(element_choices));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
#include "4C_fem_general_cell_type.hpp"
#include "4C_io_input_spec.hpp"

#include <cstdint>
#include <map>
#include <string>
#include <utility>

FOUR_C_NAMESPACE_OPEN

Expand All @@ -29,6 +31,12 @@ namespace Core::Elements
*/
struct ElementDefinition
{
enum class CellTypeGrouping : std::uint8_t
{
one_of, //< only one cell type group is allowed (and required) in the input
all_of, //< all cell type groups are allowed in the input, but none are required.
};

//! Gather all valid element definitions from global state
ElementDefinition();

Expand All @@ -40,18 +48,23 @@ namespace Core::Elements

/**
* Get an InputSpec that describes all valid element definitions.
*
* @param cell_type_grouping Whether the cell type groups are wrapped in a @c one_of or @c
* all_of group.
*/
[[nodiscard]] Core::IO::InputSpec element_data_spec() const;
[[nodiscard]] Core::IO::InputSpec element_data_spec(
CellTypeGrouping cell_type_grouping = CellTypeGrouping::all_of) const;

/**
* Given a @p data container that matches the element_data_spec(), unpack the information
* into a tuple of (element_name, cell_type, specific_data), where specific_data is a
* container that matches the spec from get(element_name, cell_type).
* Given a @p data container with exactly one element definition group, unpack the the element
* name and a map from all present cell type definitions to their corresponding input data.
* Asserts that at least one cell type group is defined.
*/
[[nodiscard]] std::tuple<std::string, Core::FE::CellType, Core::IO::InputParameterContainer>
[[nodiscard]] std::pair<std::string,
std::map<Core::FE::CellType, Core::IO::InputParameterContainer>>
unpack_element_data(const Core::IO::InputParameterContainer& data) const;

//! Map from physics to cell type to InputSpec.
//! Map from element name to cell type to InputSpec.
std::map<std::string, std::map<Core::FE::CellType, Core::IO::InputSpec>> definitions;
};

Expand Down
8 changes: 5 additions & 3 deletions src/core/io/src/4C_io_exodus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <Teuchos_Time.hpp>
#include <Teuchos_TimeMonitor.hpp>

#include <optional>
#include <utility>

FOUR_C_NAMESPACE_OPEN
Expand Down Expand Up @@ -205,10 +206,11 @@ Core::IO::MeshInput::RawMesh<3> Core::IO::Exodus::read_exodus_file(
CHECK_EXODUS_CALL(
ex_get_conn(exo_handle, EX_ELEM_BLOCK, ebids[i], allconn.data(), nullptr, nullptr));

MeshInput::CellBlock<3> cell_block(cell_type_from_exodus_string(ele_type));
std::string block_name(mychar);
MeshInput::CellBlock<3> cell_block(ebids[i], cell_type_from_exodus_string(ele_type),
block_name.empty() ? std::nullopt : std::make_optional(std::move(block_name)));
cell_block.external_ids_ = std::vector<int>{};
cell_block.reserve(num_el_in_blk);
cell_block.name = mychar;

for (int j = 0; j < num_el_in_blk; ++j)
{
Expand All @@ -225,7 +227,7 @@ Core::IO::MeshInput::RawMesh<3> Core::IO::Exodus::read_exodus_file(
cell_block.external_ids_->push_back(elem_ids[element_offset + j]);
}

mesh.cell_blocks.emplace(ebids[i], std::move(cell_block));
mesh.cell_blocks.push_back(std::move(cell_block));
element_offset += num_el_in_blk;
}
} // end of element section
Expand Down
31 changes: 8 additions & 23 deletions src/core/io/src/4C_io_gmsh_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
#include "4C_io_mesh.hpp"
#include "4C_utils_exceptions.hpp"

#include <algorithm>
#include <array>
#include <iostream>
#include <map>
#include <optional>
#include <string>
#include <unordered_set>
#include <vector>
Expand Down Expand Up @@ -272,8 +274,7 @@ namespace

/**
* @brief Fill the element block corresponding to a gmsh physical group into RawMesh.
* If multiple element types are detected in the physical group, a warning is printed and the
* physical group is not added to the element blocks (but can still be used as a point set).
* A separate homogeneous cell block is created for every element type in the physical group.
*
* @param dim The dimension of the physical group.
* @param tag The tag of the physical group.
Expand All @@ -288,15 +289,14 @@ namespace

get_elements_for_physical_group(dim, tag, elementType_to_element_data_map);

// fill element blocks
// loop over element types; if multiple types are found for the same physical group,
// a warning is issued and the corresponding element block is removed
// A physical group can contain multiple element types. Keep the cell blocks homogeneous and
// link all of them to the same group ID and group name if not empty.
for (auto& [element_type, element_data] : elementType_to_element_data_map)
{
// get cell type from Gmsh element type
Core::FE::CellType cell_type = gmsh_element_type_to_core_cell_type(element_type);
Core::IO::MeshInput::CellBlock<3> cell_block(cell_type);
cell_block.name = group_name;
Core::IO::MeshInput::CellBlock<3> cell_block(
tag, cell_type, group_name.empty() ? std::nullopt : std::make_optional(group_name));
cell_block.external_ids_ = element_data.element_tags;
cell_block.reserve(element_data.element_tags.size());

Expand All @@ -317,22 +317,7 @@ namespace
cell_block.add_cell(translate_gmsh_connectivity(cell_type, connectivity));
}

// tag is already a unique tag for element blocks. In the future, we might want to make the
// internal block_id independent of the physical group tag and use a mapping instead.
int block_id = tag;

auto [pair_in_map, inserted] = mesh.cell_blocks.emplace(block_id, cell_block);
if (!inserted)
{
std::cout << "Warning: Multiple element types detected "
<< "in physical group " << (group_name.empty() ? "(unnamed)" : group_name)
<< " (dim=" << dim << ", tag=" << tag << "). "
<< "Detected at least " << Core::FE::cell_type_to_string(cell_type) << " and "
<< Core::FE::cell_type_to_string(pair_in_map->second.cell_type) << ".\n"
<< "This physical group is removed from element blocks, but can still be used as "
"a point set.\n";
mesh.cell_blocks.erase(pair_in_map);
}
mesh.cell_blocks.push_back(std::move(cell_block));
}
}

Expand Down
3 changes: 1 addition & 2 deletions src/core/io/src/4C_io_gmsh_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ namespace Core::IO::Gmsh
*
* @subsection element_blocks Element blocks
* For each physical group, an element block is created using the corresponding
* (unique) tag as a key. If a physical group contains multiple element types, a warning is issued
* and the group is excluded from the element blocks.
* (unique) tag as a key.
*
* @subsection point_sets Point sets
* All physical groups (independent of their dimension) are converted into point
Expand Down
16 changes: 14 additions & 2 deletions src/core/io/src/4C_io_gridgenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "4C_io_value_parser.hpp"
#include "4C_rebalance_binning_based.hpp"
#include "4C_rebalance_graph_based.hpp"
#include "4C_utils_exceptions.hpp"

#include <Teuchos_ParameterList.hpp>

Expand Down Expand Up @@ -332,7 +333,9 @@ namespace Core::IO::GridGenerator
"techniques (when true) or manually partition based on the knowledge "
"of the domain intervals (when false).",
.default_value = false}),
group("elements", {element_definition.element_data_spec()},
group("elements",
{element_definition.element_data_spec(
Elements::ElementDefinition::CellTypeGrouping::one_of)},
{.description = "Specify which elements should be generated."}),
});
}
Expand All @@ -350,9 +353,18 @@ namespace Core::IO::GridGenerator
result.autopartition_ = input.get<bool>("auto_partition");

Elements::ElementDefinition element_definition;
std::tie(result.elementtype_, result.cell_type, result.element_arguments) =
const auto& [element_name, data_by_cell_type] =
element_definition.unpack_element_data(input.group("elements"));

// technically, this is guarded by the input spec already.
FOUR_C_ASSERT_ALWAYS(data_by_cell_type.size() == 1,
"Expected exactly one cell type group for {} elements, but got {}.", element_name,
data_by_cell_type.size());

result.elementtype_ = element_name;
result.cell_type = data_by_cell_type.begin()->first;
result.element_arguments = data_by_cell_type.begin()->second;

return result;
}

Expand Down
Loading
Loading