From cc1672d1b9e28af98089fcdff59d6c2f8aa8594d Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 14 Jun 2023 12:06:27 -0700 Subject: [PATCH 1/4] Add Array to Options Enable 1D arrays of integers to be read from NetCDF files, and made available via `Mesh::get()`. Mainly useful for mesh construction. --- include/bout/options.hxx | 6 +++++- include/bout/utils.hxx | 4 ++-- src/mesh/data/gridfromfile.cxx | 20 +++++++++++++------ src/sys/options.cxx | 31 ++++++++++++++++++++++++++++++ src/sys/options/options_netcdf.cxx | 4 ++++ 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/include/bout/options.hxx b/include/bout/options.hxx index bf1704100f..fae05b8ecc 100644 --- a/include/bout/options.hxx +++ b/include/bout/options.hxx @@ -196,7 +196,7 @@ public: /// The type used to store values using ValueType = bout::utils::variant, Matrix, Tensor>; + Array, Array, Matrix, Tensor>; /// The type used to store attributes /// Extends the variant class so that cast operator can be implemented @@ -874,6 +874,8 @@ void Options::assign<>(FieldPerp val, std::string source); template <> void Options::assign<>(Array val, std::string source); template <> +void Options::assign<>(Array val, std::string source); +template <> void Options::assign<>(Matrix val, std::string source); template <> void Options::assign<>(Tensor val, std::string source); @@ -902,6 +904,8 @@ FieldPerp Options::as(const FieldPerp& similar_to) const; template <> Array Options::as>(const Array& similar_to) const; template <> +Array Options::as>(const Array& similar_to) const; +template <> Matrix Options::as>(const Matrix& similar_to) const; template <> Tensor Options::as>(const Tensor& similar_to) const; diff --git a/include/bout/utils.hxx b/include/bout/utils.hxx index 450d3eaf87..e2ec5b24db 100644 --- a/include/bout/utils.hxx +++ b/include/bout/utils.hxx @@ -543,8 +543,8 @@ std::string toString(const T& val) { /// where the type may be std::string. inline std::string toString(const std::string& val) { return val; } -template <> -inline std::string toString<>(const Array& UNUSED(val)) { +template +inline std::string toString(const Array& UNUSED(val)) { return ""; } diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 7e875bd109..7fab486e54 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -138,7 +138,8 @@ struct GetDimensions { std::vector operator()(MAYBE_UNUSED(int value)) { return {1}; } std::vector operator()(MAYBE_UNUSED(BoutReal value)) { return {1}; } std::vector operator()(MAYBE_UNUSED(const std::string& value)) { return {1}; } - std::vector operator()(const Array& array) { return {array.size()}; } + template + std::vector operator()(const Array& array) { return {array.size()}; } std::vector operator()(const Matrix& array) { const auto shape = array.shape(); return {std::get<0>(shape), std::get<1>(shape)}; @@ -471,13 +472,20 @@ void GridFile::readField(Mesh* m, const std::string& name, int UNUSED(ys), int U } } -bool GridFile::get(MAYBE_UNUSED(Mesh* m), MAYBE_UNUSED(std::vector& var), - MAYBE_UNUSED(const std::string& name), MAYBE_UNUSED(int len), - MAYBE_UNUSED(int offset), - MAYBE_UNUSED(GridDataSource::Direction dir)) { +bool GridFile::get(Mesh* UNUSED(m), std::vector& var, const std::string& name, + int len, int offset, GridDataSource::Direction UNUSED(dir)) { TRACE("GridFile::get(vector)"); - return false; + if (not data.isSet(name)) { + return false; + } + + const auto full_var = data[name].as>(); + const auto* it = std::begin(full_var); + std::advance(it, offset); + std::copy_n(it, len, std::begin(var)); + + return true; } bool GridFile::get(Mesh* UNUSED(m), std::vector& var, const std::string& name, diff --git a/src/sys/options.cxx b/src/sys/options.cxx index 8b49b1f3f1..fec4073682 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -288,6 +288,10 @@ void Options::assign<>(Array val, std::string source) { _set_no_check(std::move(val), std::move(source)); } template <> +void Options::assign<>(Array val, std::string source) { + _set_no_check(std::move(val), std::move(source)); +} +template <> void Options::assign<>(Matrix val, std::string source) { _set_no_check(std::move(val), std::move(source)); } @@ -723,6 +727,33 @@ Array Options::as>(const Array& similar_to) return result; } +template <> +Array Options::as>(const Array& similar_to) const { + if (is_section) { + throw BoutException(_("Option {:s} has no value"), full_name); + } + + Array result = bout::utils::visit( + ConvertContainer>{ + fmt::format( + _("Value for option {:s} cannot be converted to an Array"), + full_name), + similar_to}, + value); + + // Mark this option as used + value_used = true; + + output_info << _("\tOption ") << full_name << " = Array"; + if (hasAttribute("source")) { + // Specify the source of the setting + output_info << " (" << bout::utils::variantToString(attributes.at("source")) << ")"; + } + output_info << endl; + + return result; +} + template <> Matrix Options::as>(const Matrix& similar_to) const { if (is_section) { diff --git a/src/sys/options/options_netcdf.cxx b/src/sys/options/options_netcdf.cxx index d7ceeaea60..7c21b309bc 100644 --- a/src/sys/options/options_netcdf.cxx +++ b/src/sys/options/options_netcdf.cxx @@ -88,6 +88,10 @@ void readGroup(const std::string& filename, const NcGroup& group, Options& resul Array value(static_cast(dims[0].getSize())); var.getVar(value.begin()); result[var_name] = value; + } else if (var_type == ncInt or var_type == ncShort) { + Array value(static_cast(dims[0].getSize())); + var.getVar(value.begin()); + result[var_name] = value; } else if ((var_type == ncString) or (var_type == ncChar)) { std::string value; value.resize(dims[0].getSize()); From e654af65c6ea32a0ee4f6f07659e246ac70ac88b Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 14 Jun 2023 18:06:49 -0700 Subject: [PATCH 2/4] GridFile: Check sizes, allocate vector ints When reading 1D vector of ints, check that the input is long enough, and resize the output vector. --- src/mesh/data/gridfromfile.cxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 7fab486e54..7c02cf4ab7 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -481,6 +481,16 @@ bool GridFile::get(Mesh* UNUSED(m), std::vector& var, const std::string& na } const auto full_var = data[name].as>(); + + // Check size + if (full_var.size() < len + offset) { + throw BoutException("{} has length {}. Expected {} elements + {} offset", + name, full_var.size(), len, offset); + } + + // Ensure that output variable has the correct size + var.resize(len); + const auto* it = std::begin(full_var); std::advance(it, offset); std::copy_n(it, len, std::begin(var)); From 359766313a8b878f056008358192cb4653130384 Mon Sep 17 00:00:00 2001 From: Ben Dudson Date: Wed, 14 Jun 2023 18:08:32 -0700 Subject: [PATCH 3/4] Add limiters in input mesh A short-term fix, allowing extra limiters to be added with inputs: limiter_count : int limiter_yinds : [int], length limiter_count limiter_xstarts : [int], length limiter_count limiter_xends : [int], length limiter_count The limiter(s) are added between yinds[i] and yinds[i] + 1 --- src/mesh/impls/bout/boutmesh.cxx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index a802d3f5b3..448832ea57 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2073,6 +2073,32 @@ void BoutMesh::topology() { add_target(ny_inner - 1, 0, nx); } + // Additional limiters + // Each limiter needs 3 indices: A Y index, start and end X indices + int limiter_count = 0; + Mesh::get(limiter_count, "limiter_count", 0); + if (limiter_count > 0) { + std::vector limiter_yinds, limiter_xstarts, limiter_xends; + if (!source->get(this, limiter_yinds, "limiter_yinds", limiter_count)) { + throw BoutException("Couldn't read limiter_yinds vector of length {} from mesh", limiter_count); + } + if (!source->get(this, limiter_xstarts, "limiter_xstarts", limiter_count)) { + throw BoutException("Couldn't read limiter_xstarts vector of length {} from mesh", limiter_count); + } + if (!source->get(this, limiter_xends, "limiter_xends", limiter_count)) { + throw BoutException("Couldn't read limiter_xend vector of length {} from mesh", limiter_count); + } + + for (int i = 0; i < limiter_count; ++i) { + int yind = limiter_yinds[i]; + int xstart = limiter_xstarts[i]; + int xend = limiter_xends[i]; + output_info.write("Adding a limiter between y={} and {}. X indices {} to {}\n", + yind, yind+1, xstart, xend); + add_target(yind, xstart, xend); + } + } + if ((ixseps_inner > 0) && (((PE_YIND * MYSUB > jyseps1_1) && (PE_YIND * MYSUB <= jyseps2_1)) || ((PE_YIND * MYSUB > jyseps1_2) && (PE_YIND * MYSUB <= jyseps2_2)))) { From 1c1d834c822857239efa5f8189b187845cebe073 Mon Sep 17 00:00:00 2001 From: bendudson Date: Thu, 15 Jun 2023 01:17:21 +0000 Subject: [PATCH 4/4] Apply clang-format changes --- include/bout/options.hxx | 6 +++--- src/mesh/data/gridfromfile.cxx | 10 ++++++---- src/mesh/impls/bout/boutmesh.cxx | 11 +++++++---- src/sys/options.cxx | 5 ++--- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/include/bout/options.hxx b/include/bout/options.hxx index fae05b8ecc..e790b405b5 100644 --- a/include/bout/options.hxx +++ b/include/bout/options.hxx @@ -194,9 +194,9 @@ public: static void cleanup(); /// The type used to store values - using ValueType = - bout::utils::variant, Array, Matrix, Tensor>; + using ValueType = bout::utils::variant, Array, + Matrix, Tensor>; /// The type used to store attributes /// Extends the variant class so that cast operator can be implemented diff --git a/src/mesh/data/gridfromfile.cxx b/src/mesh/data/gridfromfile.cxx index 7c02cf4ab7..eed70776b3 100644 --- a/src/mesh/data/gridfromfile.cxx +++ b/src/mesh/data/gridfromfile.cxx @@ -138,8 +138,10 @@ struct GetDimensions { std::vector operator()(MAYBE_UNUSED(int value)) { return {1}; } std::vector operator()(MAYBE_UNUSED(BoutReal value)) { return {1}; } std::vector operator()(MAYBE_UNUSED(const std::string& value)) { return {1}; } - template - std::vector operator()(const Array& array) { return {array.size()}; } + template + std::vector operator()(const Array& array) { + return {array.size()}; + } std::vector operator()(const Matrix& array) { const auto shape = array.shape(); return {std::get<0>(shape), std::get<1>(shape)}; @@ -484,8 +486,8 @@ bool GridFile::get(Mesh* UNUSED(m), std::vector& var, const std::string& na // Check size if (full_var.size() < len + offset) { - throw BoutException("{} has length {}. Expected {} elements + {} offset", - name, full_var.size(), len, offset); + throw BoutException("{} has length {}. Expected {} elements + {} offset", name, + full_var.size(), len, offset); } // Ensure that output variable has the correct size diff --git a/src/mesh/impls/bout/boutmesh.cxx b/src/mesh/impls/bout/boutmesh.cxx index 448832ea57..c2c9b51ba3 100644 --- a/src/mesh/impls/bout/boutmesh.cxx +++ b/src/mesh/impls/bout/boutmesh.cxx @@ -2080,13 +2080,16 @@ void BoutMesh::topology() { if (limiter_count > 0) { std::vector limiter_yinds, limiter_xstarts, limiter_xends; if (!source->get(this, limiter_yinds, "limiter_yinds", limiter_count)) { - throw BoutException("Couldn't read limiter_yinds vector of length {} from mesh", limiter_count); + throw BoutException("Couldn't read limiter_yinds vector of length {} from mesh", + limiter_count); } if (!source->get(this, limiter_xstarts, "limiter_xstarts", limiter_count)) { - throw BoutException("Couldn't read limiter_xstarts vector of length {} from mesh", limiter_count); + throw BoutException("Couldn't read limiter_xstarts vector of length {} from mesh", + limiter_count); } if (!source->get(this, limiter_xends, "limiter_xends", limiter_count)) { - throw BoutException("Couldn't read limiter_xend vector of length {} from mesh", limiter_count); + throw BoutException("Couldn't read limiter_xend vector of length {} from mesh", + limiter_count); } for (int i = 0; i < limiter_count; ++i) { @@ -2094,7 +2097,7 @@ void BoutMesh::topology() { int xstart = limiter_xstarts[i]; int xend = limiter_xends[i]; output_info.write("Adding a limiter between y={} and {}. X indices {} to {}\n", - yind, yind+1, xstart, xend); + yind, yind + 1, xstart, xend); add_target(yind, xstart, xend); } } diff --git a/src/sys/options.cxx b/src/sys/options.cxx index fec4073682..1c50db5896 100644 --- a/src/sys/options.cxx +++ b/src/sys/options.cxx @@ -735,9 +735,8 @@ Array Options::as>(const Array& similar_to) const { Array result = bout::utils::visit( ConvertContainer>{ - fmt::format( - _("Value for option {:s} cannot be converted to an Array"), - full_name), + fmt::format(_("Value for option {:s} cannot be converted to an Array"), + full_name), similar_to}, value);