-
Notifications
You must be signed in to change notification settings - Fork 44
[Possibly breaking] Require all containers with the same base name in a DataCollection be made from the same field set
#1449
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: develop
Are you sure you want to change the base?
Changes from 4 commits
98fbd36
b60c3dd
e2a76be
0160f61
aa3dc54
0ebf11d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,14 +15,17 @@ | |
|
|
||
| #include <map> | ||
| #include <memory> | ||
| #include <set> | ||
| #include <stdexcept> | ||
| #include <string> | ||
| #include <vector> | ||
|
|
||
| #include "basic_types.hpp" | ||
| #include "globals.hpp" | ||
| #include "interface/variable.hpp" | ||
| #include "utils/concepts_lite.hpp" | ||
| #include "utils/error_checking.hpp" | ||
| #include "utils/unique_id.hpp" | ||
|
|
||
| namespace parthenon { | ||
| class Mesh; | ||
|
|
@@ -53,36 +56,37 @@ class DataCollection { | |
|
|
||
| void SetMeshPointer(Mesh *pmesh) { pmy_mesh_ = pmesh; } | ||
|
|
||
| template <class SRC_t, typename ID_t> | ||
| std::shared_ptr<T> &Add(const std::string &name, const std::shared_ptr<SRC_t> &src, | ||
| const std::vector<ID_t> &fields, const bool shallow) { | ||
| auto key = GetKey(name, src); | ||
| auto it = containers_.find(key); | ||
| if (it != containers_.end()) { | ||
| if (fields.size() && !(it->second)->CreatedFrom(fields)) { | ||
| PARTHENON_THROW(key + " already exists in collection but fields do not match."); | ||
| } | ||
| return it->second; | ||
| } | ||
|
|
||
| auto c = std::make_shared<T>(name); | ||
| c->Initialize(src, fields, shallow); | ||
|
|
||
| containers_[key] = c; | ||
| return containers_[key]; | ||
| } | ||
|
|
||
| template <class SRC_t, typename ID_t = std::string> | ||
| std::shared_ptr<T> &Add(const std::string &label, const std::shared_ptr<SRC_t> &src, | ||
| const std::vector<ID_t> &fields = {}) { | ||
| return Add(label, src, fields, false); | ||
| return AddImpl(label, src, fields, false); | ||
| } | ||
|
|
||
| template <class SRC_t, typename ID_t> | ||
| std::shared_ptr<T> &Add(const std::string &label, const std::shared_ptr<SRC_t> &src, | ||
| const std::vector<ID_t> &fields, const bool shallow) { | ||
| return AddImpl(label, src, fields, shallow); | ||
| } | ||
|
|
||
| template <class SRC_t, typename ID_t = std::string> | ||
| std::shared_ptr<T> &AddShallow(const std::string &label, | ||
| const std::shared_ptr<SRC_t> &src, | ||
| const std::vector<ID_t> &fields = {}) { | ||
| return Add(label, src, fields, true); | ||
| return AddImpl(label, src, fields, true); | ||
| } | ||
|
|
||
| template <class SRC_t, typename ID_t = Uid_t> | ||
| std::shared_ptr<T> &AddFromSet(const std::string &label, | ||
| const std::shared_ptr<SRC_t> &src, | ||
| const std::set<ID_t> &fields) { | ||
| return AddImpl(label, src, fields, false); | ||
| } | ||
|
|
||
| template <class SRC_t, typename ID_t = Uid_t> | ||
| std::shared_ptr<T> &AddShallowFromSet(const std::string &label, | ||
| const std::shared_ptr<SRC_t> &src, | ||
| const std::set<ID_t> &fields) { | ||
| return AddImpl(label, src, fields, true); | ||
| } | ||
|
|
||
| auto &Stages() { return containers_; } | ||
|
|
@@ -112,6 +116,15 @@ class DataCollection { | |
| std::shared_ptr<T> &Get(const std::string &name = "base"); | ||
| const std::shared_ptr<T> &Get(const std::string &name = "base") const; | ||
|
|
||
| // The field list (as a canonical variable-uid set) that the named container was created | ||
| // from. Every container sharing a base name is created from the same list (see the | ||
| // warning in Add). If the name has never been added, returns a static empty set. | ||
| const std::set<Uid_t> &GetCreationFields(const std::string &name) const { | ||
| static const std::set<Uid_t> empty; | ||
| const auto nit = name_creation_fields_.find(name); | ||
| return nit == name_creation_fields_.end() ? empty : nit->second; | ||
| } | ||
|
Yurlungur marked this conversation as resolved.
|
||
|
|
||
| void Set(const std::string &name, std::shared_ptr<T> &d) { containers_[name] = d; } | ||
|
|
||
| // Legacy methods that are specific to MeshData | ||
|
|
@@ -122,6 +135,54 @@ class DataCollection { | |
| void clear() { containers_.clear(); } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should the
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, good catch. |
||
|
|
||
| private: | ||
| template <class SRC_t, class Fields_t> | ||
| std::shared_ptr<T> &AddImpl(const std::string &name, const std::shared_ptr<SRC_t> &src, | ||
| const Fields_t &fields, const bool shallow) { | ||
| auto key = GetKey(name, src); | ||
| auto it = containers_.find(key); | ||
| if (it != containers_.end()) { | ||
| // Existing container. An explicit field list must match what the container was | ||
| // actually created from (checked against the container itself, which also catches | ||
| // containers built by hand or through a different DataCollection); an empty list | ||
| // means "all fields"/"don't check" and always passes. | ||
|
Yurlungur marked this conversation as resolved.
|
||
| if (fields.size() && !(it->second)->CreatedFrom(fields)) | ||
| PARTHENON_THROW(key + " already exists in collection but fields do not match."); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be useful for debugging to print the source label (if we know it) and both sets of fields. |
||
| return it->second; | ||
| } | ||
|
|
||
| using ID_t = typename Fields_t::value_type; | ||
| auto to_uid = [](const ID_t &f) -> Uid_t { | ||
| if constexpr (std::is_same_v<ID_t, std::string>) | ||
| return Variable<Real>::GetUniqueID(f); | ||
| else | ||
| return f; | ||
| }; | ||
|
|
||
| // Track the field list (as a canonical uid set) each container name is created from, | ||
| // so the DataCollection is the single source of truth for it (see GetCreationFields). | ||
|
lroberts36 marked this conversation as resolved.
Outdated
|
||
| // Containers sharing a base name but built from different sources get distinct keys, | ||
|
lroberts36 marked this conversation as resolved.
Outdated
|
||
| // so the per-key CreatedFrom check above cannot compare them; this does. All | ||
|
lroberts36 marked this conversation as resolved.
Outdated
|
||
| // instances of a name must be created from the same list -- fail if not. | ||
|
lroberts36 marked this conversation as resolved.
Outdated
|
||
| std::set<Uid_t> created; | ||
| for (const auto &f : fields) | ||
| created.insert(to_uid(f)); | ||
| auto nit = name_creation_fields_.find(name); | ||
| if (nit == name_creation_fields_.end()) { | ||
| name_creation_fields_[name] = created; | ||
| } else if (nit->second != created) { | ||
| PARTHENON_THROW( | ||
| "Container \"" + name + | ||
| "\" is being created from different field lists on different sources. All " | ||
| "instances sharing a name must be created from the same field list."); | ||
| } | ||
|
Comment on lines
+173
to
+177
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be useful for debugging to print the source label (if we know it) and both sets of fields. |
||
|
|
||
| std::vector<Uid_t> uids(created.begin(), created.end()); | ||
| auto c = std::make_shared<T>(name); | ||
| c->Initialize(src, uids, shallow); | ||
| containers_[key] = c; | ||
| return containers_[key]; | ||
| } | ||
|
|
||
| std::string GetKey(const std::string &stage_label, | ||
| const std::shared_ptr<BlockListPartition> &in) const; | ||
| std::string GetKey(const std::string &stage_label, | ||
|
|
@@ -133,6 +194,7 @@ class DataCollection { | |
|
|
||
| Mesh *pmy_mesh_; | ||
| std::map<std::string, std::shared_ptr<T>> containers_; | ||
| std::map<std::string, std::set<Uid_t>> name_creation_fields_; | ||
| }; | ||
|
|
||
| } // namespace parthenon | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -146,7 +146,9 @@ class BiCGSTABSolver : public SolverBase, BiCGSTABSolverCounter { | |
| return preconditioner.AddSetupTasks(tl, dependence, partition, pmesh); | ||
| } else if (params_.precondition_type == Preconditioner::Diagonal) { | ||
| auto partitions = pmesh->GetDefaultBlockPartitions(); | ||
| auto &md = pmesh->mesh_data.Add(container_base, partitions[partition]); | ||
| auto &md = | ||
| pmesh->mesh_data.AddFromSet(container_base, partitions[partition], | ||
| pmesh->mesh_data.GetCreationFields(container_base)); | ||
| auto &md_diag = pmesh->mesh_data.Add(container_diag, md, sol_fields); | ||
| return tl.AddTask(dependence, &equations_t::SetDiagonal, &eqs_, md, md_diag); | ||
| } else { | ||
|
|
@@ -161,7 +163,9 @@ class BiCGSTABSolver : public SolverBase, BiCGSTABSolverCounter { | |
| auto partitions = pmesh->GetDefaultBlockPartitions(); | ||
| // Should contain all fields necessary for applying the matrix to a give state vector, | ||
| // e.g. diffusion coefficients and diagonal, these will not be modified by the solvers | ||
| auto &md_base = pmesh->mesh_data.Add(container_base, partitions[partition]); | ||
| auto &md_base = | ||
| pmesh->mesh_data.AddFromSet(container_base, partitions[partition], | ||
| pmesh->mesh_data.GetCreationFields(container_base)); | ||
| // Container in which the solution is stored and with which the downstream user can | ||
|
Comment on lines
+166
to
169
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this imply that this is the recommend downstream pattern now, too?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, I don't think this is the generally recommended pattern unless you need to do something specifically like what is done in multigrid where someone creates containers in one place from a set of partitions/meshdata and then somewhere else you need to create them from a different set of partitions/meshdata. |
||
| // interact. This container only requires the fields in sol_fields | ||
| auto &md_u = pmesh->mesh_data.Add(container_u, partitions[partition], sol_fields); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.