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
Extend parse function to allow multiple values per key #3267
Conversation
@jdannberg, @naliboff, @mibillen can one of you take a look if this is what we talked about? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Only caught one potential typo, but at first read through looks good!
44390ac
to
bc1efcb
Compare
Thanks for the quick review. I have fixed the comment and added one more functionality we will need. That is to return the actual substructure of the returned vector. As discussed we need this to ensure that all entries actually have the same number of phases for each individual composition (e.g. to distinguish |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice! I really like the structure, and the parsing is not that much more complicated.
* is set to 'true' it also allows entries of the form | ||
* "key1: value1|value2|value3, etc", in which case the returned | ||
* vector will have more entries than the provided | ||
* @p list_of_keys. | ||
* | ||
* This function also considers a number of special cases: | ||
* - If the input string consists of only a comma separated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to add comment here that mentions that you can not do this if allow_subentries == true
because then the notation does not provide enough information?
include/aspect/utilities.h
Outdated
* @param [in] allow_subentries If true allow having multiple subentries | ||
* for each key. If false only allow a single entry per key. In either | ||
* case each key is only allowed to appear once. | ||
* @param [out] subentry_structure If handed over this |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To me, this name does not seem as descriptive as it could be. What about something like values_per_key
or n_values_per_key
? That would also be consistent with the naming of the other input parameters.
INFO("check 10: "); | ||
auto subentry_structure = std::make_shared<std::vector<unsigned int>>(); | ||
|
||
compare_vectors_approx(aspect::Utilities::parse_map_to_double_array ("C1:100, C2:200|, C3:300, C4:400, C5:500", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, we actually allow to use the | but then not have an entry? Is that intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is allowed by deal.II (it depends on the implementation of the split_string_list
function, which explicitly allows this case). I think this is fine, likely nobody wants to use it.
// Subentries not allowed | ||
INFO("check fail 7: "); | ||
REQUIRE_THROWS_WITH( | ||
aspect::Utilities::parse_map_to_double_array ("C1:100, C2:|200, C3:300, C4:400, C5:500", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this test be more helpful and easier to read if the output format was correct (and only the subentries are not allowed)? This way, how do you know which of the two it is?
|
||
for (const auto &entry: return_map) | ||
for (const auto &sub_entry: entry) | ||
return_values.push_back(sub_entry); | ||
} | ||
else if (Patterns::List(Patterns::Double(),1,n_fields).match(input_string)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should make sure that allow_subentries
is false in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not want to do that. Consider the case that somebody wants to allow multiple values per key, but does not know the input structure the user puts into the .prm file. You would still want to allow a simple list of only a single value per key. The parameter is allow_multiple_values_per_key
, not enforce_multiple_values_per_key
. But you are right, I should document that this format expects exactly one value per key (and we already enforce that, because possibly_extend_from_1_to_N
expects either 1 entry, or n_fields
entries).
source/utilities.cc
Outdated
"|") | ||
: | ||
Patterns::Double() | ||
; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move that to the end of the line before?
@@ -146,7 +166,12 @@ namespace aspect | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a space missing in line 162 above.
* vector will be filled with as many components as | ||
* keys (+1 if there is a background field). Each value represents | ||
* how many subentries were found for this key. The sum over all | ||
* entries is the length of the returned vector of values. | ||
* | ||
* @return A vector of values that are parsed from the map, provided | ||
* in the order in which the keys appear in the @p list_of_keys argument. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add some documentation here that explains the new structure with subentries. That could also be a good place to explain why the subentry_structure
is useful (it means whoever calls the function can figure out which value belongs to which key).
I think I addressed all comments, and also added the functionality to hand over an existing vector of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice. Please address my two small comments, and then this should be good to go.
source/utilities.cc
Outdated
@@ -94,27 +94,37 @@ namespace aspect | |||
const std::vector<std::string> &input_field_names, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For some reason, the names of the first two function arguments are different in the declaration and in the implementation here.
source/utilities.cc
Outdated
(*subentry_structure)[i] = 1; | ||
AssertThrow((*n_values_per_key)[i] == 1, | ||
ExcMessage("The input parameter " + property_name + " does not have " | ||
+ "the expected number of values for field index " + std::to_string(i) + ".")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this error message a bit confusing. If this error is thrown, it means someone specified a list of doubles in the input file with one value per key, but some other parameter was specified with multiple values per key, provided in the key:value format (or there is some other reason why the function expects more than one value per key).
So to help the user a bit more, I would tell the user how many entries were expected, and tell them something like: "To specify more than one value per field for this input parameter, you need to use the format :value1|value2|..."
I addressed the comments. Thanks for the review! |
This PR extends Utilities::parse_map_to_double_array to allow multiple entries per key using the syntax:
key1: value1|value2|value3, key2: value1, key3: value1|value2
. We would like to use this syntax to make progress with defining phase transitions for multiple compositional fields (like #2656). The unit tests should cover all cases, so I can make this as a separate PR without actual implementations using it (it will be used by several rheologies, equations of state and material models).