-
Notifications
You must be signed in to change notification settings - Fork 91
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
DofManager cleanup #1412
DofManager cleanup #1412
Conversation
d896158
to
4795a33
Compare
@rrsettgast @joshua-white @castelletto1 @andrea-franceschini I don't know who to ask for a review, since nobody really looks into the guts of DofManager much I think, and this is mostly just code cleanup. Feel free to (not) leave a review. |
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 still think we should have a common set of looping patterns between the physics solvers and the DOFmanager
. I think my previous proposal to move these out of the DofManager
must have fallen flat. Perhaps we can develop a separate entity that will hold all the looping patterns for both the DOFManager
and the physics solvers to use.
set( GEOSX_LA_INTERFACE "Hypre" ) | ||
set( GEOSX_LA_INTERFACE_HYPRE ON ) | ||
set( GEOSX_LA_INTERFACE_TRILINOS OFF ) | ||
set( GEOSX_LA_INTERFACE_PETSC OFF ) |
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.
Aren't these the defaults in geosxoptions.cmake
?
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.
They are, but they're overridden by user host-config. One of the recent PRs actually committed changes to doxygen/GeosxConfig.hpp
, reverting it to Trilinos
once again, because we were missing enforcement of these LAI parameters here.
dofManager.addField( m_fieldName, | ||
DofManager::Location::Node, | ||
1, | ||
targetRegionNames() ); |
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 targetRegionNames()
used if the DOF is on a node?
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.
Yes. DOF index will only be assigned to nodes that are within or adjacent to target regions (although the index array obviously is allocated on all nodes).
/** | ||
* @brief @return the size of the map along first dimension | ||
* @tparam T type of map element | ||
* @param map reference to the map | ||
*/ | ||
template< typename T > | ||
inline localIndex size0( arrayView1d< arrayView1d< T const > const > const & map ) | ||
{ | ||
return map.size(); | ||
} | ||
|
||
/** | ||
* @copydoc size0(arrayView1d< arrayView1d< T const > const > const &) | ||
* @tparam USD unit-stride dimension of the map | ||
*/ | ||
template< typename T, int USD > | ||
inline localIndex size0( arrayView2d< T, USD > const & map ) | ||
{ | ||
return map.size( 0 ); | ||
} | ||
|
||
/** | ||
* @copydoc size0(arrayView1d< arrayView1d< T const > const > const &) | ||
*/ | ||
template< typename T > | ||
inline localIndex size0( ArrayOfArraysView< T const > const & map ) | ||
{ | ||
return map.size(); | ||
} | ||
|
||
/** | ||
* @copydoc size0(arrayView1d< arrayView1d< T const > const > const &) | ||
*/ | ||
template< typename T > | ||
inline localIndex size0( ArrayOfSetsView< T const > const & map ) | ||
{ | ||
return map.size(); | ||
} |
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 these could be a single function if you wanted
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.
Between arrayView1d< arrayView1d>
, ArrayOfSetsView
and ArrayOfArraysView
for sure, but arrayView2d
is different (size()
with no arguments does not do what I want). I chose to explicitly spell out all supported types here rather than make a template function to handle 3 cases together (I didn't even need T
parameter here tbh, since mesh maps are always localIndex
). Or did you have something else in mind?
v--; | ||
v |= v >> 1; | ||
v |= v >> 2; | ||
v |= v >> 4; | ||
v |= v >> 8; | ||
v |= v >> 16; | ||
v++; | ||
return v; |
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.
does v
need to be unsigned
for this to always work?
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.
Yes, will fix
arrayView1d< string const > const & regions, | ||
bool const symmetric ); | ||
bool symmetric = 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.
Would it be better or worse to not specify a default here?
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 true
is a reasonable default that is used close to 100% of the time. If one way coupling is assumed, don't people tend to do operator splitting instead of a monolithic matrix approach?
As far as sparsity generation is concerned, we're sort of moving towards having these looping patterns abstracted similar to current FEM kernel hierarchy. We'll hopefully have something similar for stencil-based FV, and then all sparsity-related stuff will be removed from The other use of mesh looping here is enumerating dofs, which entails visiting each locally owned mesh object (node, face, element) within target regions exactly once. This is not unlike looping over |
4795a33
to
54d8855
Compare
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.
Some missed the action comment!
@@ -52,7 +52,7 @@ namespace mgr | |||
*/ | |||
template< typename STRATEGY > | |||
void setStrategy( LinearSolverParameters::MGR const & params, | |||
arrayView1d< localIndex const > const & numComponentsPerField, | |||
arrayView1d< integer const > const & numComponentsPerField, |
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.
Hi @klevzoff !
I notice that you change localIndex
to integer
in your patch.
I always thought that behind the naming localIndex
and globalIndex
there was some kind of idea that those indices we intrinsically not the same kind of indices: some local to the MPI rank, some global to the simulation.
In some sense, it was like we were using some Hungarian notation for indices. (Not exactly since we use it on types and not on variable names, but there is some flavor).
(It's true that here numComponentsPerField
is not indeed an index.)
We had spoken about having some unit
system inside of GEOSX.
Do you think this could also be a use case for this unit
stuff?
poke @rrsettgast
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.
Hi @TotoGaz ! What you describe for localIndex
vs globalIndex
is true. Using either of these types to represent number of components per degree-of-freedom (or component index for that matter) doesn't feel right, because it doesn't scale with number of mesh objects (either local or global), even though it often gets added to those things to form a new (local or global) index. It was a historical mistake of me misusing localIndex
for all kinds of things where I shouldn't have.
Doing what you suggest in my mind implies introducing strong types for indices, and while it's not a bad idea per se, I imagine this being a huge headache in terms of implementation, especially considering that index arrays are part of interop with TPLs (e.g. directly handed off to linear algebra packages).
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.
Doing what you suggest in my mind implies introducing strong types for indices, and while it's not a bad idea per se, I imagine this being a huge headache in terms of implementation, especially considering that index arrays are part of interop with TPLs (e.g. directly handed off to linear algebra packages).
Indeed that may be an issue.
There was this idea to typedef
our type to unit<int>
or int
based on some compilation flag.
Maybe there are some unit
libs that allow some automatic conversion from their unit<int>
to int
(maybe an option? Maybe units::no_dim<int> -> int
?). But what about pointers to data ? This needs to be investigated as part of the more global discussion on units
.
@@ -247,7 +247,7 @@ void computeRigidBodyModes( MeshLevel const & mesh, | |||
array1d< globalIndex > globalNodeList; | |||
for( localIndex k = 0; k < LvArray::integerConversion< localIndex >( selection.size() ); ++k ) | |||
{ | |||
if( dofManager.getLocation( selection[k] ) == DofManager::Location::Node ) | |||
if( dofManager.location( selection[k] ) == DofManager::Location::Node ) |
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 problem with this
if( dofManager.location( selection[k] ) == DofManager::Location::Node ) | |
if( dofManager.getLocation( selection[k] ) == DofManager::Location::Node ) |
is that with the get
prefix, without knowing what I am talking about, I know that I am probably accessing some immutable component (or something like that) of location
.
Without get
, it's not obvious anymore if I am setting location
to a certain value and then use some return type while passing through. It's an additional cost for new comers.
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.
In this case I just made it consistent with other member functions that didn't use get
prefix (numComponents()
, rankOffset()
, etc.). I also just realized there is still one inconsistent member getKey()
left, but... "we'll get'em next time".
In general, I prefer thing()
and setThing()
for getter and setter, respectively. I think any mutating member function should contain an action verb, and a lack thereof signifies a "passive" getter or some kind of const inspection method. This seems to me like a pretty intuitive convention (though exceptions are possible, of course).
(For the record, I totally used to be in the get
/set
camp. My first OOP language was Java in ~2006, and this convention was prevalent there at the time. I think I shifted over time, especially as I looked more and more at modern C++ code bases and style guides).
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.
OK then!
Personally I am in the "think less" side. get
, set
and we're all set 😉. And also on rule with no exception: one function gets a verb and that's it.
Also, when in the IDE, you can just type get
and ask for completion. That's really convenient when you do not know where you are.
ComponentMask
abstraction that replaces the[loComp; hiComp)
pairs in methods that do component sub-setting (all vector-to-field and field-to-vector methods, as well asmakeRestrictor
), which allows for more flexible specification of component mapping (previously only a contiguous range). It acts like a simple dynamic-size bitset of fixed capacity (up to 64, so that it fits into a single unsigned 64-bit int), but is host-device marked so it can be used in device kernels.addField
andaddCoupling
methods (seems easy enough to just provide all parameters at all call sites)No change in functionality otherwise, but rebaseline required to a slight naming scheme change for dof index arrays - even though dof index array have a
NO_WRITE
flag, the wrapper name still appears (without data) in the restart file.