-
Notifications
You must be signed in to change notification settings - Fork 12
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
Some final input on the IVC OO update #59
Conversation
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 @gonuke, I think a lot of these changes make things more streamlined than before.
I just have some comments/questions involving structure and syntax. For the smaller changes involving syntax, I'm happy to take care of them myself.
cubit_initialized = True | ||
|
||
return cubit_initialized | ||
initialized = True |
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.
The global variable initialized
will not be updated outside this function. To have the update apply globally, initialized
either needs to be returned or be referenced as a global variable; see corresponding suggestion
""" | ||
if not cubit_initialized: | ||
if not initialized: |
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 not initialized: | |
global initialized | |
if not initialized: |
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.
hopefully that is enough to handle all the other assumptions I make about how this should work
@@ -61,6 +53,8 @@ def export_step_cubit(filename, export_dir=''): | |||
export_dir (str): directory to which to export the STEP output file | |||
(defaults to empty string). | |||
""" | |||
init_cubit() |
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 STEP files are being exported, presumably Cubit has already been initialized? Is there a different reason for calling init_cubit()
?
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.
Maybe it should also be mentioned that with newer versions of Cubit (perhaps this was true for older versions as well), calling Cubit functions in Python without explicitly initializing Cubit beforehand will initialize Cubit with default parameters. We define our own Cubit initialization to limit output and set the Svalinn plug-in directory (which is only relevant for the legacy DAGMC export).
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.
The way we have written it (possibly with your corrections), this function costs basically nothing after the first time. The reason to call it often is just to be robust against other people using these methods in ways we don't expect. An alternative would be to check initialization and raise an exception. (Or maybe that would happen anyway if not initialized?)
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.
Fair enough! I think calling init_cubit
at the beginning of each function as you've implemented is simpler than checking initialization. My only concern has to do with the behavior of Cubit re-initialization.
Is it guaranteed that re-initializing effectively doesn't do anything? After testing I can guarantee that it doesn't affect geometry but Cubit's Python source code isn't transparent enough for me to see anything else that might be going on.
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 agree that some of the additions I made are probably a little superfluous, but since they are essentially free, it seems like it's ok.
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.
Agreed that it's okay, and since we've confirmed that the state of initialized
persists, calling init_cubit
in each function is harmless
@@ -74,6 +68,8 @@ def export_mesh_cubit(filename, export_dir=''): | |||
export_dir (str): directory to which to export the H5M output file | |||
(defaults to empty string). | |||
""" | |||
init_cubit() |
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.
Similar question as above about initialization.
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.
Using our Cubit initialization function does feel more necessary here to set the Svalinn plug-in path, though only if this function is called outside ParaStell.
@@ -101,6 +97,8 @@ def export_dagmc_cubit_legacy( | |||
export_dir (str): directory to which to export the DAGMC output file | |||
(defaults to empty string). | |||
""" | |||
init_cubit() |
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.
Similar question as above about initialization.
def merge_layer_surfaces(self): | ||
"""Merges ParaStell in-vessel component surfaces in Coreform Cubit based on | ||
surface IDs rather than imprinting and merging all. Assumes that the | ||
radial_build dictionary is ordered radially outward. Note that overlaps | ||
between magnet volumes and in-vessel components will not be merged in this | ||
workflow. | ||
""" | ||
# Tracks the surface id of the outer surface of the previous layer | ||
prev_outer_surface_id = None | ||
|
||
for data in self.invessel_build.radial_build.values(): | ||
|
||
inner_surface_id, outer_surface_id = ( | ||
orient_spline_surfaces(data['vol_id']) | ||
) | ||
|
||
# Conditionally skip merging (first iteration only) | ||
if prev_outer_surface_id is None: | ||
prev_outer_surface_id = outer_surface_id | ||
else: | ||
cubit.cmd( | ||
f'merge surface {inner_surface_id} {prev_outer_surface_id}' | ||
) | ||
prev_outer_surface_id = outer_surface_id | ||
|
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 should be noted that unless _import_ivb_step
in parastell.py
is called, the radial_build
dictionary will not have vol_id
keys in its subdictionaries, which is why I originally had it as a non-member function that used a separate dictionary input.
Upon reflection, though, I think this is better since that failure mechanism is built-in. We should maybe add some error block that captures that failure though.
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 was on the fence about making this a member function. In the end, I thought this was cleaner. On one hand, it's true that you need to have run _import_ivb_step()
, but you also need to have an InvesselBuild
object to do this, so it makes sense to be a member function.
src/parastell.py
Outdated
from src.utils import invessel_build_def, magnets_def, source_def, | ||
dagmc_export_def |
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.
Since these imports are on separate lines, we'll need some way to make Python recognize that they are all from the same script, such as parentheses surrounding the imports or a \
at the line break
@@ -131,6 +145,14 @@ def construct_invessel_build(self, invessel_build): | |||
self.invessel_build.populate_surfaces() | |||
self.invessel_build.calculate_loci() | |||
self.invessel_build.generate_components() | |||
|
|||
def export_invessel_build(self, ivb_dict): |
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 each of these export methods, should the corresponding dictionary be stored as a member variable in the corresponding construction method so that users don't need to add it again as an argument?
Alternatively, we could remove the export-related variables from the corresponding dictionaries and use them as arguments in the export functions instead.
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 thought about doing the latter, but it is less robust against making changes to the content of the dictionary.
I'm comfortable with leaving it as is since the construct methods and export methods then have similar signatures and I think it makes it pretty easy to follow.
ivb_dict = invessel_build_def.copy() | ||
ivb_dict.update(invessel_build) |
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.
Without incorporating the default dictionaries in the construction methods, there will be no default parameters defined for the input dictionaries should the user choose to interface with ParaStell via Python rather than YAML. Users would need to define every parameter themselves.
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.
Couldn't they do it the same way we do it here? Load the defaults from utils
and then overwrite as they choose?
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.
Certainly! Just a tad less streamlined from a UI perspective.
I think I addressed the bugs that were noted, and don't think other changes are necessary. |
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.
Going through the tests, there were several small issues regarding syntax. I also have a question regarding the incorporation of the default DAGMC export dictionary (see below).
Can confirm that with suggested changes, all tests pass.
tests/test_invessel_build.py
Outdated
import read_vmec | ||
|
||
import src.invessel_build as ivb |
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.
Importing in this order leads to a library linking issue for Cubit since Cubit ends up getting imported after read_vmec
.
It's not pythonic but to fix, src.invessel_build
can be imported before read_vmec
. Note that nothing needs to be changed in the actual invessel_build
script.
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.
Since default dictionaries are no longer applied to Python input, need to specify all input parameters in corresponding dictionaries.
For invessel_build
, need to add 'scale'
, 'export_cad_to_dagmc'
, 'plasma_mat_tag'
, 'sol_mat_tag'
, 'dagmc_filename'
, and 'export_dir'
keys.
For magnets
, need to add 'scale'
, 'step_filename'
, 'mat_tag'
, 'mesh_filename'
, and 'export_dir'
keys.
For source
, need to add 'scale'
, 'filename'
, and 'export_dir'
keys.
Alternatively, you can import the default dictionaries from utils.py
and modify them or copy and update the dictionaries as is done in the parastell()
function of parastell.py
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, I couldn't comment on specific lines of this file (presumably because they weren't changed) so I commented on the file itself.
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.
Is there a particular reason for using the default dictionaries in the parastell()
function rather than the original implementation?
As someone who will likely be using ParaStell via the Python interface rather than YAML in order to use NumPy operations and other math to define the thickness matrices, it would be nice to have the default dictionaries apply there as well to simplify input.
By implementing these changes to the default dictionaries, there is loss of functionality for Python users, whereas in the original way, the same functionality applies for both Python and YAML users.
src/parastell.py
Outdated
export_dict = dagmc_export_def.copy() | ||
export_dict.update(dagmc_export) |
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.
Any particular reason that the default DAGMC export dictionary is incorporated here and not in the parastell()
function like the other default dictionaries?
Co-authored-by: connoramoreno <[email protected]>
Co-authored-by: connoramoreno <[email protected]>
In hindsight, I should have had you just merge the PR and then make additional commits on the original branch :) |
Thanks @gonuke |
Some final input on the IVC OO update
Here are a number of changes to the latest update to streamline a number of things. I used a number of small commits to show the individual changes, mostly distinct from each other. NOTE: this PR will update the
ivc_oo
branch thus changing PR #55None of this has been tested since I don't have a robust testing environment for the whole process, so there may be some typo bugs.