-
Notifications
You must be signed in to change notification settings - Fork 247
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
[Core] Remove push_back from ModelPart #12903
base: master
Are you sure you want to change the base?
Changes from 21 commits
dd02fc8
2bf1e96
2c5d23f
d5521ba
2f72e0c
1e98ea3
9c05b31
abbce15
71ae35f
6d34602
f1c4a6f
35c1874
13e87e7
a50fd2b
8a42759
93293e0
6adabf4
9082f96
d7d4734
d718a9a
4430f5e
d7e05de
fedc6b3
d642295
ee29e90
71e3074
1024156
a9e8219
abfdcab
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 |
---|---|---|
|
@@ -36,7 +36,10 @@ void PointsData::CreateNodes(NodesContainerType& rNodes) | |
const array_1d<double, 3>& r_coord = mCoords[i]; | ||
NodeType::Pointer p_node = Kratos::make_intrusive<NodeType>( | ||
mIds[i], r_coord[0], r_coord[1], r_coord[2]); | ||
rNodes.push_back(p_node); | ||
// here we can safely use the insert with the rNodes.end() as the hint | ||
// because, when reading, we can assume that it was written in the | ||
// sorted order within HDF5. | ||
rNodes.insert(rNodes.end(), p_node); | ||
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. same 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. Same comment as before |
||
} | ||
KRATOS_CATCH(""); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,274 @@ | ||
// | / | | ||
// ' / __| _` | __| _ \ __| | ||
// . \ | ( | | ( |\__ ` | ||
// _|\_\_| \__,_|\__|\___/ ____/ | ||
// Multi-Physics | ||
// | ||
// License: BSD License | ||
// Kratos default license: kratos/license.txt | ||
// | ||
// Main authors: Suneth Warnakulasuriya | ||
// | ||
|
||
// System includes | ||
#include <vector> | ||
|
||
// External includes | ||
#include <benchmark/benchmark.h> | ||
|
||
// Project includes | ||
#include "containers/model.h" | ||
#include "containers/pointer_vector_set.h" | ||
#include "includes/indexed_object.h" | ||
#include "includes/key_hash.h" | ||
#include "includes/model_part.h" | ||
#include "includes/smart_pointers.h" | ||
#include "utilities/assign_unique_model_part_collection_tag_utility.h" | ||
|
||
namespace Kratos { | ||
|
||
static void BM_ModelPartCreateNewNode(benchmark::State& state) { | ||
for (auto _ : state) { | ||
const IndexType input_size = state.range(0); | ||
|
||
state.PauseTiming(); | ||
|
||
auto model = Model(); | ||
auto& r_model_part = model.CreateModelPart("test"); | ||
|
||
state.ResumeTiming(); | ||
|
||
for (IndexType i = 0; i < input_size; ++i) { | ||
r_model_part.CreateNewNode(i + 1, 0.0, 0.0, 0.0); | ||
} | ||
} | ||
} | ||
|
||
|
||
static void BM_ModelPartAddNodesToRootFromRange1(benchmark::State& state) { | ||
for (auto _ : state) { | ||
const IndexType input_size = state.range(0); | ||
const bool fill_existing = state.range(1) == 1; | ||
|
||
state.PauseTiming(); | ||
|
||
auto model = Model(); | ||
auto& r_model_part = model.CreateModelPart("test"); | ||
|
||
std::vector<ModelPart::NodeType::Pointer> nodes_to_be_added, existing_nodes; | ||
if (!fill_existing) { | ||
nodes_to_be_added.reserve(input_size); | ||
} else { | ||
nodes_to_be_added.reserve(input_size / 2 + 1); | ||
existing_nodes.reserve(input_size / 2 + 1); | ||
} | ||
|
||
// doing it in reverse to make sure a proper sort is done always | ||
for (IndexType i = input_size; i > 0; --i) { | ||
auto p_node = Kratos::make_intrusive<NodeType>(i, 0.0, 0.0, 0.0); | ||
if (!fill_existing || i % 2 == 0) { | ||
nodes_to_be_added.push_back(p_node); | ||
} else { | ||
existing_nodes.push_back(p_node); | ||
} | ||
} | ||
r_model_part.AddNodes(existing_nodes.begin(), existing_nodes.end()); | ||
state.ResumeTiming(); | ||
|
||
// benchmarking to add nodes for already existing model part with nodes | ||
r_model_part.AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); | ||
} | ||
} | ||
|
||
static void BM_ModelPartAddNodesToRootFromRange2(benchmark::State& state) { | ||
for (auto _ : state) { | ||
const IndexType input_size = state.range(0); | ||
const bool fill_existing = state.range(1) == 1; | ||
|
||
state.PauseTiming(); | ||
|
||
auto model = Model(); | ||
auto& r_model_part = model.CreateModelPart("test"); | ||
|
||
PointerVectorSet<ModelPart::NodeType, IndexedObject> nodes_to_be_added, existing_nodes; | ||
if (!fill_existing) { | ||
nodes_to_be_added.reserve(input_size); | ||
} else { | ||
nodes_to_be_added.reserve(input_size / 2 + 1); | ||
existing_nodes.reserve(input_size / 2 + 1); | ||
} | ||
|
||
// doing it in reverse to make sure a proper sort is done always | ||
for (IndexType i = 0; i < input_size; ++i) { | ||
auto p_node = Kratos::make_intrusive<NodeType>(i + 1, 0.0, 0.0, 0.0); | ||
if (!fill_existing || i % 2 == 0) { | ||
nodes_to_be_added.insert(nodes_to_be_added.end(), p_node); | ||
} else { | ||
existing_nodes.insert(existing_nodes.end(), p_node); | ||
} | ||
} | ||
r_model_part.AddNodes(existing_nodes.begin(), existing_nodes.end()); | ||
state.ResumeTiming(); | ||
|
||
// benchmarking to add nodes for already existing model part with nodes | ||
r_model_part.AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); | ||
} | ||
} | ||
|
||
static void BM_ModelPartAddNodesToSubSubFromRange1(benchmark::State& state) { | ||
for (auto _ : state) { | ||
const IndexType input_size = state.range(0); | ||
const bool fill_existing = state.range(1) == 1; | ||
|
||
state.PauseTiming(); | ||
|
||
auto model = Model(); | ||
auto& r_sub_sub_model_part = model.CreateModelPart("test").CreateSubModelPart("sub_test").CreateSubModelPart("sub_sub_test"); | ||
|
||
std::vector<ModelPart::NodeType::Pointer> nodes_to_be_added, existing_nodes; | ||
if (!fill_existing) { | ||
nodes_to_be_added.reserve(input_size); | ||
} else { | ||
nodes_to_be_added.reserve(input_size / 2 + 1); | ||
existing_nodes.reserve(input_size / 2 + 1); | ||
} | ||
|
||
// doing it in reverse to make sure a proper sort is done always | ||
for (IndexType i = 0; i < input_size; ++i) { | ||
auto p_node = Kratos::make_intrusive<NodeType>(i + 1, 0.0, 0.0, 0.0); | ||
if (!fill_existing || i % 2 == 0) { | ||
nodes_to_be_added.insert(nodes_to_be_added.end(), p_node); | ||
} else { | ||
existing_nodes.insert(existing_nodes.end(), p_node); | ||
} | ||
} | ||
r_sub_sub_model_part.AddNodes(existing_nodes.begin(), existing_nodes.end()); | ||
state.ResumeTiming(); | ||
|
||
r_sub_sub_model_part.AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); | ||
} | ||
} | ||
|
||
static void BM_ModelPartAddNodesToSubSubFromRange2(benchmark::State& state) { | ||
for (auto _ : state) { | ||
const IndexType input_size = state.range(0); | ||
const bool fill_existing = state.range(1) == 1; | ||
|
||
state.PauseTiming(); | ||
|
||
auto model = Model(); | ||
auto& r_sub_sub_model_part = model.CreateModelPart("test").CreateSubModelPart("sub_test").CreateSubModelPart("sub_sub_test"); | ||
|
||
std::vector<ModelPart::NodeType::Pointer> nodes_to_be_added, existing_nodes; | ||
if (!fill_existing) { | ||
nodes_to_be_added.reserve(input_size); | ||
} else { | ||
nodes_to_be_added.reserve(input_size / 2 + 1); | ||
existing_nodes.reserve(input_size / 2 + 1); | ||
} | ||
|
||
// doing it in reverse to make sure a proper sort is done always | ||
for (IndexType i = 0; i < input_size; ++i) { | ||
auto p_node = Kratos::make_intrusive<NodeType>(i + 1, 0.0, 0.0, 0.0); | ||
if (!fill_existing || i % 2 == 0) { | ||
nodes_to_be_added.insert(nodes_to_be_added.end(), p_node); | ||
} else { | ||
existing_nodes.insert(existing_nodes.end(), p_node); | ||
} | ||
} | ||
r_sub_sub_model_part.GetRootModelPart().AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); | ||
r_sub_sub_model_part.GetRootModelPart().AddNodes(existing_nodes.begin(), existing_nodes.end()); | ||
state.ResumeTiming(); | ||
|
||
r_sub_sub_model_part.AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); | ||
} | ||
} | ||
|
||
static void BM_ModelPartAddNodesToSubSubFromRange3(benchmark::State& state) { | ||
for (auto _ : state) { | ||
const IndexType input_size = state.range(0); | ||
const bool fill_existing = state.range(1) == 1; | ||
|
||
state.PauseTiming(); | ||
|
||
auto model = Model(); | ||
auto& r_sub_sub_model_part = model.CreateModelPart("test").CreateSubModelPart("sub_test").CreateSubModelPart("sub_sub_test"); | ||
|
||
std::vector<ModelPart::NodeType::Pointer> nodes_to_be_added, existing_nodes; | ||
if (!fill_existing) { | ||
nodes_to_be_added.reserve(input_size); | ||
} else { | ||
nodes_to_be_added.reserve(input_size / 2 + 1); | ||
existing_nodes.reserve(input_size / 2 + 1); | ||
} | ||
|
||
// doing it in reverse to make sure a proper sort is done always | ||
for (IndexType i = 0; i < input_size; ++i) { | ||
auto p_node = Kratos::make_intrusive<NodeType>(i + 1, 0.0, 0.0, 0.0); | ||
if (!fill_existing || i % 2 == 0) { | ||
nodes_to_be_added.insert(nodes_to_be_added.end(), p_node); | ||
} else { | ||
existing_nodes.insert(existing_nodes.end(), p_node); | ||
} | ||
} | ||
r_sub_sub_model_part.GetRootModelPart().AddNodes(nodes_to_be_added.begin(), nodes_to_be_added.end()); | ||
r_sub_sub_model_part.GetRootModelPart().AddNodes(existing_nodes.begin(), existing_nodes.end()); | ||
state.ResumeTiming(); | ||
|
||
r_sub_sub_model_part.AddNodes(r_sub_sub_model_part.GetRootModelPart().NodesBegin(), r_sub_sub_model_part.GetRootModelPart().NodesEnd()); | ||
} | ||
} | ||
|
||
static void BM_ModelPartAddNodesToSubSubFromId1(benchmark::State& state) { | ||
for (auto _ : state) { | ||
const IndexType input_size = state.range(0); | ||
const bool fill_existing = state.range(1) == 1; | ||
|
||
state.PauseTiming(); | ||
|
||
auto model = Model(); | ||
auto& r_root_model_part = model.CreateModelPart("test"); | ||
auto& r_sub_sub_model_part = r_root_model_part.CreateSubModelPart("sub_test").CreateSubModelPart("sub_sub_test"); | ||
|
||
PointerVectorSet<ModelPart::NodeType, IndexedObject> nodes; | ||
std::vector<IndexType> node_ids_to_add, existing_node_ids; | ||
if (!fill_existing) { | ||
node_ids_to_add.reserve(input_size); | ||
} else { | ||
node_ids_to_add.reserve(input_size / 2 + 1); | ||
existing_node_ids.reserve(input_size / 2 + 1); | ||
} | ||
|
||
for (IndexType i = 0; i < input_size; ++i) { | ||
nodes.insert(nodes.end(), Kratos::make_intrusive<NodeType>(i + 1, 0.0, 0.0, 0.0)); | ||
RiccardoRossi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// doing it in reverse to make sure a proper sort is done always | ||
for (IndexType i = input_size; i > 0; --i) { | ||
if (!fill_existing || i % 2 == 0) { | ||
node_ids_to_add.push_back(i); | ||
} else { | ||
existing_node_ids.push_back(i); | ||
} | ||
} | ||
r_root_model_part.AddNodes(nodes.begin(), nodes.end()); | ||
r_sub_sub_model_part.AddNodes(existing_node_ids); | ||
state.ResumeTiming(); | ||
|
||
r_sub_sub_model_part.AddNodes(node_ids_to_add); | ||
} | ||
} | ||
|
||
|
||
// Register the function as a benchmark | ||
BENCHMARK(BM_ModelPartCreateNewNode) -> RangeMultiplier(10) -> Range(1e2, 1e+6); | ||
BENCHMARK(BM_ModelPartAddNodesToRootFromRange1) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); | ||
BENCHMARK(BM_ModelPartAddNodesToRootFromRange2) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); | ||
BENCHMARK(BM_ModelPartAddNodesToSubSubFromRange1) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); | ||
BENCHMARK(BM_ModelPartAddNodesToSubSubFromRange2) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); | ||
BENCHMARK(BM_ModelPartAddNodesToSubSubFromRange3) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); | ||
BENCHMARK(BM_ModelPartAddNodesToSubSubFromId1) -> ArgsProduct({{100, 1000, 10000, 100000, 1000000}, {0, 1}}); | ||
|
||
} // namespace Kratos | ||
|
||
BENCHMARK_MAIN(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ | |
#include <sstream> | ||
#include <cstddef> | ||
#include <utility> | ||
#include <type_traits> | ||
|
||
// External includes | ||
#include <boost/iterator/indirect_iterator.hpp> | ||
|
@@ -647,10 +648,23 @@ class PointerVectorSet final | |
template <class InputIterator> | ||
void insert(InputIterator first, InputIterator last) | ||
{ | ||
// first sorts the input iterators and make the input unique. | ||
std::sort(first, last, CompareKey()); | ||
auto new_last = std::unique(first, last, EqualKeyTo()); | ||
SortedInsert(first, new_last); | ||
if constexpr(std::is_assignable_v<decltype(*std::declval<InputIterator>()), decltype(*std::declval<InputIterator>())>) { | ||
// first sorts the input iterators and make the input unique if the iterators are assignable | ||
std::sort(first, last, CompareKey()); | ||
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. this means that you are changing the order of the input "in place", correct? I am not sure if this is what you would expect. I am not sure of what is the praxis in this context. Do you have it clear? |
||
auto new_last = std::unique(first, last, EqualKeyTo()); | ||
SortedInsert(first, new_last); | ||
} else { | ||
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. sorry i cannot understand this ... 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. @Myself, this is for the case in which what i comment above is not possible ... still the comment above still holds 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.
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.
This is to support iterators coming from 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 i understand, however think at the following: std::vector my_pointer_list ....
pvs.insert(my_pointer_list.begin(), my_pointer_list.end(); //it works
//but here my_pointer_list is ordered... i would not expect this. Is that something we accept? (open question...i am not sure of what would be a standardized behaviour) indeed const std::vector my_pointer_list .... //CONST!
//pvs.insert(my_pointer_list.begin(), my_pointer_list.end(); //will int principle not compile
pvs.insert(my_pointer_list.cbegin(), my_pointer_list.cend(); //i understand you will eventually remove the constness inside. Did i get it wrong?
//but here my_pointer_list is NOT ordered (ok, since it was const) but now in the PVS will i have const pointers? if i do not, aren't we removing the constness wrongly? to me this is a difficuly programming question, but i am really not clear about what will happen and OF WHAT SHOULD HAPPEN 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. Hi @RiccardoRossi. This problem is fixed with the cpp standard way of doing this. The std::vector my_pointer_list;
// following will not change the my_pointer_list
//but will incur a cost of copying the data in my_pointer_list to another vector.
pvs.insert(my_pointer_list.begin(), my_pointer_list.end()); If you are sure that you don't want the std::vector my_pointer_list;
// this will mutate the my_pointer_list avoiding a copy operation.
pvs.insert(std::move(my_pointer_list)); Is this acceptable? (The benchmark shows higher performance with There are unit tests added to the |
||
// the iterators are not assignable, hence they may be coming from a const vector, So, we need to make a copy | ||
// to do the sort and unique. | ||
std::vector<TPointerType> temp; | ||
temp.reserve(std::distance(first, last)); | ||
for (auto it = first; it != last; ++it) { | ||
temp.push_back(GetPointer(it)); | ||
} | ||
std::sort(temp.begin(), temp.end(), CompareKey()); | ||
auto new_last = std::unique(temp.begin(), temp.end(), EqualKeyTo()); | ||
SortedInsert(temp.begin(), new_last); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -667,6 +681,20 @@ class PointerVectorSet final | |
SortedInsert(first, last); | ||
} | ||
|
||
/** | ||
* @brief Insert elements from another PointerVectorSet range. | ||
* @details This function inserts element pointers from another PointerVectorSet range specified by first and last into the current set. | ||
* Since, PointerVectorSet is assumed to be sorted and unique, the incoming PointerVectorSet is not | ||
* sorted and made unique again. This will not insert any elements in the incoming set, if there exists an element with a key | ||
* which is equal to an element's key in the input range. | ||
* @param first Other PointerVectorSet starting iterator | ||
* @param last Other PointerVectorSet ending iterator | ||
*/ | ||
void insert(PointerVectorSet::iterator first, PointerVectorSet::iterator last) | ||
{ | ||
SortedInsert(first, last); | ||
} | ||
|
||
void insert(const PointerVectorSet& rOther) | ||
{ | ||
insert(rOther.begin(), rOther.end()); | ||
|
@@ -1199,7 +1227,10 @@ class PointerVectorSet final | |
// which is harder to guess, and cryptic. Hence, using the decltype. | ||
using iterator_value_type = std::decay_t<decltype(*Iterator)>; | ||
|
||
if constexpr(std::is_same_v<iterator_value_type, std::remove_cv_t<TPointerType>>) { | ||
if constexpr(std::is_same_v<TIteratorType, iterator> || std::is_same_v<TIteratorType, reverse_iterator>) { | ||
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. @roigcarlo can you take a look into GetPointer and GetReference? these are difficult functions and i am quite afraid of their implications |
||
// if the TIteratorType is of boost::indirect_iterator type, then we can get the pointer by dereferencing. | ||
return *(Iterator.base()); | ||
} else if constexpr(std::is_same_v<iterator_value_type, std::remove_cv_t<TPointerType>>) { | ||
// this supports any type of pointers | ||
return *Iterator; | ||
} else if constexpr(std::is_same_v<iterator_value_type, std::remove_cv_t<value_type>> && std::is_same_v<TPointerType, Kratos::intrusive_ptr<std::decay_t<decltype(*Iterator)>>>) { | ||
|
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 is not efficient as you may be creating it out of order
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 cannot be out of order, because we assume HDF5 files are written by the
HDF5Application
, hence when we write, we always write in the sorted order.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.
then i do not understand the role of mIds ...
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.
wait, mIds is ordered?
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'll accept the comment, but ... what if somone writes the hdf5 "by hand"? in that case it will be enormously expensive, correct?