[MedApplication] Preserve node and geometry IDs in MED I/O with SubModelParts #14201
[MedApplication] Preserve node and geometry IDs in MED I/O with SubModelParts #14201
Conversation
philbucher
left a comment
There was a problem hiding this comment.
cool!
I have some concerns, but overall looks good
I leave approval to current users
| for (int i = 0; i < num_groups; i++) { | ||
| group_names[i] = StringUtilities::Trim(c_group_names.substr(i * MED_LNAME_SIZE, MED_LNAME_SIZE), /*RemoveNullChar=*/true); | ||
| std::string raw_name( c_group_names.data() + i * MED_LNAME_SIZE, MED_LNAME_SIZE); | ||
| raw_name = StringUtilities::Trim(raw_name, true); |
There was a problem hiding this comment.
can you explain this change a bit? I thought the nullchars are already handled?
There was a problem hiding this comment.
Thanks for your comments Philipp.
With the original version, the group names contain garbage characters at the end. To fix this, I trim the strings at the "\0" null terminator.
At least on Ubuntu, this works.
| reorder_fct(geom_node_ids); | ||
|
|
||
| // Avoid using nodes or points as geometries | ||
| if (geo_type == MED_POINT1) { |
There was a problem hiding this comment.
why are those skipped? Structural cases need them! (e.g. pointloads)
There was a problem hiding this comment.
I'm skipping the creation of point geometries, as they don't represent real geometries in Kratos.
Here, node families are used to construct SubModelParts that contain only nodes.
There was a problem hiding this comment.
But they should represent real geometries. If you dont want them then you shouldnt create them in Salome.
See an example for a simple cantilever how they are used:
https://github.com/KratosMultiphysics/KratosSalomePlugin/blob/dce31197e15887b40174d27783ac2839b0134a2e/tui_examples/cantilever/salome_cantilever_hexa.py#L60
| num_nodes, | ||
| dimension); | ||
|
|
||
| // get global numbering for nodes, if the file contains them |
There was a problem hiding this comment.
ah man, despite my best efforts the IDs are always finding their way back :D
Main reason I am against using ids is that they are often (ab) used to get nodes from ModelParts. This is a search, which is expensive for large models
=> one should use position in the ModelPart instead with is O(1)
Also non-consecutive IDs can create problems for MPI-partitioning
personal rant aside, this should be optional, as some meshers dont even write the IDs
I would vote to not read the IDs by default, but that decision I leave to current users or the tech-committee
There was a problem hiding this comment.
That’s true, but in any case, if we do nothing, the MED library enumerates them in its own way. This option is available in both Kratos and Salome, so for now, I think it is better to keep them synchronised. We can remove this later if needed.
There was a problem hiding this comment.
well until now the Ids were just enuerated from the node position
In any case, I dont have a strong opinion
There was a problem hiding this comment.
It's optional now, but locally just so we don't forget we're doing it until someone says something about it.
applications/MedApplication/custom_utilities/med_testing_utilities.cpp
Outdated
Show resolved
Hide resolved
| << "Using MED implicit numbering." << std::endl; | ||
|
|
||
| for (med_int i = 0; i < num_nodes; ++i) { | ||
| node_ids[i] = i + 1; |
There was a problem hiding this comment.
I think you can use std::iota or sth similar
philbucher
left a comment
There was a problem hiding this comment.
I remembered some more potential conceptual issues with the export of SubModelParts
| med_int dimension = 0; | ||
| for (const auto& r_geom : rThisModelPart.Geometries()) { | ||
|
|
||
| dimension = std::max( dimension, static_cast<med_int>(r_geom.WorkingSpaceDimension())); | ||
| } | ||
| if (dimension == 0 || dimension == 1){ | ||
| dimension = 3; | ||
| } |
There was a problem hiding this comment.
| med_int dimension = 0; | |
| for (const auto& r_geom : rThisModelPart.Geometries()) { | |
| dimension = std::max( dimension, static_cast<med_int>(r_geom.WorkingSpaceDimension())); | |
| } | |
| if (dimension == 0 || dimension == 1){ | |
| dimension = 3; | |
| } | |
| med_int dimension = 2; | |
| for (const auto& r_geom : rThisModelPart.Geometries()) { | |
| dimension = std::max( dimension, static_cast<med_int>(r_geom.WorkingSpaceDimension())); | |
| } |
| CheckMEDErrorCode(err, "MEDmeshGlobalNumberWr (nodes)"); | ||
|
|
||
| med_int next_family = 1; | ||
| std::unordered_map<std::string, med_int> smp_to_family; |
There was a problem hiding this comment.
I remembered part of why I didnt implement the writing of SubModelParts: A family in med is NOT the same as a SubModelPart in Kratos. A family contains only one type of geometry (e.g. only Triangle3 or Tetra4).
The med equivalent of a SubModelPart is a group, which consists of multiple families. (actually the relation is the other way round, each family has groups)
Also what I think is not considered is if a geometry belongs to multiple SubModelParts.
Back then I thought the solution would be to tag each entity like is done for the MMG-stuff, but not sure
|
|
||
| CheckMEDErrorCode(err, "MEDmeshGlobalNumberWr (nodes)"); | ||
|
|
||
| med_int next_family = 1; |
There was a problem hiding this comment.
FYI by definition node-families are positive, whereas geometry families are negative
| CheckMEDErrorCode(err, "MEDmeshGlobalNumberWr (cells)"); | ||
|
|
||
| const std::size_t nb_elem = conn.size(); | ||
| std::vector<med_int> elem_family_numbers(nb_elem, 0); |
There was a problem hiding this comment.
| std::vector<med_int> elem_family_numbers(nb_elem, 0); | |
| std::vector<med_int> geom_family_numbers(nb_elem, 0); |
|
|
||
| std::function<void(const ModelPart&)> collect_subparts = | ||
| [&](const ModelPart& mp) { | ||
| for (const auto& r_child : mp.SubModelParts()) { |
There was a problem hiding this comment.
med doesnt know SubSubModelParts, I am curious how you handle it. Have you tested it?
📝 Description
This PR updates the MED I/O so that Kratos can write and read MED files preserving node and geometry IDs, including SubModelParts.
Main points:
I tested this with Python and C++ tests, and also with HROM potential flow models. So far everything works as expected.
🆕 Changelog