feat: support non-scalar valued field specifications #4034
Conversation
|
@rrsettgast does this work for you? |
rrsettgast
left a comment
There was a problem hiding this comment.
Really only two potential issues I have:
- It seems like the tensorial specifications are a completely separate thing from the scalar specifications. They should be able to be made into the same thing.
- The introduction of
regionNamesseems like it is duplicating theobjectPathcapability but just cutting out theElementRegions/regionName*? Can you comment on how the usage is improved?
@rrsettgast thanks for the review.
|
This is great. However, I am not opposed to forcing an xml change to "{1.0}". I go back and forth on this. Avoiding the input file churn should not be a deciding factor in this decision. What do the users think?
Call this my anti-perl tendency, but I prefer a single way to do something rather than multiple ways. With the introduction of "regionNames" there are two ways to specify an element region, and multiple ways to be inconsistent. For instance regionNames and objectPath both being specified requires specific input error checks? I do acknowledge that there was an intent to make objectPath better at some point. I do think it is possible to remove the requirement for "ElementRegions/" and just parse the remaining object path assuming it is there, unless the other objects are specified (i.e. nodeManager, edgeManager, faceManager). For instance: in MeshObjectPath::ObjectTypes extractObjectType( string const & path )
{
MeshObjectPath::ObjectTypes objectType = MeshObjectPath::ObjectTypes::invalid;
if( path.find( MeshLevel::groupStructKeys::nodeManagerString() ) != std::string::npos )
{
objectType = MeshObjectPath::ObjectTypes::nodes;
}
else if( path.find( MeshLevel::groupStructKeys::edgeManagerString() ) != std::string::npos )
{
objectType = MeshObjectPath::ObjectTypes::edges;
}
else if( path.find( MeshLevel::groupStructKeys::faceManagerString() ) != std::string::npos )
{
objectType = MeshObjectPath::ObjectTypes::faces;
}
else if( path.find( MeshLevel::groupStructKeys::elemManagerString() ) != std::string::npos )
{
objectType = MeshObjectPath::ObjectTypes::elems;
}
return objectType;
}So it is always one of these values. (note: I think there should be an error case here) If we changed the last else
{
objectType = MeshObjectPath::ObjectTypes::elems;
}
}then it defaults to elements. I still prefer keeping "ElementRegions" as a requirement, but I don't think defaulting to it is horrible in theory...except for the fact?? that you cannot have an error check here. |
| /// The name of the function used to generate values for application. | ||
| string m_functionName; | ||
| /// Name(s) of the function used to generate values for application. | ||
| string_array m_functionName; |
There was a problem hiding this comment.
| string_array m_functionName; | |
| string_array m_functionNames; |
| /// @return The key for scale | ||
| constexpr static char const * scaleString() { return "scale"; } | ||
| /// @return The key for functionName | ||
| constexpr static char const * functionNameString() { return "functionName"; } |
There was a problem hiding this comment.
| constexpr static char const * functionNamesString() { return "functionNames"; } |
There was a problem hiding this comment.
Same for scale -> scales.
There was a problem hiding this comment.
To avoid breaking users' input files, I kept it as "scale" (same for "functionName"). However, if the previously mentioned change/commit to accept unbracketed single values for 1D arrays is rejected, I will rename it to scales (unless breaking users' files in this case is acceptable?).
There was a problem hiding this comment.
Do both. Enforce scales = {}
| { | ||
| string const path = m_regionNames.empty() | ||
| ? m_objectPath | ||
| : "ElementRegions/{" + stringutilities::join( m_regionNames, ' ' ) + "}"; |
There was a problem hiding this comment.
This isn't quite what I expected. I expected a loop over the region names. Has this been tested with multiple regions?
There was a problem hiding this comment.
Yes, regionNames works with multiple regions (tested with isothermalLeakyWell_smoke_3d.xml). It relies on an objectPath capability that accepts multiple "nodes" at the same level (e.g., objectPath="ElementRegions/{ region1 region2 }").
However, after testing, I found that using objectPath="ElementRegions/{ region1 region2 }" in a XML does not work, whereas regionNames="{ region1, region2 }" does. This is likely due to a regex in the parsing phase that blocks it.
There was a problem hiding this comment.
However, after testing, I found that using
objectPath="ElementRegions/{ region1 region2 }"in a XML does not work, whereasregionNames="{ region1, region2 }"does. This is likely due to a regex in the parsing phase that blocks it.
This is not regex, it is fnmatch. This not a valid fnmatch pattern. Much to your users displeasure I think the valid fnmatch pattern is:
regionNames="ElementRegions/region[12]"
or full expansion:
regionNames="{ ElementRegions/region1, ElementRegions/region2 }"
annoyingly it would be hard (not possible) to get a fnmatch expansion to something like
ElementRegions/reservoir, ElementRegions/overburden
that would have to be:
{ ElementRegions/reservoir, ElementRegions/overburden }
alternatively if you take my suggestion that we just assume everything not FaceManager, EdgeManager, NodeManager is ElementRegion, then I think
objectPath="{ reservoir, overburden }"
would work as desired.
|
I've removed the |
This PR generalizes field specifications to support non-scalar values, notably scales (and so function names).
The following interface is proposed:
Instead of:
This PR also add aregionNamesarray to make it easier to specify multiple regions.Considerations
Implementations considerations:
Design choice
I added a separate
scalesattribute (on top of the already existingscale) and afunctionNamesattribute (on top of the already existingfunctionName) to keep backward compatibility with every input files.The user must choose one way to describe its field specification,
either the scalar way:
or the non-scalar way:
and will not be able to use both at the same time.
Other possible implementations
There are different ways this PR could have been implemented, like:
scaleattribute in favor of a non-scalarscalesscale="42"andscale="{ 42 }"as the same type)FieldSpecification