diff --git a/bindings/C/CMakeLists.txt b/bindings/C/CMakeLists.txt index a7d3bddfdd0f1a6f04b738d53bbaa4b941a50905..75f35a43a93c6ff2a1e013e4ff5328b2bdf3e4d4 100644 --- a/bindings/C/CMakeLists.txt +++ b/bindings/C/CMakeLists.txt @@ -9,6 +9,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/adios2/adios2_c_adios.cpp ${CMAKE_CURRENT_SOURCE_DIR}/adios2/adios2_c_glue.cpp ${CMAKE_CURRENT_SOURCE_DIR}/adios2/adios2_c_io.cpp ${CMAKE_CURRENT_SOURCE_DIR}/adios2/adios2_c_engine.cpp +${CMAKE_CURRENT_SOURCE_DIR}/adios2/adios2_c_variable.cpp ) target_include_directories(adios2 @@ -26,6 +27,7 @@ install( adios2/adios2_c_adios.h adios2/adios2_c_glue.h adios2/adios2_c_io.h + adios2/adios2_c_variable.h adios2/adios2_c_engine.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/adios2 ) diff --git a/bindings/C/adios2/adios2_c_glue.h b/bindings/C/adios2/adios2_c_glue.h index 3b1ffd65cdd4b6d33bf9f10d78e67410a7be140e..07058f294de04a4956eed554896dc251080caadf 100644 --- a/bindings/C/adios2/adios2_c_glue.h +++ b/bindings/C/adios2/adios2_c_glue.h @@ -3,7 +3,7 @@ * accompanying file Copyright.txt for details. * * adios2_c_glue.h : used by languages other than C, using the C-bindings API - * (e.g. Fortran), not meant to be for applications + * (e.g. Fortran), not meant to be used by applications * * Created on: Nov 3, 2017 * Author: William F Godoy godoywf@ornl.gov diff --git a/bindings/C/adios2/adios2_c_variable.cpp b/bindings/C/adios2/adios2_c_variable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ee1661920bcb9ca14862adc94f33ffb801ebb581 --- /dev/null +++ b/bindings/C/adios2/adios2_c_variable.cpp @@ -0,0 +1,172 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * adios2_c_variable.cpp + * + * Created on: Nov 10, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#include "adios2_c_variable.h" + +#include "adios2/core/Variable.h" +#include "adios2/helper/adiosFunctions.h" + +const char *adios2_variable_name(const adios2_Variable *variable) +{ + const adios2::VariableBase *variableBase = + reinterpret_cast<const adios2::VariableBase *>(variable); + return variableBase->m_Name.c_str(); +} + +const char *adios2_variable_type(const adios2_Variable *variable) +{ + const adios2::VariableBase *variableBase = + reinterpret_cast<const adios2::VariableBase *>(variable); + return variableBase->m_Type.c_str(); +} + +int adios2_variable_is_constant_dims(const adios2_Variable *variable) +{ + const adios2::VariableBase *variableBase = + reinterpret_cast<const adios2::VariableBase *>(variable); + const int isConstantDims = (variableBase->m_ConstantDims) ? 1 : 0; + return isConstantDims; +} + +const size_t adios2_variable_ndims(const adios2_Variable *variable) +{ + const adios2::VariableBase *variableBase = + reinterpret_cast<const adios2::VariableBase *>(variable); + return variableBase->m_Shape.size(); +} + +const size_t *adios2_variable_shape(const adios2_Variable *variable) +{ + const adios2::VariableBase *variableBase = + reinterpret_cast<const adios2::VariableBase *>(variable); + return variableBase->m_Shape.data(); +} + +const size_t *adios2_variable_start(const adios2_Variable *variable) +{ + const adios2::VariableBase *variableBase = + reinterpret_cast<const adios2::VariableBase *>(variable); + return variableBase->m_Start.data(); +} + +const size_t *adios2_variable_count(const adios2_Variable *variable) +{ + const adios2::VariableBase *variableBase = + reinterpret_cast<const adios2::VariableBase *>(variable); + return variableBase->m_Count.data(); +} + +const size_t +adios2_variable_available_steps_start(const adios2_Variable *variable) +{ + const adios2::VariableBase *variableBase = + reinterpret_cast<const adios2::VariableBase *>(variable); + return variableBase->m_AvailableStepsStart; +} + +const size_t +adios2_variable_available_steps_count(const adios2_Variable *variable) +{ + const adios2::VariableBase *variableBase = + reinterpret_cast<const adios2::VariableBase *>(variable); + return variableBase->m_AvailableStepsCount; +} + +void adios2_set_dimensions(adios2_Variable *variable, const size_t ndims, + const size_t *shape, const size_t *start, + const size_t *count) +{ + auto lf_Assign = [](const size_t ndims, const size_t *input, + adios2::Dims &dims) { + + if (input != nullptr) + { + dims.clear(); + dims.assign(input, input + ndims); + } + }; + + adios2::VariableBase *variableBase = + reinterpret_cast<adios2::VariableBase *>(variable); + + lf_Assign(ndims, shape, variableBase->m_Shape); + lf_Assign(ndims, start, variableBase->m_Start); + lf_Assign(ndims, count, variableBase->m_Count); + variableBase->CheckDimensions("in call to adios2_set_selection"); +} + +void adios2_set_selection(adios2_Variable *variable, const size_t ndims, + const size_t *start, const size_t *count) +{ + adios2::VariableBase *variableBase = + reinterpret_cast<adios2::VariableBase *>(variable); + + const adios2::Dims startV(start, start + ndims); + const adios2::Dims countV(start, start + ndims); + variableBase->SetSelection({startV, countV}); + variableBase->CheckDimensions("in call to adios2_set_selection"); +} + +void adios2_set_step_selection(adios2_Variable *variable, + const size_t step_start, const size_t step_count) +{ + adios2::VariableBase *variableBase = + reinterpret_cast<adios2::VariableBase *>(variable); + variableBase->SetStepSelection(adios2::Box<size_t>{step_start, step_count}); +} + +void *adios2_get_data(const adios2_Variable *variable) +{ + const std::string type(adios2_variable_type(variable)); + + void *data = nullptr; + if (type == "compound") + { + // not supported + } +#define declare_template_instantiation(T) \ + else if (type == adios2::GetType<T>()) \ + { \ + const adios2::Variable<T> *variableCpp = \ + reinterpret_cast<const adios2::Variable<T> *>(variable); \ + data = variableCpp->GetData(); \ + } + ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation) +#undef declare_template_instantiation + + return data; +} + +void adios2_set_data(adios2_Variable *variable, const void *data) +{ + if (data == nullptr) + { + const std::string name(adios2_variable_name(variable)); + throw std::invalid_argument( + "ERROR: trying to pass a null pointer to variable " + name + + ", in call to adios2_set_data"); + } + + const std::string type(adios2_variable_type(variable)); + + if (type == "compound") + { + // not supported + } +#define declare_template_instantiation(T) \ + else if (type == adios2::GetType<T>()) \ + { \ + adios2::Variable<T> *variableCpp = \ + reinterpret_cast<adios2::Variable<T> *>(variable); \ + variableCpp->SetData(reinterpret_cast<const T *>(data)); \ + } + ADIOS2_FOREACH_TYPE_1ARG(declare_template_instantiation) +#undef declare_template_instantiation +} diff --git a/bindings/C/adios2/adios2_c_variable.h b/bindings/C/adios2/adios2_c_variable.h new file mode 100644 index 0000000000000000000000000000000000000000..ce144cc6e3be30b5c2b10844573851f62b1aea12 --- /dev/null +++ b/bindings/C/adios2/adios2_c_variable.h @@ -0,0 +1,127 @@ +/* + * Distributed under the OSI-approved Apache License, Version 2.0. See + * accompanying file Copyright.txt for details. + * + * adios2_c_variable.h : exposes some members of the Variable handler + * + * Created on: Nov 10, 2017 + * Author: William F Godoy godoywf@ornl.gov + */ + +#ifndef BINDINGS_C_ADIOS2_ADIOS2_C_VARIABLE_H_ +#define BINDINGS_C_ADIOS2_ADIOS2_C_VARIABLE_H_ + +#include "adios2_c_types.h" + +#include <stddef.h> //size_t + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Retrieve variable name (read-only) + * @param variable handler + * @return name + */ +const char *adios2_variable_name(const adios2_Variable *variable); + +/** + * Retrieve variable type (read-only) + * @param variable handler + * @return type + */ +const char *adios2_variable_type(const adios2_Variable *variable); + +/** + * Check if dimensions are constant + * @param variable + * @return 0: false (dimensions are not constant), 1: true dimensions are + * declared constant + */ +int adios2_variable_is_constant_dims(const adios2_Variable *variable); + +const size_t adios2_variable_ndims(const adios2_Variable *variable); + +/** + * Retrieve current variable shape (read-only) + * @param variable handler + * @return shape + */ +const size_t *adios2_variable_shape(const adios2_Variable *variable); + +/** + * Retrieve current variable start (read-only) + * @param variable handler + * @return + */ +const size_t *adios2_variable_start(const adios2_Variable *variable); +/** + * Retrieve current variable shape (read-only) + * @param variable + * @return type + */ +const size_t *adios2_variable_count(const adios2_Variable *variable); + +const size_t +adios2_variable_available_steps_start(const adios2_Variable *variable); +const size_t +adios2_variable_available_steps_count(const adios2_Variable *variable); + +/** + * Set new dimensions + * @param variable + * @param shape + * @param start + * @param count + */ +void adios2_set_dimensions(adios2_Variable *variable, const size_t ndims, + const size_t *shape, const size_t *start, + const size_t *count); + +/** + * Set new selection using start and count + * @param variable + * @param start + * @param count + */ +void adios2_set_selection(adios2_Variable *variable, const size_t ndims, + const size_t *start, const size_t *count); + +/** + * Set new step selection using step_start and step_count + * @param variable + * @param step_start + * @param step_count + */ +void adios2_set_step_selection(adios2_Variable *variable, + const size_t step_start, + const size_t step_count); + +/** + * Returns the minimum required allocation (in number of elements of a certain + * type, not bytes) + * for the current selection + * @param variable + * @return memory size to be allocated by a pointer/vector to read this + */ +size_t adios2_selection_size(const adios2_Variable *variable); + +/** + * Get current data pointer, types must match + * @param variable + */ +void *adios2_get_data(const adios2_Variable *variable); + +/** + * Sets current data pointer, types must match + * @param variable + * @param data + */ +void adios2_set_data(adios2_Variable *variable, const void *data); + +#ifdef __cplusplus +} // end extern C +#endif + +#endif /* BINDINGS_C_ADIOS2_ADIOS2_C_VARIABLE_H_ */ diff --git a/bindings/C/adios2_c.h b/bindings/C/adios2_c.h index 64cc07d32995449ecfb294ed3743c08b10dbec6e..2813ff6d0ec275278e51b88c234fa2a8ff9ada62 100644 --- a/bindings/C/adios2_c.h +++ b/bindings/C/adios2_c.h @@ -16,5 +16,6 @@ #include "adios2/adios2_c_engine.h" #include "adios2/adios2_c_glue.h" #include "adios2/adios2_c_io.h" +#include "adios2/adios2_c_variable.h" #endif /* ADIOS2_BINDINGS_C_ADIOS2_C_H_ */ diff --git a/examples/hello/bpReader/helloBPReaderHeatMap2D.cpp b/examples/hello/bpReader/helloBPReaderHeatMap2D.cpp index 86fc95ed6fb180be1752efe27b27191ec4d87aa9..3305d29f4e1486b42651699b03d7881f09269ad6 100644 --- a/examples/hello/bpReader/helloBPReaderHeatMap2D.cpp +++ b/examples/hello/bpReader/helloBPReaderHeatMap2D.cpp @@ -91,7 +91,7 @@ int main(int argc, char *argv[]) if (inTemperature != nullptr) { inTemperature->SetSelection({{2, 2}, {6, 1}}); - size_t elementsSize = inTemperature->GetElementsSize(); + size_t elementsSize = inTemperature->SelectionSize(); std::vector<unsigned int> inTemperatures(elementsSize); std::cout << "Pre-allocated " << elementsSize << " elements, " << elementsSize * sizeof(unsigned int) << " bytes\n"; diff --git a/examples/hello/bpReader/helloBPReaderHeatMap3D.cpp b/examples/hello/bpReader/helloBPReaderHeatMap3D.cpp index 71cb73f486ade9a744127fdbec5d56ebe0f837de..815a02826a43e4066418a652e60eb1d931db9c11 100644 --- a/examples/hello/bpReader/helloBPReaderHeatMap3D.cpp +++ b/examples/hello/bpReader/helloBPReaderHeatMap3D.cpp @@ -100,7 +100,7 @@ int main(int argc, char *argv[]) if (inTemperature != nullptr) { inTemperature->SetSelection({{2, 2, 2}, {4, 4, 4}}); - const size_t elementsSize = inTemperature->GetElementsSize(); + const size_t elementsSize = inTemperature->SelectionSize(); std::vector<unsigned int> inTemperatures(elementsSize); std::cout << "Pre-allocated " << elementsSize << " elements, " << elementsSize * sizeof(unsigned int) << " bytes\n"; diff --git a/source/adios2/core/VariableBase.cpp b/source/adios2/core/VariableBase.cpp index 591e5ca5bde74066d61c163bf93d36638abdc887..aa3c8fa5fea15b8c1df66a54e306358892efed7c 100644 --- a/source/adios2/core/VariableBase.cpp +++ b/source/adios2/core/VariableBase.cpp @@ -134,7 +134,7 @@ size_t VariableBase::GetAvailableStepsCount() const return m_AvailableStepsCount; } -void VariableBase::SetStepSelection(const std::pair<size_t, size_t> &boxSteps) +void VariableBase::SetStepSelection(const Box<size_t> &boxSteps) { if (boxSteps.second == 0) { @@ -176,7 +176,7 @@ void VariableBase::ClearOperators() noexcept { m_OperatorsInfo.clear(); } void VariableBase::CheckDimensions(const std::string hint) const { - if (m_ShapeID == ShapeID::GlobalArray) + if (m_DebugMode && m_ShapeID == ShapeID::GlobalArray) { if (m_Start.empty() || m_Count.empty()) { @@ -192,7 +192,7 @@ void VariableBase::CheckDimensions(const std::string hint) const // TODO need to think more exceptions here } -size_t VariableBase::GetElementsSize() const +size_t VariableBase::SelectionSize() const { return GetTotalSize(m_Count) * m_StepsCount; } @@ -204,7 +204,7 @@ void VariableBase::InitShapeType() { if (std::count(m_Shape.begin(), m_Shape.end(), JoinedDim) == 1) { - if (!m_Start.empty() && + if (m_DebugMode && !m_Start.empty() && std::count(m_Start.begin(), m_Start.end(), 0) != m_Start.size()) { throw std::invalid_argument("ERROR: The Start array must be " @@ -224,17 +224,15 @@ void VariableBase::InitShapeType() } else { - if (m_DebugMode) + + if (m_DebugMode && m_ConstantDims) { - if (m_ConstantDims) - { - throw std::invalid_argument( - "ERROR: isConstantShape (true) argument is invalid " - "with empty start and count " - "arguments in call to " - "DefineVariable " + - m_Name + "\n"); - } + throw std::invalid_argument( + "ERROR: isConstantShape (true) argument is invalid " + "with empty start and count " + "arguments in call to " + "DefineVariable " + + m_Name + "\n"); } m_ShapeID = ShapeID::GlobalArray; @@ -299,11 +297,14 @@ void VariableBase::InitShapeType() } else { - throw std::invalid_argument( - "ERROR: if the " - "shape is empty, start must be empty as well, in call to " - "DefineVariable " + - m_Name + "\n"); + if (m_DebugMode) + { + throw std::invalid_argument( + "ERROR: if the " + "shape is empty, start must be empty as well, in call to " + "DefineVariable " + + m_Name + "\n"); + } } } @@ -317,6 +318,11 @@ void VariableBase::InitShapeType() void VariableBase::CheckDimensionsCommon(const std::string hint) const { + if (!m_DebugMode) + { + return; + } + if (m_Type == "string") { if (!(m_Shape.empty() && m_Start.empty() && m_Count.empty())) diff --git a/source/adios2/core/VariableBase.h b/source/adios2/core/VariableBase.h index 39d6410578db70a1d820725262e8be7e78a18edf..c57b716908a142a48e709eeb88dd41ba5304c124 100644 --- a/source/adios2/core/VariableBase.h +++ b/source/adios2/core/VariableBase.h @@ -148,7 +148,7 @@ public: * @return memory size to be allocated by a pointer/vector to read this * variable */ - size_t GetElementsSize() const; + size_t SelectionSize() const; protected: const bool m_DebugMode = false; diff --git a/source/adios2/helper/adiosMath.h b/source/adios2/helper/adiosMath.h index 4ca4140170db2a5211d98abe80eb8d019bada1f1..d8dd481fc6498e0bfe55db8f411273caf4d71395 100644 --- a/source/adios2/helper/adiosMath.h +++ b/source/adios2/helper/adiosMath.h @@ -120,7 +120,7 @@ Box<Dims> IntersectionBox(const Box<Dims> &box1, const Box<Dims> &box2) noexcept; /** - * Get a linear index for a point inside a localBox + * Get a linear index for a point inside a localBox depending on data layout * @param localBox start and count * @param point inside box * @param isRowMajor diff --git a/source/adios2/helper/adiosSystem.cpp b/source/adios2/helper/adiosSystem.cpp index 233f2d096cffde6bb1b482c75bcdcbbc5a36ee72..cac0a33421628d3bbe0963968da800fe021eb6be 100644 --- a/source/adios2/helper/adiosSystem.cpp +++ b/source/adios2/helper/adiosSystem.cpp @@ -21,7 +21,7 @@ // remove ctime warning on Windows #ifdef _WIN32 -#pragma warning(disable : 4996) +#pragma warning(disable : 4996) // ctime warning #endif namespace adios2 @@ -46,4 +46,26 @@ std::string LocalTimeDate() noexcept return std::string(ctime(&now)); } -} // end namespace adios +bool IsRowMajor(const std::string hostLanguage) noexcept +{ + bool isRowMajor = true; + + if (hostLanguage == "Fortran" || hostLanguage == "R") + { + isRowMajor = false; + } + return isRowMajor; +} + +bool IsZeroIndexed(const std::string hostLanguage) noexcept +{ + bool isZeroIndexed = true; + + if (hostLanguage == "Fortran" || hostLanguage == "R") + { + isZeroIndexed = false; + } + return isZeroIndexed; +} + +} // end namespace adios2 diff --git a/source/adios2/helper/adiosSystem.h b/source/adios2/helper/adiosSystem.h index e241e65164a1ccf89cf805f9721dc5863ce0a5c7..0a8c2cfb78ff5903777fe1fc0ad3431af2c1fc25 100644 --- a/source/adios2/helper/adiosSystem.h +++ b/source/adios2/helper/adiosSystem.h @@ -40,6 +40,22 @@ bool IsLittleEndian() noexcept; */ std::string LocalTimeDate() noexcept; -} // end namespace adios +/** + * Support for language bindings, identify if data is row-major (C, C++) or not + * (Fortran, R) + * @param hostLanguage input host language + * @return true: row-major, false: column-major + */ +bool IsRowMajor(const std::string hostLanguage) noexcept; + +/** + * Support for language bindings, identify if data is zero-indexed (C, C++) or + * not (Fortran, R) + * @param hostLanguage input host language + * @return true: zero-indexed, false: one-indexed + */ +bool IsZeroIndexed(const std::string hostLanguage) noexcept; + +} // end namespace adios2 #endif /* ADIOS2_HELPER_ADIOSSYSTEM_H_ */ diff --git a/source/adios2/toolkit/format/bp3/BP3Base.h b/source/adios2/toolkit/format/bp3/BP3Base.h index 6f10ebdc7124afc67f17e6a48dfe4e6b13e47507..a5d5d0c72d91f81df53237432972b87cffc798b0 100644 --- a/source/adios2/toolkit/format/bp3/BP3Base.h +++ b/source/adios2/toolkit/format/bp3/BP3Base.h @@ -207,9 +207,9 @@ protected: unsigned int m_Threads = 1; const bool m_DebugMode = false; - /** from host language */ + /** from host language in data information */ bool m_IsRowMajor = true; // C, C++ defaults - /** from host language */ + /** from host language in data information */ bool m_IsZeroIndex = true; // C, C++ /** method type for file I/O */ diff --git a/source/adios2/toolkit/format/bp3/BP3Deserializer.cpp b/source/adios2/toolkit/format/bp3/BP3Deserializer.cpp index 1bfa4de39606f8cdcdfea9aa6df98ab9e19364dc..701e425ed68e3248b30ae1bcafb554acd69a9c05 100644 --- a/source/adios2/toolkit/format/bp3/BP3Deserializer.cpp +++ b/source/adios2/toolkit/format/bp3/BP3Deserializer.cpp @@ -119,6 +119,7 @@ void BP3Deserializer::ParsePGIndex() m_MetadataSet.DataPGCount = ReadValue<uint64_t>(buffer, position); const uint64_t pgLength = ReadValue<uint64_t>(buffer, position); // not required + // TODO: here check for host language in first pg index } void BP3Deserializer::ParseVariablesIndex(IO &io) diff --git a/source/adios2/toolkit/format/bp3/BP3Deserializer.h b/source/adios2/toolkit/format/bp3/BP3Deserializer.h index 4bf14e3f5b692ffc6ab99cf869059d9858b2ed9b..01f829dcbd53d30a875d831b988f9ecff5a8c50f 100644 --- a/source/adios2/toolkit/format/bp3/BP3Deserializer.h +++ b/source/adios2/toolkit/format/bp3/BP3Deserializer.h @@ -70,8 +70,8 @@ private: void ParseAttributesIndex(IO &io); /** - * This function reads a variable index element (serialized) and calls IO - * DefineVariable to deserialize the data + * Reads a variable index element (serialized) and calls IO.DefineVariable + * to deserialize the Variable metadata * @param header serialize * @param io * @param buffer @@ -91,10 +91,29 @@ private: const Box<Dims> &blockBox, const Box<Dims> &intersectionBox) const; + /** + * Row-major, zero-indexed data e.g. : C, C++ + * @param variable + * @param contiguousMemory + * @param blockBox + * @param intersectionBox + */ template <class T> void ClipContiguousMemoryCommonRowZero( Variable<T> &variable, const std::vector<char> &contiguousMemory, const Box<Dims> &blockBox, const Box<Dims> &intersectionBox) const; + + /** + * Column-major, one indexed data e.g. : Fortran, R + * @param variable + * @param contiguousMemory + * @param blockBox + * @param intersectionBox + */ + template <class T> + void ClipContiguousMemoryCommonColumnOne( + Variable<T> &variable, const std::vector<char> &contiguousMemory, + const Box<Dims> &blockBox, const Box<Dims> &intersectionBox) const; }; #define declare_template_instantiation(T) \ diff --git a/source/adios2/toolkit/format/bp3/BP3Deserializer.tcc b/source/adios2/toolkit/format/bp3/BP3Deserializer.tcc index c0c0933815e9ee7d1875916eaccbba11064b601a..8e90253eef67ff1ceaae5495ca08caf74dd0aa9b 100644 --- a/source/adios2/toolkit/format/bp3/BP3Deserializer.tcc +++ b/source/adios2/toolkit/format/bp3/BP3Deserializer.tcc @@ -217,11 +217,16 @@ void BP3Deserializer::ClipContiguousMemoryCommon( return; } - if (m_IsRowMajor && m_IsZeroIndex) + if (m_IsRowMajor && m_IsZeroIndex) // C, C++, Python { ClipContiguousMemoryCommonRowZero(variable, contiguousMemory, blockBox, intersectionBox); } + else if (!m_IsRowMajor && !m_IsZeroIndex) // Fortran, R + { + ClipContiguousMemoryCommonColumnOne(variable, contiguousMemory, + blockBox, intersectionBox); + } } template <class T> @@ -288,6 +293,70 @@ void BP3Deserializer::ClipContiguousMemoryCommonRowZero( } // run } +template <class T> +void BP3Deserializer::ClipContiguousMemoryCommonColumnOne( + Variable<T> &variable, const std::vector<char> &contiguousMemory, + const Box<Dims> &blockBox, const Box<Dims> &intersectionBox) const +{ + const Dims &start = intersectionBox.first; + const Dims &end = intersectionBox.second; + const size_t stride = (end.front() - start.front() + 1) * sizeof(T); + + Dims currentPoint(start); // current point for memory copy + + const Box<Dims> selectionBox = + StartEndBox(variable.m_Start, variable.m_Count); + + const size_t dimensions = start.size(); + bool run = true; + + const size_t intersectionStart = + LinearIndex(blockBox, intersectionBox.first, false, false) * sizeof(T); + + while (run) + { + // here copy current linear memory between currentPoint and end + const size_t contiguousStart = + LinearIndex(blockBox, currentPoint, false, false) * sizeof(T) - + intersectionStart; + + const size_t variableStart = + LinearIndex(selectionBox, currentPoint, false, false) * sizeof(T); + + char *rawVariableData = reinterpret_cast<char *>(variable.GetData()); + + std::copy(&contiguousMemory[contiguousStart], + &contiguousMemory[contiguousStart + stride], + &rawVariableData[variableStart]); + + // here update each index recursively, always starting from the 2nd + // fastest changing index, since fastest changing index is the + // continuous part in the previous std::copy + size_t p = 1; + while (true) + { + ++currentPoint[p]; + if (currentPoint[p] > end[p]) // TODO: check end condition + { + if (p == dimensions - 1) + { + run = false; // we are done + break; + } + else + { + currentPoint[p] = start[p]; + ++p; + } + } + else + { + break; // break inner p loop + } + } // dimension index update + } +} + } // end namespace format } // end namespace adios2