-
-
Notifications
You must be signed in to change notification settings - Fork 169
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
Add global/meshless data #1549
base: develop
Are you sure you want to change the base?
Add global/meshless data #1549
Conversation
0603299
to
cf02bf3
Compare
The many changes are due to the github pr pointing to develop-3.0.0 instead of develop. |
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.
Had a first more thorough look at this. Nice that it works for simple problems already 👍
Please rebase often. A few recent changes might have a big influence here. Good news: I think they simplify things.
The amount of code duplication looks a bit unfortunate. Maybe we could reduce this by defining a common interface for both data types (mesh-based and global)?
@fsimonis Any quick suggestions?
Connected to the discussion in #202, "size" is currently fixed at 1. In my opinion, this is completely OK as a first step. Let's only try to generalize this later if required.
Probably clear, but we need to increase test coverage, especially tests that combine global and mesh-based data. Also, the combination with waveform iteration and data initialization needs testing.
In general, please don't commit commented-out code. Only leads to confusion in the long run.
There is actually no real difference between |
Yes agree; I also felt and suggested the same back in January. Will check now if changing all And actually this is only one of the multiple classes/structs associated with global data that are just slightly modified equivalents of their mesh-data cousins. So there is more potential for removing code duplication, but others might not be so straightfoward as reusing |
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 added a few comments on the question whether there should be a GlobalDataContext
or rather a GlobalReadDataContext
and GlobalWriteDataContext
.
* - GlobalDataContext is basically a stripped-down equivalent of DataContext. | ||
* Unlike DataContext, it has no associated mappings or meshes. | ||
*/ | ||
class GlobalDataContext { |
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.
Why does GlobalDataContext
not inherit from DataContext
? (compared to ReadDataContext
and WriteDataContext
)
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.
DataContext
has a pointer _mesh
and mesh-associated query functions which were not needed for global, so I created a new GlobalDataContext
(just like GlobalData
was created instead of reusing Data
).
But now following the same philosophy of getting rid of GlobalData
and making Data
itself versatile, we can do the same here, i.e., reuse DataContext
for global by for e.g. setting _mesh
to nullptr in case of global contexts.
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.
But now following the same philosophy of getting rid of
GlobalData
and makingData
itself versatile, we can do the same here, i.e., reuseDataContext
for global by for e.g. setting_mesh
to nullptr in case of global contexts.
Sounds to me like a risky approach: We then get a general Data
that is either implicitly global (has, for example, empty gradients and no _mesh
) or lives on a mesh. To me this sounds like there should be an AbstractData
which provides the base for MeshData
and GlobalData
. But not sure about all the implications this might have, 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.
For now I've made Data
work for both mesh and global datas, and it looks good.
Regarding an AabstractData
: The current Data
class has no knowledge of any mesh (Datas don't point to any meshes. Only meshes point to their Datas).
Since Data
is already dumb, it makes sense to me to use it as it is for both mesh-associated and global use cases.
33552c0
to
0576ed3
Compare
* @param[in] mappingContext Context of the mapping | ||
* @param[in] meshContext Context of mesh this mapping is mapping from or to | ||
*/ | ||
virtual void appendMappingConfiguration(MappingContext &mappingContext, const MeshContext &meshContext) = 0; |
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.
Explanation: This function is removed because Global read/write DataContexts inherit from DataContext
, but don't implement appendMappingConfiguration(...)
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.
But then you have to declare this function in ReadDataContext
and WriteDataContext
. We could, of course, introduce an intermediate layer LocalDataContext
just for this purpose, but this looks overengineered. You can also just implement it in Read/WriteGlobalDataContext
and trigger an assertion, if somebody tries to call the function.
In the end this is a hint for some problem with the class design, but I think we can live with it.
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 am really sorry, but I think we need another rebase. But those massive changes should soon be over 🙈
In general, please resolve done conversations. Such that we can keep a better overview of what we still need to do.
To reduce some of the code duplication here (e.g. convergence measures), maybe we could restrict the feature to explicit coupling for the moment??
Before merging we definitely need:
- Integration tests that combine mesh-based and global data
- Mark feature as experimental
Open TODOS that could also come later, but should be documented in a follow-up issue:
- Implementation in Fortran and C bindings
- Get rid of the hacks
- Support for parallel participants
- Support implicit coupling
- Package name
mesh
55ca9fa
to
3fac740
Compare
37dd7a7
to
3453ef0
Compare
We can also allow global data exchange during implicit coupling without offering convergence measures for global data. |
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 we save a lot of code duplication if we create an abstract bases class CouplingData
from which then the current CouplingData
(needs a different name then) and GlobalCouplingData
inherits? Then, we don't need a GlobalDataMap
etc
Ah yes. There was actually nothing new in GlobalCouplingData, so I've removed it altogether. Drawback: No more |
Sounds good 👍
-> sth for the follow-up issue |
072668c
to
04d3600
Compare
…d rename `waveform-order` to `waveform-degree`
0240f05
to
c179e93
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.
In a good-enough state to merge from my perspective. Remaining TODOs are documented in #1716.
Thanks for the patient and extensive contribution @kanishkbh 🚀
@BenjaminRodenberg Please check again the interplay with waveforms. Are we missing anything?
@fsimonis Please have a brief general look again. Anything we might regret in the future?
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 some tests using a MultiCouplingScheme
or CompositionalCouplingScheme
would be good, because this is often a place where the integration of experimental features causes problems. Besides that: I don't see a problem right now. The amount of code-duplication will require some refactoring in the future, but that's ok.
src/cplscheme/BaseCouplingScheme.cpp
Outdated
if (not data->isGlobal()) { | ||
meshID = data->getMeshID(); | ||
} else { | ||
meshID = -1; |
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 something like mesh::GLOBAL_DATA_ID
would be better here. (compare to time::Storage::WINDOW_START
)
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.
Agree. Added a mesh::Mesh::GLOBAL_DATA_MESH_ID{-2}
(-1 is reserved for MESH_ID_UNDEFINED
)
// TODO: store mesh and global data together in a `DataMap _allData ` (currently produces a bug), see https://github.com/precice/precice/issues/1716 | ||
if (isGlobal) { | ||
if (!utils::contained(id, _allGlobalData)) { // data is not used by this coupling scheme yet, create new CouplingData | ||
_allGlobalData.emplace(id, ptrCplData); | ||
} else { // data is already used by another exchange of this coupling scheme, use existing CouplingData | ||
ptrCplData = _allGlobalData[id]; | ||
} | ||
} else { // mesh data | ||
if (!utils::contained(id, _allMeshData)) { // data is not used by this coupling scheme yet, create new CouplingData | ||
_allMeshData.emplace(id, ptrCplData); | ||
} else { // data is already used by another exchange of this coupling scheme, use existing CouplingData | ||
ptrCplData = _allMeshData[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.
Any chance to try to merge _allGlobalData
and _allMeshData
like suggested above? I guess otherwise we will just keep it the way it is for a very long time.
for (auto &data : _allData | boost::adaptors::map_values) { | ||
for (auto &data : _allMeshData | boost::adaptors::map_values) { | ||
data->moveToNextWindow(); | ||
} | ||
for (auto &data : _allGlobalData | boost::adaptors::map_values) { | ||
data->moveToNextWindow(); | ||
} |
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 you cannot put both into _allData
, maybe try to use a function allData()
that returns _allMeshData + _allGlobalData
? (maybe this also leads to the same bug again)
/// All send and receive data as a map "data ID -> data" | ||
DataMap _allData; | ||
/// All send and receive mesh-associated data as a map "data ID -> data" | ||
DataMap _allMeshData; | ||
/// All send and receive global data as a map "data ID -> data" | ||
DataMap _allGlobalData; |
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 suggest to add the comment TODO ...
here instead.
* @param[in] mappingContext Context of the mapping | ||
* @param[in] meshContext Context of mesh this mapping is mapping from or to | ||
*/ | ||
virtual void appendMappingConfiguration(MappingContext &mappingContext, const MeshContext &meshContext) = 0; |
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.
But then you have to declare this function in ReadDataContext
and WriteDataContext
. We could, of course, introduce an intermediate layer LocalDataContext
just for this purpose, but this looks overengineered. You can also just implement it in Read/WriteGlobalDataContext
and trigger an assertion, if somebody tries to call the function.
In the end this is a hint for some problem with the class design, but I think we can live with it.
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 prefer to refactor this PR before we merge it as I see the risk of introducing a lot of preventable duplication, which could easily diverge.
We definitely still need:
- Tests for Multi Coupling schemes
- Tests for Compositional schemes
Refactoring on my list:
- Simplify the implementation of the configuration
- Merge data and global data containers
- Simplify DataContexts
- Investigate if we can make Data self-aware if it is global or not.
@@ -227,16 +240,26 @@ void BaseCouplingScheme::initializeWithZeroInitialData(const DataMap &receiveDat | |||
} | |||
} | |||
|
|||
PtrCouplingData BaseCouplingScheme::addCouplingData(const mesh::PtrData &data, mesh::PtrMesh mesh, bool requiresInitialization, bool communicateSubsteps) | |||
PtrCouplingData BaseCouplingScheme::addCouplingData(const mesh::PtrData &data, mesh::PtrMesh mesh, bool requiresInitialization, bool communicateSubsteps, bool isGlobal) |
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.
This would become way simpler if Data would know if it is global or attached to a mesh.
Multi coupling is not yet supported in this PR, see #1716 |
In #1742, we moved the So At this point, we can either make the vectorial dimension explicit, <global-data:scalar />
<global-data:vector2d />
<global-data:vector3d /> or we make the entire dimensionality explicit, allowing global data of any dimensions pretty naturally and requiring only a single tag. <global-data dimensions="1" />
<global-data dimensions="2" />
<global-data dimensions="3" /> |
Good point. Alternatively, if we want to keep things simple here and extend later, we could restrict the feature to scalar first. <global-data:scalar /> In principle, <global-data dimensions="n" /> sounds good, but might lead to (much?) additional work if we allow any |
Sounds inconsistent with the
Sounds more natural.
I like the "let's try things slowly" approach.
Why the too much additional work (compared to |
Just had a look again: It should actually be easier than I originally expected. Might only need changes in the |
Adds functionality to exchange data that is not associated with any mesh. So far the name is "global-data".
Motivation and additional information
Closes #202
Main changes of this PR
API
Configuration
global-data
Allow implicit coupling to configure convergence measures for global data without specifying any mesh name.(Open TODO for a future PR)Data
Add aGlobalData
class (meshless equivalent ofData
).DataConfiguration
:global-data
tag._globalData
inDataConfiguration
to store global data here asData
objects.Participants
GlobalRead/WriteDataContexts
class (meshless and mappingless equivalents ofRead/WriteDataContext
) which inherit fromDataContext
.ParticipantState
andParticipantConfiguration
: Configure and store global read/write contexts.Coupling
Add aAdd anGlobalCouplingData
class, analogous toCouplingData
for mesh data.isGlobal
attribute toCouplingData
and use it for global coupling as well.CouplingSchemeConfiguration
: Add a struct to store global exchanges and functions for global data (analogous to mesh-associated data).Com
M2N
: always use intracom in case of global data.Open Questions and TODOs:
Documented in #1716
Author's checklist
pre-commit
hook to prevent dirty commits and usedpre-commit run --all
to format old commits.make changelog
if there are user-observable changes since the last release.Reviewers' checklist