Skip to content
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

Improve functions to retrieve fields of certain type from introspection #5643

Merged

Conversation

gassmoeller
Copy link
Member

This PR improves the functionality inside the Introspection class to retrieve the names or indices of certain field types. In particular it changes:

  • some functions now return references instead of copies of vectors, saving on dynamic allocations
  • the information returned in a number of functions is now precomputed on model start, which makes returning this information much faster (no more push_back into a vector which is then returned by-value)

This PR should allow to retrieve this information quickly even in loops over cells without significant performance penalty.

This should help somewhat with an application in #4370.

@anne-glerum, @jdannberg or @bobmyhill could you take a look at this PR?

@gassmoeller gassmoeller force-pushed the function_to_retrieve_fields_of_type branch from d213f3f to ee12034 Compare May 24, 2024 14:00
Comment on lines 58 to 69
enum Type
{
chemical_composition,
stress,
strain,
grain_size,
porosity,
density,
entropy,
generic,
unspecified
chemical_composition = 0,
stress = 1,
strain = 2,
grain_size = 3,
porosity = 4,
density = 5,
entropy = 6,
generic = 7,
unspecified = 8
} type;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you actually make use of these numeric values? My preference is to treat enums as symbolic names independent of any numerical representation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I use these values to index into an std::vector below. That is why I explicitly specified them to make sure I can uniquely do the indexing. If I would just treat the enums as symbolic names I would create a utility function with a switch statement to return an unsigned int depending on type. However, I think according to the standard I am actually allowed to implicitly cast the enums to the unsigned ints.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just dislike this from a conceptual perspective. It requires keeping track of things in different places.

What would you think of keeping the enum as just a list of symbolic names, and storing data instead of a fixed-size vector into a std::map<enum_type, value_type>?

Copy link
Member Author

@gassmoeller gassmoeller May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not happy about that solution because I do not know the performance implications. The cost of a lookup into a std::map already suprised us in the particle code before and the reason for this PR was to allow this lookup to be fast enough to be done multiple times per cell. What do you think about the alternative of keeping the enum as just a list of names, and having a helper function in an anonymous namespace in introspection.cc that is essentially:

unsigned int
index_of_type (enum type)
{
switch (type):
  case type_a:
    return 0;
  case type_b:
    return 1;
...
}

This way no code outside of Introspection can see that we translate the enum values into indices of a std::vector. However, it requires to always change the function if we change the enum. The beaty of the current solution is that no other code is affected if we add another enum option, everything will just work like before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you still have to have two places that you keep in sync: The translation (whether in a function or by providing initializers) and the place where you store the number of enum elements.

I can be ok with the current state. Let's not make it more difficult!

Comment on lines -541 to +560
const std::vector<unsigned int>
const std::vector<unsigned int> &
get_indices_for_fields_of_type (const CompositionalFieldDescription::Type &type) const;

/**
* Get the names of the compositional fields which are of a
* particular type (chemical composition, porosity, etc.).
*/
const std::vector<std::string>
const std::vector<std::string> &
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was a bug to begin with. The fact that we marked these return types as const suggests that we always intended for them to be references.

source/simulator/introspection.cc Show resolved Hide resolved
@gassmoeller
Copy link
Member Author

I added the assert's you asked for.

Comment on lines 406 to 410
Introspection<dim>::composition_type_exists (const CompositionalFieldDescription::Type &type) const
{
for (unsigned int c=0; c<composition_descriptions.size(); ++c)
if (composition_descriptions[c].type == type)
return true;
return false;
return composition_indices_for_type[type].size() > 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just add an assert here that type is a valid index into the array. This way we'll catch the case where we add an enum element but forget to update n_types. Same in the other places where you use type as an index.

Comment on lines +417 to +422
if (composition_indices_for_type[type].size() > 0)
return composition_indices_for_type[type][0];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like here

@gassmoeller gassmoeller force-pushed the function_to_retrieve_fields_of_type branch from a1de925 to dc9f2d4 Compare May 30, 2024 01:20
@gassmoeller gassmoeller force-pushed the function_to_retrieve_fields_of_type branch from dc9f2d4 to fe04d81 Compare May 30, 2024 01:24
@gassmoeller
Copy link
Member Author

Ah, sorry I missed those two functions. Fixed now, and I now compare against the actual size of the array, not the n_types variable.

@bangerth
Copy link
Contributor

Great, thank you!

@bangerth bangerth merged commit 336e6ef into geodynamics:main May 30, 2024
7 of 8 checks passed
@gassmoeller gassmoeller deleted the function_to_retrieve_fields_of_type branch May 30, 2024 02:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants