-
Notifications
You must be signed in to change notification settings - Fork 10
Add implicit complement and default material properties #57
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
base: main
Are you sure you want to change the base?
Add implicit complement and default material properties #57
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #57 +/- ##
==========================================
- Coverage 97.08% 96.98% -0.11%
==========================================
Files 2 2
Lines 446 497 +51
Branches 48 65 +17
==========================================
+ Hits 433 482 +49
- Misses 10 11 +1
- Partials 3 4 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
gonuke
left a comment
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'm not sure all the assumptions and conventions are robust to the rules for how the implicit complement and its material are used in practice. I wonder if we've every written down the expectations for how this information is used in codes? @pshriwise ?
| Returns the implicit complement volume. | ||
| The implicit complement volume is identified as the volume | ||
| that has the material 'Graveyard'. |
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 don't think it's true that a volume in the mat:Graveyard group is necessarily the implicit complement.
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.
Right. In most/many cases the .h5m doesn't have an implicit complement volume -- it typically gets built at runtime. It wouldn't be difficult to construct one using PyDAGMC, however.
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.
It might be beneficial to do this even? One of the challenges we have with the implicit complement material assignment is that the volume doesn't exist yet when we load the file and parse metadata leading to a sort of chicken and egg problem here. If we create the volume in PyDAGMC then we can assign the material easily enough.
One issue I can see with that is keeping track of which volume is the implicit complement when round-tripping the mesh to and from disk. Is marking the implicit complement part of the file spec?
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.
Im pretty sure it's not part of the file spec because it's intended to be reconstructed as necessary, potentially with every read.
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.
What happens when the build_obbs tool is run on a file? Is the implicit complement omitted and run later?
| # First, find and unset any existing implicit complement material group | ||
| for group in self.groups: | ||
| if group.name and group.name.startswith('mat:') and group.name.endswith('_comp'): | ||
| group.name = group.name.removesuffix('_comp') | ||
| break |
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.
If this group is empty, it should probably just be deleted
| if material_name is not None: | ||
| # Find the group for the new material | ||
| material_group_name = f"mat:{material_name}" | ||
| if material_group_name in self.groups_by_name: |
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.
If this group exists and is not empty, is it safe to just rename it like this?
| is_comp = self.material_group and self.material_group.name.endswith('_comp') | ||
| self._set_metadata_group(self._material_prefix, name) | ||
| if is_comp: | ||
| self.material_group.name += '_comp' |
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.
Doesn't this bypass some of the care you used to set the implicit complement material above?
| if val.lower() in self.model.group_names: | ||
| current_name = self.name | ||
| if val.lower() in self.model.group_names and val.lower() != current_name.lower(): |
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 think it's better to just return early if current_name.lower() == val.lower() and then test for the case that raises an exception
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.
Also we should compare val.lower() to the lowercase version of each group name if that's the precedent we're going with here. Could get some false negatives in the current state.
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.
Different question: do we actually assume that group names are case-insensitive? Or should we NOT use lower() at all?
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.
Good point. In OpenMC, lowercase comparison is how we perform comparisons against materials when names are used for assignment. That doesn't have to be the case for all codes that might use names for assignment (though I'll say I think it's worked pretty well for us so far).
To date I believe OpenMC is the only one that allows assignment by name.
pshriwise
left a comment
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 for submitting this @ahnaf-tahmid-chowdhury. There's some cleanup to do here. This will be nice to have for those interested in this capability I think!
| @property | ||
| def default_material(self) -> Optional[str]: | ||
| """ | ||
| The default material for volumes without a material. | ||
| """ | ||
| for group in self.groups: | ||
| if group.name and group.name.startswith('pydagmc:default_material:'): | ||
| return group.name.split(':')[-1] | ||
| return None | ||
|
|
||
| @default_material.setter | ||
| def default_material(self, material_name: Optional[str]): | ||
| """ | ||
| Set the default material for volumes without a material. | ||
| """ | ||
| # First, remove any existing default material marker | ||
| for group in self.groups: | ||
| if group.name and group.name.startswith('pydagmc:default_material:'): | ||
| group.delete() | ||
| break | ||
|
|
||
| if material_name is not None: | ||
| # Assign the material to all volumes without one. | ||
| for volume in self.volumes_without_material: | ||
| volume.material = material_name | ||
| # Create a marker group to store the default material name | ||
| self.create_group(name=f'pydagmc:default_material:{material_name}') | ||
|
|
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.
Not a bad concept to introduce, but this is out of scope for the PR. Let's keep it to one thing at a time and focus on the implicit complement.
| if val.lower() in self.model.group_names: | ||
| current_name = self.name | ||
| if val.lower() in self.model.group_names and val.lower() != current_name.lower(): |
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.
Also we should compare val.lower() to the lowercase version of each group name if that's the precedent we're going with here. Could get some false negatives in the current state.
| Returns the implicit complement volume. | ||
| The implicit complement volume is identified as the volume | ||
| that has the material 'Graveyard'. |
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.
It might be beneficial to do this even? One of the challenges we have with the implicit complement material assignment is that the volume doesn't exist yet when we load the file and parse metadata leading to a sort of chicken and egg problem here. If we create the volume in PyDAGMC then we can assign the material easily enough.
One issue I can see with that is keeping track of which volume is the implicit complement when round-tripping the mesh to and from disk. Is marking the implicit complement part of the file spec?
| # Set the implicit complement material to the existing material of the graveyard | ||
| model.implicit_complement_material = 'Graveyard' | ||
| assert model.implicit_complement_material == 'Graveyard' | ||
| assert graveyard.material_group.name == 'mat:Graveyard_comp' | ||
| assert graveyard.material == 'Graveyard' # Should not change |
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.
As @gonuke mentioned above, I think there's some conflation of concepts here between the implicit complement and graveyard volume.
Thanks for jogging my memory about this @gonuke as to the chicken and egg problem we run into when assigning the implicit complement material in OpenMC. Based on the website, this capability appears to be supported for MCNP, Tripoli4, and OpenMC. Here are a couple of snippets from the page: "Since the implicit complement doesn’t exist before running DAGMC and DAGMC can only recognize groups that contain an entity, the material for the implicit complement must be specified as if it were being specified for the graveyard volume." "Since DAGMC only recognizes those groups that contain an entity, it is necessary to add a volume to this group, recognizing that this material will NOT be assigned to that volume" This part of how the material assignment works is particularly confusing and understandably led to a lot of confusion in this PR as to it's connection with the graveyard volume (sorry @ahnaf-tahmid-chowdhury). As I understand it this is something that we could solve in DAGMC if we were to revisit the restriction around the group requiring a volume to be recognized. As an alternative, we could add the capability here to create the implicit complement volume and assign its material like any other volume. Codes do tend to treat this volume specially, however, and I think we'd want to mark it as such as part of the DAGMC file spec were we to do this. Plenty to discuss here it seems. |
Linking in a related issue in the DAGMC repo here: |
This PR introduces two new features to the
Modelclass:1. Implicit Complement Material
The
implicit_complement_materialproperty allows getting and setting the material of the implicit complement volume (the volume with the 'Graveyard' material).implicit_complementproperty has been added to easily access this volume.implicit_complement_materialproperty getter finds the material of the implicit complement.implicit_complement_materialproperty setter allows changing the material of the implicit complement. A_compsuffix is added to the material group name to indicate that it is the implicit complement material.2. Default Material
The
default_materialproperty allows setting a default material for all volumes that do not have a material assigned.default_materialis set, all volumes without a material are assigned the specified material.pydagmc:default_material:<material_name>is created to indicate the default material.default_materialis unset, the marker group is deleted, but the volumes retain the assigned material.Tests have been added for both features to ensure they work as expected.