From 7e95532ea346dd412796b4e0488ab6cba729efc4 Mon Sep 17 00:00:00 2001 From: Geoffrey C Danielson Date: Tue, 6 Oct 2020 14:18:39 -0600 Subject: [PATCH 001/147] add test and intercept lib --- .../test/KokkosIntegration/CMakeLists.txt | 11 ++ .../core/test/KokkosIntegration/Intercept.cpp | 179 ++++++++++++++++++ .../test/KokkosIntegration/KokkosDeepcopy.cpp | 100 ++++++++++ 3 files changed, 290 insertions(+) create mode 100644 packages/tpetra/core/test/KokkosIntegration/Intercept.cpp create mode 100644 packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp diff --git a/packages/tpetra/core/test/KokkosIntegration/CMakeLists.txt b/packages/tpetra/core/test/KokkosIntegration/CMakeLists.txt index 906c118515fb..89488f3e9d31 100644 --- a/packages/tpetra/core/test/KokkosIntegration/CMakeLists.txt +++ b/packages/tpetra/core/test/KokkosIntegration/CMakeLists.txt @@ -5,4 +5,15 @@ IF (Tpetra_ENABLE_CUDA) SOURCES KokkosUVM COMM serial ) + TRIBITS_ADD_EXECUTABLE( + KokkosDeepcopy + SOURCES KokkosDeepcopy + COMM serial + ) + TRIBITS_ADD_LIBRARY( + Intercept + SOURCES Intercept + SHARED + TESTONLY + ) ENDIF() diff --git a/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp b/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp new file mode 100644 index 000000000000..a0a77ab4cf5b --- /dev/null +++ b/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp @@ -0,0 +1,179 @@ +/* +// @HEADER +// *********************************************************************** +// +// Tpetra: Templated Linear Algebra Services Package +// Copyright (2008) Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Michael A. Heroux (maherou@sandia.gov) +// +// ************************************************************************ +// @HEADER +*/ + +#include +#include +#include +#include +#include + +//strategy: kokkos::deepcopy a view, count the intercepts. For right now, just report them when mpi_finalize happens. +void OnHost2Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + /* using range_policy = Kokkos::RangePolicy; + + Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(b, a); +} + +void OnDevice2Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + using range_policy = Kokkos::RangePolicy; + + Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + + Kokkos::deep_copy(b, a); +} + +void HostToDevice2Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + /* + Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(b, a); +} + +void DeviceToHost2Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + /* + Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(b, a); +} + +void OnHost3Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + Kokkos::DefaultExecutionSpace mySpace; + /* + using range_policy = Kokkos::RangePolicy; + + Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(mySpace, b, a); +} + +void OnDevice3Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + Kokkos::DefaultExecutionSpace mySpace; + using range_policy = Kokkos::RangePolicy; + + Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + + Kokkos::deep_copy(mySpace, b, a); +} + +void HostToDevice3Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + Kokkos::DefaultExecutionSpace mySpace; + /* + Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(mySpace, b, a); +} + +void DeviceToHost3Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + Kokkos::DefaultExecutionSpace mySpace; + /* + Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(mySpace, b, a); +} + +int main(int argc, char *argv[]) { + //initialize + MPI_Init(&argc, &argv); + Kokkos::initialize(argc, argv); + + fprintf (stderr, "Starting copies\n"); + //OnHost2Arg(); + //OnDevice2Arg(); + //HostToDevice2Arg(); + //DeviceToHost2Arg(); + //OnHost3Arg(); + //OnDevice3Arg(); + //HostToDevice3Arg(); + DeviceToHost3Arg(); + fprintf (stderr, "Finished copies\n"); + + fprintf(stderr, "summary statistics\n"); + //finalize + Kokkos::finalize(); + MPI_Finalize(); + + return 0; +} + diff --git a/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp b/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp new file mode 100644 index 000000000000..03f93e3a47c3 --- /dev/null +++ b/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp @@ -0,0 +1,100 @@ +/* +// @HEADER +// *********************************************************************** +// +// Tpetra: Templated Linear Algebra Services Package +// Copyright (2008) Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Michael A. Heroux (maherou@sandia.gov) +// +// ************************************************************************ +// @HEADER +*/ + +#include + +#include +#include + +class DeepcopyTester { +public: + DeepcopyTester() { } + + void run() { + log("Tpetra Kokkos Deepcopy test start"); + + OnHost(); + OnDevice(); + HostToDevice(); + DeviceToHost(); + + if (isConsistent) log("+++ Result is consistent +++"); + else log("!!! Result is inconsistent !!!"); + } + + //strategy: kokkos::deepcopy a view, count the intercepts. For right now, just report them when mpi_finalize happens. + void OnHost() { + Kokkos::View a ("a", 1); + Kokkos::View b ("b", 1); + + Kokkos::deep_copy(a, b); + } + + void OnDevice() { + Kokkos::View a ("a", 1); + Kokkos::View b ("b", 1); + + Kokkos::deep_copy(a, b); + } + + void HostToDevice() { + Kokkos::View a ("a", 1); + Kokkos::View b ("b", 1); + + Kokkos::deep_copy(a, b); + } + + void DeviceToHost() { + Kokkos::View a ("a", 1); + Kokkos::View b ("b", 1); + + Kokkos::deep_copy(a, b); + } + +private: + bool isConsistent = true; + void log(const std::string& msg) { + std::cout << msg << std::endl; + } + +}; From a47474d483b9c5670526b10f593c0939749daf61 Mon Sep 17 00:00:00 2001 From: Geoffrey C Danielson Date: Wed, 7 Oct 2020 09:20:55 -0600 Subject: [PATCH 002/147] please ignore the man behind the curtain --- .../core/test/KokkosIntegration/Intercept.cpp | 471 +++++++++++------- .../test/KokkosIntegration/KokkosDeepcopy.cpp | 187 +++++-- .../core/test/KokkosIntegration/intercept.cpp | 312 ++++++++++++ 3 files changed, 747 insertions(+), 223 deletions(-) create mode 100644 packages/tpetra/core/test/KokkosIntegration/intercept.cpp diff --git a/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp b/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp index a0a77ab4cf5b..0fbe47546acb 100644 --- a/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp +++ b/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp @@ -1,179 +1,312 @@ /* -// @HEADER -// *********************************************************************** -// -// Tpetra: Templated Linear Algebra Services Package -// Copyright (2008) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, -// the U.S. Government retains certain rights in this software. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// -// 3. Neither the name of the Corporation nor the names of the -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Questions? Contact Michael A. Heroux (maherou@sandia.gov) -// -// ************************************************************************ -// @HEADER -*/ + * a cuda intercept for kokkos deep copies, now with counts + */ +#include +#include +#include #include +#include #include #include #include -#include - -//strategy: kokkos::deepcopy a view, count the intercepts. For right now, just report them when mpi_finalize happens. -void OnHost2Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); - /* using range_policy = Kokkos::RangePolicy; - - Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - */ - Kokkos::deep_copy(b, a); -} - -void OnDevice2Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); - using range_policy = Kokkos::RangePolicy; - - Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - - Kokkos::deep_copy(b, a); -} - -void HostToDevice2Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); - /* - Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - */ - Kokkos::deep_copy(b, a); -} - -void DeviceToHost2Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); - /* - Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - */ - Kokkos::deep_copy(b, a); -} - -void OnHost3Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); - Kokkos::DefaultExecutionSpace mySpace; - /* - using range_policy = Kokkos::RangePolicy; - - Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - */ - Kokkos::deep_copy(mySpace, b, a); -} - -void OnDevice3Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); - Kokkos::DefaultExecutionSpace mySpace; - using range_policy = Kokkos::RangePolicy; - - Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - - Kokkos::deep_copy(mySpace, b, a); -} - -void HostToDevice3Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); - Kokkos::DefaultExecutionSpace mySpace; - /* - Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - */ - Kokkos::deep_copy(mySpace, b, a); -} - -void DeviceToHost3Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); - Kokkos::DefaultExecutionSpace mySpace; - /* - Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - */ - Kokkos::deep_copy(mySpace, b, a); -} - -int main(int argc, char *argv[]) { - //initialize - MPI_Init(&argc, &argv); - Kokkos::initialize(argc, argv); - - fprintf (stderr, "Starting copies\n"); - //OnHost2Arg(); - //OnDevice2Arg(); - //HostToDevice2Arg(); - //DeviceToHost2Arg(); - //OnHost3Arg(); - //OnDevice3Arg(); - //HostToDevice3Arg(); - DeviceToHost3Arg(); - fprintf (stderr, "Finished copies\n"); - - fprintf(stderr, "summary statistics\n"); - //finalize - Kokkos::finalize(); - MPI_Finalize(); +#include +namespace ApiTest { + enum devCalls { + cudaDeviceSynchronize, + cudaMemcpy2DAsync, + cudaMemcpy3DAsync, + cudaMemcpyAsync + }; + + std::map totalCounter; + const int numCounters = 4; + + __device__ int *cudaCounters; + int *hostCounters; +} + +int pincr(std::map &store, std::string key, int val) { + std::map::iterator it = store.find(key); + if (it == store.end()) { + store.insert(std::make_pair(key, 1)); + } else { + it->second += val; + } return 0; } +int incr(std::map &store, std::string key) { + return pincr(store, key, 1); +} + +void printAll(std::map &store) { + std::map::iterator it = store.begin(); + fprintf (stderr, "**************** cuda call analysis ****************\n"); + fprintf (stderr, "call\t\ttimes\n"); + while (it != store.end()) { + fprintf(stderr, "%s:\t%d\n", it->first.c_str(), it->second); + it++; + } + fprintf (stderr, "**************** cuda call analysis ****************\n"); +} + +int MPI_Init(int *argc, char ***argv) { + int (*o_mpi_init)(int *, char ***); + o_mpi_init = (int (*)(int *, char ***))dlsym(RTLD_NEXT, "MPI_Init"); + + ApiTest::hostCounters = (int *)malloc (sizeof(int)*4); + for (size_t i = 0; i < 4; i++) { + ApiTest::hostCounters[i] = 0; + } + + return o_mpi_init(argc, argv); +} + +int MPI_Finalize(void) { + fprintf(stderr, "MPI_Finalize()\n"); + int (*o_mpi_finalize)(void); + std::map::iterator f; + o_mpi_finalize = (int (*)(void))dlsym(RTLD_NEXT, "MPI_Finalize"); + + //copies out the device calls + pincr(ApiTest::totalCounter, "cudaDeviceSynchronize", + ApiTest::hostCounters[ApiTest::devCalls::cudaDeviceSynchronize]); + pincr(ApiTest::totalCounter, "cudaMemcpy2DAsync", + ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpy2DAsync]); + pincr(ApiTest::totalCounter, "cudaMemcpy3DAsync", + ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpy3DAsync]); + pincr(ApiTest::totalCounter, "cudaMemcpyAsync", + ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpyAsync]); + + //baseline: these numbers are magic, happen with kokkos initialization + //to update, run KokkosDeepcopy with no deep copies performed and comment + //this section out. + pincr(ApiTest::totalCounter, "cudaDeviceSynchronize", -5); + pincr(ApiTest::totalCounter, "cudaMemcpy", -11); + pincr(ApiTest::totalCounter, "cudaMemcpyToSymbol", -1); + pincr(ApiTest::totalCounter, "cudaMemcpy2DAsync", -1); + pincr(ApiTest::totalCounter, "cudaMemcpy3DAsync", -1); + pincr(ApiTest::totalCounter, "cudaMemcpyAsync", -1); + + free(ApiTest::hostCounters); + + printAll(ApiTest::totalCounter); + + return o_mpi_finalize(); +} + +namespace Kokkos { +void initialize(int& narg, char* arg[]) { + void (*o_init)(int&, char **); + o_init = (void (*)(int&, char **))dlsym(RTLD_NEXT, "_ZN6Kokkos10initializeERiPPc"); + + o_init(narg, arg); + + ApiTest::cudaCounters = (int *)Kokkos::kokkos_malloc("cuda calls", sizeof(int)*4); +} + +void finalize() { + fprintf(stderr, "Kokkos::finalize()\n"); + void (*o_finalize)(void); + o_finalize = (void (*)(void))dlsym(RTLD_NEXT, "_ZN6Kokkos8finalizeEv"); + + //copy ApiTest::cudaCounters into ApiTest::hostCounters + { + // This scoping is important since it ensures the Views deallocate *before* the real Kokkos::finalize() is called. + Kokkos::View h_cudaCounters("host counter temp",ApiTest::numCounters); + Kokkos::View d_cudaCounters(ApiTest::cudaCounters,ApiTest::numCounters); + Kokkos::deep_copy(h_cudaCounters,d_cudaCounters); + + for(int i=0; i(ApiTest::cudaCounters); + } + o_finalize(); +} + +}; + +__host__ __device__ cudaError_t cudaDeviceSynchronize() { + cudaError_t (*o_cudaDeviceSynchronize)(); + o_cudaDeviceSynchronize = (cudaError_t (*)())dlsym(RTLD_NEXT, "cudaDeviceSynchronize"); +#ifdef __CUDA_ARCH__ + Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaDeviceSynchronize]); +#else + incr(ApiTest::totalCounter, "cudaDeviceSynchronize"); +#endif + return o_cudaDeviceSynchronize(); +} + +//Copies data to the given symbol on the device. +__host__ cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpy)(void*, const void*, size_t, cudaMemcpyKind); + o_cudaMemcpy = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy"); + incr(ApiTest::totalCounter, "cudaMemcpy"); + return o_cudaMemcpy(dst, src, count, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpy2D)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind); + o_cudaMemcpy2D = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2D"); + incr(ApiTest::totalCounter, "cudaMemcpy2D"); + return o_cudaMemcpy2D(dst, dpitch, src, spitch, width, height, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DArrayToArray ( cudaArray_t dst, size_t wOffsetDst, size_t hOffsetDst, cudaArray_const_t src, size_t wOffsetSrc, size_t hOffsetSrc, size_t width, size_t height, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpy2DArrayToArray) (cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); + o_cudaMemcpy2DArrayToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DArrayToArray"); + incr(ApiTest::totalCounter, "cudaMemcpy2DArrayToArray"); + return o_cudaMemcpy2DArrayToArray(dst, wOffsetDst, hOffsetDst, src, wOffsetSrc, hOffsetSrc, width, height, kind); +} + +//Copies data between host and device. +__host__ __device__ cudaError_t cudaMemcpy2DAsync ( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy2DAsync) (void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); + o_cudaMemcpy2DAsync = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DAsync"); +#ifdef __CUDA_ARCH__ + Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpy2DAsync]); +#else + incr(ApiTest::totalCounter, "cudaMemcpy2DAsync"); +#endif + return o_cudaMemcpy2DAsync(dst, dpitch, src, spitch, width, height, kind, stream); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DFromArray ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind ) { + cudaError_t (*o_cudaMemcpy2DFromArray) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); + o_cudaMemcpy2DFromArray = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArray"); + incr(ApiTest::totalCounter, "cudaMemcpy2DFromArray"); + return o_cudaMemcpy2DFromArray(dst, dpitch, src, wOffset, hOffset, width, height, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DFromArrayAsync ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy2DFromArrayAsync) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); + o_cudaMemcpy2DFromArrayAsync = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArrayAsync"); + incr(ApiTest::totalCounter, "cudaMemcpy2DFromArrayAsync"); + return o_cudaMemcpy2DFromArrayAsync(dst, dpitch, src, wOffset, hOffset, width, height, kind, stream); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DToArray ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind ) { + cudaError_t (*o_cudaMemcpy2DToArray) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind ); + o_cudaMemcpy2DToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DToArray"); + incr(ApiTest::totalCounter, "cudaMemcpy2DToArray"); + return o_cudaMemcpy2DToArray(dst, wOffset, hOffset, src, spitch, width, height, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DToArrayAsync ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy2DToArrayAsync) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpy2DToArrayAsync = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DToArrayAsync"); + incr(ApiTest::totalCounter, "cudaMemcpy2DToArrayAsync"); + return o_cudaMemcpy2DToArrayAsync(dst, wOffset, hOffset, src, spitch, width, height, kind, stream); +} + +//Copies data between 3D objects. +__host__ cudaError_t cudaMemcpy3D ( const cudaMemcpy3DParms* p ) { + cudaError_t (*o_cudaMemcpy3D) ( const cudaMemcpy3DParms* ); + o_cudaMemcpy3D = (cudaError_t (*)(const cudaMemcpy3DParms*))dlsym(RTLD_NEXT, "cudaMemcpy3D"); + incr(ApiTest::totalCounter, "cudaMemcpy3D"); + return o_cudaMemcpy3D(p); +} + +//Copies data between 3D objects. +__host__ __device__ cudaError_t cudaMemcpy3DAsync ( const cudaMemcpy3DParms* p, cudaStream_t stream ) { + cudaError_t (*o_cudaMemcpy3DAsync) ( const cudaMemcpy3DParms* , cudaStream_t ); + o_cudaMemcpy3DAsync = (cudaError_t (*)(const cudaMemcpy3DParms* , cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DAsync"); +#ifdef __CUDA_ARCH__ + Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpy3DAsync]); +#else + incr(ApiTest::totalCounter, "cudaMemcpy3DAsync"); +#endif + return o_cudaMemcpy3DAsync(p, stream); +} + +//Copies memory between devices. +__host__ cudaError_t cudaMemcpy3DPeer ( const cudaMemcpy3DPeerParms* p ) { + cudaError_t (*o_cudaMemcpy3DPeer) ( const cudaMemcpy3DPeerParms* ); + o_cudaMemcpy3DPeer = (cudaError_t (*)(const cudaMemcpy3DPeerParms*))dlsym(RTLD_NEXT, "cudaMemcpy3DPeer"); + incr(ApiTest::totalCounter, "cudaMemcpy3DPeer"); + return o_cudaMemcpy3DPeer(p); +} + +//Copies memory between devices asynchronously. +__host__ cudaError_t cudaMemcpy3DPeerAsync ( const cudaMemcpy3DPeerParms* p, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy3DPeerAsync) ( const cudaMemcpy3DPeerParms*, cudaStream_t ); + o_cudaMemcpy3DPeerAsync = (cudaError_t (*)(const cudaMemcpy3DPeerParms*, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DPeerAsync"); + incr(ApiTest::totalCounter, "cudaMemcpy3DPeerAsync"); + return o_cudaMemcpy3DPeerAsync(p, stream); +} + +//Copies data between host and device. +__host__ __device__ cudaError_t cudaMemcpyAsync ( void* dst, const void* src, size_t count, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpyAsync) ( void*, const void*, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpyAsync = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpyAsync"); +#ifdef __CUDA_ARCH__ + Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpyAsync]); +#else + incr(ApiTest::totalCounter, "cudaMemcpyAsync"); +#endif + return o_cudaMemcpyAsync(dst, src, count, kind, stream); +} + +//Copies data from the given symbol on the device. +__host__ cudaError_t cudaMemcpyFromSymbol ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpyFromSymbol) ( void*, const void*, size_t, size_t, cudaMemcpyKind ); + o_cudaMemcpyFromSymbol = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbol"); + incr(ApiTest::totalCounter, "cudaMemcpyFromSymbol"); + return o_cudaMemcpyFromSymbol(dst, symbol, count, offset, kind); +} + +//Copies data from the given symbol on the device. +__host__ cudaError_t cudaMemcpyFromSymbolAsync ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpyFromSymbolAsync) ( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpyFromSymbolAsync = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbolAsync"); + incr(ApiTest::totalCounter, "cudaMemcpyFromSymbolAsync"); + return o_cudaMemcpyFromSymbolAsync(dst, symbol, count, offset, kind, stream); +} + +//Copies memory between two devices. +__host__ cudaError_t cudaMemcpyPeer ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count ) { + cudaError_t (*o_cudaMemcpyPeer) ( void*, int, const void*, int, size_t ); + o_cudaMemcpyPeer = (cudaError_t (*)( void*, int, const void*, int, size_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeer"); + incr(ApiTest::totalCounter, "cudaMemcpyPeer"); + return o_cudaMemcpyPeer(dst, dstDevice, src, srcDevice, count); +} + +//Copies memory between two devices asynchronously. +__host__ cudaError_t cudaMemcpyPeerAsync ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpyPeerAsync) ( void*, int, const void*, int, size_t, cudaStream_t ); + o_cudaMemcpyPeerAsync = (cudaError_t (*)( void*, int, const void*, int, size_t, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeerAsync"); + incr(ApiTest::totalCounter, "cudaMemcpyPeerAsync"); + return o_cudaMemcpyPeerAsync(dst, dstDevice, src, srcDevice, count, stream); +} + +//Copies data to the given symbol on the device. +__host__ cudaError_t cudaMemcpyToSymbol ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind ) { + cudaError_t (*o_cudaMemcpyToSymbol) ( const void*, const void*, size_t, size_t, cudaMemcpyKind ); + o_cudaMemcpyToSymbol = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbol"); + incr(ApiTest::totalCounter, "cudaMemcpyToSymbol"); + return o_cudaMemcpyToSymbol(symbol, src, count, offset, kind); +} + +//Copies data to the given symbol on the device. +__host__ cudaError_t cudaMemcpyToSymbolAsync ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream ) { + cudaError_t (*o_cudaMemcpyToSymbolAsync) ( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpyToSymbolAsync = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbolAsync"); + incr(ApiTest::totalCounter, "cudaMemcpyToSymbolAsync"); + return o_cudaMemcpyToSymbolAsync(symbol, src, count, offset, kind, stream); +} diff --git a/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp b/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp index 03f93e3a47c3..a0a77ab4cf5b 100644 --- a/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp +++ b/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp @@ -41,60 +41,139 @@ // @HEADER */ -#include - +#include +#include #include #include +#include + +//strategy: kokkos::deepcopy a view, count the intercepts. For right now, just report them when mpi_finalize happens. +void OnHost2Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + /* using range_policy = Kokkos::RangePolicy; + + Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(b, a); +} + +void OnDevice2Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + using range_policy = Kokkos::RangePolicy; + + Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + + Kokkos::deep_copy(b, a); +} + +void HostToDevice2Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + /* + Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(b, a); +} + +void DeviceToHost2Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + /* + Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(b, a); +} + +void OnHost3Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + Kokkos::DefaultExecutionSpace mySpace; + /* + using range_policy = Kokkos::RangePolicy; + + Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(mySpace, b, a); +} + +void OnDevice3Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + Kokkos::DefaultExecutionSpace mySpace; + using range_policy = Kokkos::RangePolicy; + + Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + + Kokkos::deep_copy(mySpace, b, a); +} + +void HostToDevice3Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + Kokkos::DefaultExecutionSpace mySpace; + /* + Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(mySpace, b, a); +} + +void DeviceToHost3Arg() { + int N=100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + Kokkos::DefaultExecutionSpace mySpace; + /* + Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(mySpace, b, a); +} + +int main(int argc, char *argv[]) { + //initialize + MPI_Init(&argc, &argv); + Kokkos::initialize(argc, argv); + + fprintf (stderr, "Starting copies\n"); + //OnHost2Arg(); + //OnDevice2Arg(); + //HostToDevice2Arg(); + //DeviceToHost2Arg(); + //OnHost3Arg(); + //OnDevice3Arg(); + //HostToDevice3Arg(); + DeviceToHost3Arg(); + fprintf (stderr, "Finished copies\n"); + + fprintf(stderr, "summary statistics\n"); + //finalize + Kokkos::finalize(); + MPI_Finalize(); + + return 0; +} -class DeepcopyTester { -public: - DeepcopyTester() { } - - void run() { - log("Tpetra Kokkos Deepcopy test start"); - - OnHost(); - OnDevice(); - HostToDevice(); - DeviceToHost(); - - if (isConsistent) log("+++ Result is consistent +++"); - else log("!!! Result is inconsistent !!!"); - } - - //strategy: kokkos::deepcopy a view, count the intercepts. For right now, just report them when mpi_finalize happens. - void OnHost() { - Kokkos::View a ("a", 1); - Kokkos::View b ("b", 1); - - Kokkos::deep_copy(a, b); - } - - void OnDevice() { - Kokkos::View a ("a", 1); - Kokkos::View b ("b", 1); - - Kokkos::deep_copy(a, b); - } - - void HostToDevice() { - Kokkos::View a ("a", 1); - Kokkos::View b ("b", 1); - - Kokkos::deep_copy(a, b); - } - - void DeviceToHost() { - Kokkos::View a ("a", 1); - Kokkos::View b ("b", 1); - - Kokkos::deep_copy(a, b); - } - -private: - bool isConsistent = true; - void log(const std::string& msg) { - std::cout << msg << std::endl; - } - -}; diff --git a/packages/tpetra/core/test/KokkosIntegration/intercept.cpp b/packages/tpetra/core/test/KokkosIntegration/intercept.cpp new file mode 100644 index 000000000000..0fbe47546acb --- /dev/null +++ b/packages/tpetra/core/test/KokkosIntegration/intercept.cpp @@ -0,0 +1,312 @@ +/* + * a cuda intercept for kokkos deep copies, now with counts + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ApiTest { + enum devCalls { + cudaDeviceSynchronize, + cudaMemcpy2DAsync, + cudaMemcpy3DAsync, + cudaMemcpyAsync + }; + + std::map totalCounter; + const int numCounters = 4; + + __device__ int *cudaCounters; + int *hostCounters; +} + +int pincr(std::map &store, std::string key, int val) { + std::map::iterator it = store.find(key); + if (it == store.end()) { + store.insert(std::make_pair(key, 1)); + } else { + it->second += val; + } + return 0; +} + +int incr(std::map &store, std::string key) { + return pincr(store, key, 1); +} + +void printAll(std::map &store) { + std::map::iterator it = store.begin(); + fprintf (stderr, "**************** cuda call analysis ****************\n"); + fprintf (stderr, "call\t\ttimes\n"); + while (it != store.end()) { + fprintf(stderr, "%s:\t%d\n", it->first.c_str(), it->second); + it++; + } + fprintf (stderr, "**************** cuda call analysis ****************\n"); +} + +int MPI_Init(int *argc, char ***argv) { + int (*o_mpi_init)(int *, char ***); + o_mpi_init = (int (*)(int *, char ***))dlsym(RTLD_NEXT, "MPI_Init"); + + ApiTest::hostCounters = (int *)malloc (sizeof(int)*4); + for (size_t i = 0; i < 4; i++) { + ApiTest::hostCounters[i] = 0; + } + + return o_mpi_init(argc, argv); +} + +int MPI_Finalize(void) { + fprintf(stderr, "MPI_Finalize()\n"); + int (*o_mpi_finalize)(void); + std::map::iterator f; + o_mpi_finalize = (int (*)(void))dlsym(RTLD_NEXT, "MPI_Finalize"); + + //copies out the device calls + pincr(ApiTest::totalCounter, "cudaDeviceSynchronize", + ApiTest::hostCounters[ApiTest::devCalls::cudaDeviceSynchronize]); + pincr(ApiTest::totalCounter, "cudaMemcpy2DAsync", + ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpy2DAsync]); + pincr(ApiTest::totalCounter, "cudaMemcpy3DAsync", + ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpy3DAsync]); + pincr(ApiTest::totalCounter, "cudaMemcpyAsync", + ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpyAsync]); + + //baseline: these numbers are magic, happen with kokkos initialization + //to update, run KokkosDeepcopy with no deep copies performed and comment + //this section out. + pincr(ApiTest::totalCounter, "cudaDeviceSynchronize", -5); + pincr(ApiTest::totalCounter, "cudaMemcpy", -11); + pincr(ApiTest::totalCounter, "cudaMemcpyToSymbol", -1); + pincr(ApiTest::totalCounter, "cudaMemcpy2DAsync", -1); + pincr(ApiTest::totalCounter, "cudaMemcpy3DAsync", -1); + pincr(ApiTest::totalCounter, "cudaMemcpyAsync", -1); + + free(ApiTest::hostCounters); + + printAll(ApiTest::totalCounter); + + return o_mpi_finalize(); +} + +namespace Kokkos { +void initialize(int& narg, char* arg[]) { + void (*o_init)(int&, char **); + o_init = (void (*)(int&, char **))dlsym(RTLD_NEXT, "_ZN6Kokkos10initializeERiPPc"); + + o_init(narg, arg); + + ApiTest::cudaCounters = (int *)Kokkos::kokkos_malloc("cuda calls", sizeof(int)*4); +} + +void finalize() { + fprintf(stderr, "Kokkos::finalize()\n"); + void (*o_finalize)(void); + o_finalize = (void (*)(void))dlsym(RTLD_NEXT, "_ZN6Kokkos8finalizeEv"); + + //copy ApiTest::cudaCounters into ApiTest::hostCounters + { + // This scoping is important since it ensures the Views deallocate *before* the real Kokkos::finalize() is called. + Kokkos::View h_cudaCounters("host counter temp",ApiTest::numCounters); + Kokkos::View d_cudaCounters(ApiTest::cudaCounters,ApiTest::numCounters); + Kokkos::deep_copy(h_cudaCounters,d_cudaCounters); + + for(int i=0; i(ApiTest::cudaCounters); + } + o_finalize(); +} + +}; + +__host__ __device__ cudaError_t cudaDeviceSynchronize() { + cudaError_t (*o_cudaDeviceSynchronize)(); + o_cudaDeviceSynchronize = (cudaError_t (*)())dlsym(RTLD_NEXT, "cudaDeviceSynchronize"); +#ifdef __CUDA_ARCH__ + Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaDeviceSynchronize]); +#else + incr(ApiTest::totalCounter, "cudaDeviceSynchronize"); +#endif + return o_cudaDeviceSynchronize(); +} + +//Copies data to the given symbol on the device. +__host__ cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpy)(void*, const void*, size_t, cudaMemcpyKind); + o_cudaMemcpy = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy"); + incr(ApiTest::totalCounter, "cudaMemcpy"); + return o_cudaMemcpy(dst, src, count, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpy2D)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind); + o_cudaMemcpy2D = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2D"); + incr(ApiTest::totalCounter, "cudaMemcpy2D"); + return o_cudaMemcpy2D(dst, dpitch, src, spitch, width, height, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DArrayToArray ( cudaArray_t dst, size_t wOffsetDst, size_t hOffsetDst, cudaArray_const_t src, size_t wOffsetSrc, size_t hOffsetSrc, size_t width, size_t height, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpy2DArrayToArray) (cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); + o_cudaMemcpy2DArrayToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DArrayToArray"); + incr(ApiTest::totalCounter, "cudaMemcpy2DArrayToArray"); + return o_cudaMemcpy2DArrayToArray(dst, wOffsetDst, hOffsetDst, src, wOffsetSrc, hOffsetSrc, width, height, kind); +} + +//Copies data between host and device. +__host__ __device__ cudaError_t cudaMemcpy2DAsync ( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy2DAsync) (void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); + o_cudaMemcpy2DAsync = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DAsync"); +#ifdef __CUDA_ARCH__ + Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpy2DAsync]); +#else + incr(ApiTest::totalCounter, "cudaMemcpy2DAsync"); +#endif + return o_cudaMemcpy2DAsync(dst, dpitch, src, spitch, width, height, kind, stream); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DFromArray ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind ) { + cudaError_t (*o_cudaMemcpy2DFromArray) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); + o_cudaMemcpy2DFromArray = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArray"); + incr(ApiTest::totalCounter, "cudaMemcpy2DFromArray"); + return o_cudaMemcpy2DFromArray(dst, dpitch, src, wOffset, hOffset, width, height, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DFromArrayAsync ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy2DFromArrayAsync) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); + o_cudaMemcpy2DFromArrayAsync = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArrayAsync"); + incr(ApiTest::totalCounter, "cudaMemcpy2DFromArrayAsync"); + return o_cudaMemcpy2DFromArrayAsync(dst, dpitch, src, wOffset, hOffset, width, height, kind, stream); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DToArray ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind ) { + cudaError_t (*o_cudaMemcpy2DToArray) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind ); + o_cudaMemcpy2DToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DToArray"); + incr(ApiTest::totalCounter, "cudaMemcpy2DToArray"); + return o_cudaMemcpy2DToArray(dst, wOffset, hOffset, src, spitch, width, height, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DToArrayAsync ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy2DToArrayAsync) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpy2DToArrayAsync = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DToArrayAsync"); + incr(ApiTest::totalCounter, "cudaMemcpy2DToArrayAsync"); + return o_cudaMemcpy2DToArrayAsync(dst, wOffset, hOffset, src, spitch, width, height, kind, stream); +} + +//Copies data between 3D objects. +__host__ cudaError_t cudaMemcpy3D ( const cudaMemcpy3DParms* p ) { + cudaError_t (*o_cudaMemcpy3D) ( const cudaMemcpy3DParms* ); + o_cudaMemcpy3D = (cudaError_t (*)(const cudaMemcpy3DParms*))dlsym(RTLD_NEXT, "cudaMemcpy3D"); + incr(ApiTest::totalCounter, "cudaMemcpy3D"); + return o_cudaMemcpy3D(p); +} + +//Copies data between 3D objects. +__host__ __device__ cudaError_t cudaMemcpy3DAsync ( const cudaMemcpy3DParms* p, cudaStream_t stream ) { + cudaError_t (*o_cudaMemcpy3DAsync) ( const cudaMemcpy3DParms* , cudaStream_t ); + o_cudaMemcpy3DAsync = (cudaError_t (*)(const cudaMemcpy3DParms* , cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DAsync"); +#ifdef __CUDA_ARCH__ + Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpy3DAsync]); +#else + incr(ApiTest::totalCounter, "cudaMemcpy3DAsync"); +#endif + return o_cudaMemcpy3DAsync(p, stream); +} + +//Copies memory between devices. +__host__ cudaError_t cudaMemcpy3DPeer ( const cudaMemcpy3DPeerParms* p ) { + cudaError_t (*o_cudaMemcpy3DPeer) ( const cudaMemcpy3DPeerParms* ); + o_cudaMemcpy3DPeer = (cudaError_t (*)(const cudaMemcpy3DPeerParms*))dlsym(RTLD_NEXT, "cudaMemcpy3DPeer"); + incr(ApiTest::totalCounter, "cudaMemcpy3DPeer"); + return o_cudaMemcpy3DPeer(p); +} + +//Copies memory between devices asynchronously. +__host__ cudaError_t cudaMemcpy3DPeerAsync ( const cudaMemcpy3DPeerParms* p, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy3DPeerAsync) ( const cudaMemcpy3DPeerParms*, cudaStream_t ); + o_cudaMemcpy3DPeerAsync = (cudaError_t (*)(const cudaMemcpy3DPeerParms*, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DPeerAsync"); + incr(ApiTest::totalCounter, "cudaMemcpy3DPeerAsync"); + return o_cudaMemcpy3DPeerAsync(p, stream); +} + +//Copies data between host and device. +__host__ __device__ cudaError_t cudaMemcpyAsync ( void* dst, const void* src, size_t count, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpyAsync) ( void*, const void*, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpyAsync = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpyAsync"); +#ifdef __CUDA_ARCH__ + Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpyAsync]); +#else + incr(ApiTest::totalCounter, "cudaMemcpyAsync"); +#endif + return o_cudaMemcpyAsync(dst, src, count, kind, stream); +} + +//Copies data from the given symbol on the device. +__host__ cudaError_t cudaMemcpyFromSymbol ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpyFromSymbol) ( void*, const void*, size_t, size_t, cudaMemcpyKind ); + o_cudaMemcpyFromSymbol = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbol"); + incr(ApiTest::totalCounter, "cudaMemcpyFromSymbol"); + return o_cudaMemcpyFromSymbol(dst, symbol, count, offset, kind); +} + +//Copies data from the given symbol on the device. +__host__ cudaError_t cudaMemcpyFromSymbolAsync ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpyFromSymbolAsync) ( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpyFromSymbolAsync = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbolAsync"); + incr(ApiTest::totalCounter, "cudaMemcpyFromSymbolAsync"); + return o_cudaMemcpyFromSymbolAsync(dst, symbol, count, offset, kind, stream); +} + +//Copies memory between two devices. +__host__ cudaError_t cudaMemcpyPeer ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count ) { + cudaError_t (*o_cudaMemcpyPeer) ( void*, int, const void*, int, size_t ); + o_cudaMemcpyPeer = (cudaError_t (*)( void*, int, const void*, int, size_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeer"); + incr(ApiTest::totalCounter, "cudaMemcpyPeer"); + return o_cudaMemcpyPeer(dst, dstDevice, src, srcDevice, count); +} + +//Copies memory between two devices asynchronously. +__host__ cudaError_t cudaMemcpyPeerAsync ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpyPeerAsync) ( void*, int, const void*, int, size_t, cudaStream_t ); + o_cudaMemcpyPeerAsync = (cudaError_t (*)( void*, int, const void*, int, size_t, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeerAsync"); + incr(ApiTest::totalCounter, "cudaMemcpyPeerAsync"); + return o_cudaMemcpyPeerAsync(dst, dstDevice, src, srcDevice, count, stream); +} + +//Copies data to the given symbol on the device. +__host__ cudaError_t cudaMemcpyToSymbol ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind ) { + cudaError_t (*o_cudaMemcpyToSymbol) ( const void*, const void*, size_t, size_t, cudaMemcpyKind ); + o_cudaMemcpyToSymbol = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbol"); + incr(ApiTest::totalCounter, "cudaMemcpyToSymbol"); + return o_cudaMemcpyToSymbol(symbol, src, count, offset, kind); +} + +//Copies data to the given symbol on the device. +__host__ cudaError_t cudaMemcpyToSymbolAsync ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream ) { + cudaError_t (*o_cudaMemcpyToSymbolAsync) ( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpyToSymbolAsync = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbolAsync"); + incr(ApiTest::totalCounter, "cudaMemcpyToSymbolAsync"); + return o_cudaMemcpyToSymbolAsync(symbol, src, count, offset, kind, stream); +} From 7bc3b85e9b12aee8dd488cb2b2cb4b9d772e08e0 Mon Sep 17 00:00:00 2001 From: Geoffrey C Danielson Date: Wed, 7 Oct 2020 09:24:21 -0600 Subject: [PATCH 003/147] remove old file to comply with naming standards --- .../core/test/KokkosIntegration/intercept.cpp | 312 ------------------ 1 file changed, 312 deletions(-) delete mode 100644 packages/tpetra/core/test/KokkosIntegration/intercept.cpp diff --git a/packages/tpetra/core/test/KokkosIntegration/intercept.cpp b/packages/tpetra/core/test/KokkosIntegration/intercept.cpp deleted file mode 100644 index 0fbe47546acb..000000000000 --- a/packages/tpetra/core/test/KokkosIntegration/intercept.cpp +++ /dev/null @@ -1,312 +0,0 @@ -/* - * a cuda intercept for kokkos deep copies, now with counts - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace ApiTest { - enum devCalls { - cudaDeviceSynchronize, - cudaMemcpy2DAsync, - cudaMemcpy3DAsync, - cudaMemcpyAsync - }; - - std::map totalCounter; - const int numCounters = 4; - - __device__ int *cudaCounters; - int *hostCounters; -} - -int pincr(std::map &store, std::string key, int val) { - std::map::iterator it = store.find(key); - if (it == store.end()) { - store.insert(std::make_pair(key, 1)); - } else { - it->second += val; - } - return 0; -} - -int incr(std::map &store, std::string key) { - return pincr(store, key, 1); -} - -void printAll(std::map &store) { - std::map::iterator it = store.begin(); - fprintf (stderr, "**************** cuda call analysis ****************\n"); - fprintf (stderr, "call\t\ttimes\n"); - while (it != store.end()) { - fprintf(stderr, "%s:\t%d\n", it->first.c_str(), it->second); - it++; - } - fprintf (stderr, "**************** cuda call analysis ****************\n"); -} - -int MPI_Init(int *argc, char ***argv) { - int (*o_mpi_init)(int *, char ***); - o_mpi_init = (int (*)(int *, char ***))dlsym(RTLD_NEXT, "MPI_Init"); - - ApiTest::hostCounters = (int *)malloc (sizeof(int)*4); - for (size_t i = 0; i < 4; i++) { - ApiTest::hostCounters[i] = 0; - } - - return o_mpi_init(argc, argv); -} - -int MPI_Finalize(void) { - fprintf(stderr, "MPI_Finalize()\n"); - int (*o_mpi_finalize)(void); - std::map::iterator f; - o_mpi_finalize = (int (*)(void))dlsym(RTLD_NEXT, "MPI_Finalize"); - - //copies out the device calls - pincr(ApiTest::totalCounter, "cudaDeviceSynchronize", - ApiTest::hostCounters[ApiTest::devCalls::cudaDeviceSynchronize]); - pincr(ApiTest::totalCounter, "cudaMemcpy2DAsync", - ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpy2DAsync]); - pincr(ApiTest::totalCounter, "cudaMemcpy3DAsync", - ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpy3DAsync]); - pincr(ApiTest::totalCounter, "cudaMemcpyAsync", - ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpyAsync]); - - //baseline: these numbers are magic, happen with kokkos initialization - //to update, run KokkosDeepcopy with no deep copies performed and comment - //this section out. - pincr(ApiTest::totalCounter, "cudaDeviceSynchronize", -5); - pincr(ApiTest::totalCounter, "cudaMemcpy", -11); - pincr(ApiTest::totalCounter, "cudaMemcpyToSymbol", -1); - pincr(ApiTest::totalCounter, "cudaMemcpy2DAsync", -1); - pincr(ApiTest::totalCounter, "cudaMemcpy3DAsync", -1); - pincr(ApiTest::totalCounter, "cudaMemcpyAsync", -1); - - free(ApiTest::hostCounters); - - printAll(ApiTest::totalCounter); - - return o_mpi_finalize(); -} - -namespace Kokkos { -void initialize(int& narg, char* arg[]) { - void (*o_init)(int&, char **); - o_init = (void (*)(int&, char **))dlsym(RTLD_NEXT, "_ZN6Kokkos10initializeERiPPc"); - - o_init(narg, arg); - - ApiTest::cudaCounters = (int *)Kokkos::kokkos_malloc("cuda calls", sizeof(int)*4); -} - -void finalize() { - fprintf(stderr, "Kokkos::finalize()\n"); - void (*o_finalize)(void); - o_finalize = (void (*)(void))dlsym(RTLD_NEXT, "_ZN6Kokkos8finalizeEv"); - - //copy ApiTest::cudaCounters into ApiTest::hostCounters - { - // This scoping is important since it ensures the Views deallocate *before* the real Kokkos::finalize() is called. - Kokkos::View h_cudaCounters("host counter temp",ApiTest::numCounters); - Kokkos::View d_cudaCounters(ApiTest::cudaCounters,ApiTest::numCounters); - Kokkos::deep_copy(h_cudaCounters,d_cudaCounters); - - for(int i=0; i(ApiTest::cudaCounters); - } - o_finalize(); -} - -}; - -__host__ __device__ cudaError_t cudaDeviceSynchronize() { - cudaError_t (*o_cudaDeviceSynchronize)(); - o_cudaDeviceSynchronize = (cudaError_t (*)())dlsym(RTLD_NEXT, "cudaDeviceSynchronize"); -#ifdef __CUDA_ARCH__ - Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaDeviceSynchronize]); -#else - incr(ApiTest::totalCounter, "cudaDeviceSynchronize"); -#endif - return o_cudaDeviceSynchronize(); -} - -//Copies data to the given symbol on the device. -__host__ cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMemcpyKind kind) { - cudaError_t (*o_cudaMemcpy)(void*, const void*, size_t, cudaMemcpyKind); - o_cudaMemcpy = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy"); - incr(ApiTest::totalCounter, "cudaMemcpy"); - return o_cudaMemcpy(dst, src, count, kind); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind) { - cudaError_t (*o_cudaMemcpy2D)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind); - o_cudaMemcpy2D = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2D"); - incr(ApiTest::totalCounter, "cudaMemcpy2D"); - return o_cudaMemcpy2D(dst, dpitch, src, spitch, width, height, kind); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2DArrayToArray ( cudaArray_t dst, size_t wOffsetDst, size_t hOffsetDst, cudaArray_const_t src, size_t wOffsetSrc, size_t hOffsetSrc, size_t width, size_t height, cudaMemcpyKind kind) { - cudaError_t (*o_cudaMemcpy2DArrayToArray) (cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); - o_cudaMemcpy2DArrayToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DArrayToArray"); - incr(ApiTest::totalCounter, "cudaMemcpy2DArrayToArray"); - return o_cudaMemcpy2DArrayToArray(dst, wOffsetDst, hOffsetDst, src, wOffsetSrc, hOffsetSrc, width, height, kind); -} - -//Copies data between host and device. -__host__ __device__ cudaError_t cudaMemcpy2DAsync ( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpy2DAsync) (void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); - o_cudaMemcpy2DAsync = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DAsync"); -#ifdef __CUDA_ARCH__ - Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpy2DAsync]); -#else - incr(ApiTest::totalCounter, "cudaMemcpy2DAsync"); -#endif - return o_cudaMemcpy2DAsync(dst, dpitch, src, spitch, width, height, kind, stream); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2DFromArray ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind ) { - cudaError_t (*o_cudaMemcpy2DFromArray) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); - o_cudaMemcpy2DFromArray = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArray"); - incr(ApiTest::totalCounter, "cudaMemcpy2DFromArray"); - return o_cudaMemcpy2DFromArray(dst, dpitch, src, wOffset, hOffset, width, height, kind); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2DFromArrayAsync ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpy2DFromArrayAsync) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); - o_cudaMemcpy2DFromArrayAsync = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArrayAsync"); - incr(ApiTest::totalCounter, "cudaMemcpy2DFromArrayAsync"); - return o_cudaMemcpy2DFromArrayAsync(dst, dpitch, src, wOffset, hOffset, width, height, kind, stream); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2DToArray ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind ) { - cudaError_t (*o_cudaMemcpy2DToArray) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind ); - o_cudaMemcpy2DToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DToArray"); - incr(ApiTest::totalCounter, "cudaMemcpy2DToArray"); - return o_cudaMemcpy2DToArray(dst, wOffset, hOffset, src, spitch, width, height, kind); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2DToArrayAsync ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpy2DToArrayAsync) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t ); - o_cudaMemcpy2DToArrayAsync = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DToArrayAsync"); - incr(ApiTest::totalCounter, "cudaMemcpy2DToArrayAsync"); - return o_cudaMemcpy2DToArrayAsync(dst, wOffset, hOffset, src, spitch, width, height, kind, stream); -} - -//Copies data between 3D objects. -__host__ cudaError_t cudaMemcpy3D ( const cudaMemcpy3DParms* p ) { - cudaError_t (*o_cudaMemcpy3D) ( const cudaMemcpy3DParms* ); - o_cudaMemcpy3D = (cudaError_t (*)(const cudaMemcpy3DParms*))dlsym(RTLD_NEXT, "cudaMemcpy3D"); - incr(ApiTest::totalCounter, "cudaMemcpy3D"); - return o_cudaMemcpy3D(p); -} - -//Copies data between 3D objects. -__host__ __device__ cudaError_t cudaMemcpy3DAsync ( const cudaMemcpy3DParms* p, cudaStream_t stream ) { - cudaError_t (*o_cudaMemcpy3DAsync) ( const cudaMemcpy3DParms* , cudaStream_t ); - o_cudaMemcpy3DAsync = (cudaError_t (*)(const cudaMemcpy3DParms* , cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DAsync"); -#ifdef __CUDA_ARCH__ - Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpy3DAsync]); -#else - incr(ApiTest::totalCounter, "cudaMemcpy3DAsync"); -#endif - return o_cudaMemcpy3DAsync(p, stream); -} - -//Copies memory between devices. -__host__ cudaError_t cudaMemcpy3DPeer ( const cudaMemcpy3DPeerParms* p ) { - cudaError_t (*o_cudaMemcpy3DPeer) ( const cudaMemcpy3DPeerParms* ); - o_cudaMemcpy3DPeer = (cudaError_t (*)(const cudaMemcpy3DPeerParms*))dlsym(RTLD_NEXT, "cudaMemcpy3DPeer"); - incr(ApiTest::totalCounter, "cudaMemcpy3DPeer"); - return o_cudaMemcpy3DPeer(p); -} - -//Copies memory between devices asynchronously. -__host__ cudaError_t cudaMemcpy3DPeerAsync ( const cudaMemcpy3DPeerParms* p, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpy3DPeerAsync) ( const cudaMemcpy3DPeerParms*, cudaStream_t ); - o_cudaMemcpy3DPeerAsync = (cudaError_t (*)(const cudaMemcpy3DPeerParms*, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DPeerAsync"); - incr(ApiTest::totalCounter, "cudaMemcpy3DPeerAsync"); - return o_cudaMemcpy3DPeerAsync(p, stream); -} - -//Copies data between host and device. -__host__ __device__ cudaError_t cudaMemcpyAsync ( void* dst, const void* src, size_t count, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpyAsync) ( void*, const void*, size_t, cudaMemcpyKind, cudaStream_t ); - o_cudaMemcpyAsync = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpyAsync"); -#ifdef __CUDA_ARCH__ - Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpyAsync]); -#else - incr(ApiTest::totalCounter, "cudaMemcpyAsync"); -#endif - return o_cudaMemcpyAsync(dst, src, count, kind, stream); -} - -//Copies data from the given symbol on the device. -__host__ cudaError_t cudaMemcpyFromSymbol ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind) { - cudaError_t (*o_cudaMemcpyFromSymbol) ( void*, const void*, size_t, size_t, cudaMemcpyKind ); - o_cudaMemcpyFromSymbol = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbol"); - incr(ApiTest::totalCounter, "cudaMemcpyFromSymbol"); - return o_cudaMemcpyFromSymbol(dst, symbol, count, offset, kind); -} - -//Copies data from the given symbol on the device. -__host__ cudaError_t cudaMemcpyFromSymbolAsync ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpyFromSymbolAsync) ( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); - o_cudaMemcpyFromSymbolAsync = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbolAsync"); - incr(ApiTest::totalCounter, "cudaMemcpyFromSymbolAsync"); - return o_cudaMemcpyFromSymbolAsync(dst, symbol, count, offset, kind, stream); -} - -//Copies memory between two devices. -__host__ cudaError_t cudaMemcpyPeer ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count ) { - cudaError_t (*o_cudaMemcpyPeer) ( void*, int, const void*, int, size_t ); - o_cudaMemcpyPeer = (cudaError_t (*)( void*, int, const void*, int, size_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeer"); - incr(ApiTest::totalCounter, "cudaMemcpyPeer"); - return o_cudaMemcpyPeer(dst, dstDevice, src, srcDevice, count); -} - -//Copies memory between two devices asynchronously. -__host__ cudaError_t cudaMemcpyPeerAsync ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpyPeerAsync) ( void*, int, const void*, int, size_t, cudaStream_t ); - o_cudaMemcpyPeerAsync = (cudaError_t (*)( void*, int, const void*, int, size_t, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeerAsync"); - incr(ApiTest::totalCounter, "cudaMemcpyPeerAsync"); - return o_cudaMemcpyPeerAsync(dst, dstDevice, src, srcDevice, count, stream); -} - -//Copies data to the given symbol on the device. -__host__ cudaError_t cudaMemcpyToSymbol ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind ) { - cudaError_t (*o_cudaMemcpyToSymbol) ( const void*, const void*, size_t, size_t, cudaMemcpyKind ); - o_cudaMemcpyToSymbol = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbol"); - incr(ApiTest::totalCounter, "cudaMemcpyToSymbol"); - return o_cudaMemcpyToSymbol(symbol, src, count, offset, kind); -} - -//Copies data to the given symbol on the device. -__host__ cudaError_t cudaMemcpyToSymbolAsync ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream ) { - cudaError_t (*o_cudaMemcpyToSymbolAsync) ( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); - o_cudaMemcpyToSymbolAsync = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbolAsync"); - incr(ApiTest::totalCounter, "cudaMemcpyToSymbolAsync"); - return o_cudaMemcpyToSymbolAsync(symbol, src, count, offset, kind, stream); -} From 0becc0630460fce6825436e52ccff4e2811bcda6 Mon Sep 17 00:00:00 2001 From: Geoffrey C Danielson Date: Wed, 7 Oct 2020 16:08:49 -0600 Subject: [PATCH 004/147] addresses some TODOs --- .../core/test/KokkosIntegration/ApiTest.cpp | 56 ++++ .../core/test/KokkosIntegration/ApiTest.h | 39 +++ .../test/KokkosIntegration/KokkosDeepcopy.cpp | 86 +++--- .../core/test/KokkosIntegration/intercept.cpp | 262 ++++++++++++++++++ 4 files changed, 394 insertions(+), 49 deletions(-) create mode 100644 packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp create mode 100644 packages/tpetra/core/test/KokkosIntegration/ApiTest.h create mode 100644 packages/tpetra/core/test/KokkosIntegration/intercept.cpp diff --git a/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp b/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp new file mode 100644 index 000000000000..705f73a92541 --- /dev/null +++ b/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp @@ -0,0 +1,56 @@ + +#include +#include +#include +#include "ApiTest.h" + +ApiTest::ApiTest() { } + +ApiTest::~ApiTest() { } + +int ApiTest::setExpectations(std::map &exp) { + for (std::map::iterator it = exp.begin(); + it != exp.end(); it++) { + std::map >::iterator found = counter.find(it->first); + if (found != counter.end()) { + found->second.second = it->second; + } else { + return -1; + } + } + return 0; +} + +void ApiTest::map_zero() { + for (std::list::iterator it = ApiTest::funcs.begin(); it != ApiTest::funcs.end(); it++) { + std::map >::iterator found = counter.find(*it); + if (found != counter.end()) { + found->second = std::make_pair(0, 0); + } else { + counter.insert(std::make_pair(*it, std::make_pair(0, 0))); + } + } +} + +void ApiTest::pincr(std::string key, int val) { + std::map >::iterator it = counter.find(key); + if (it == counter.end()) { + counter.insert(std::make_pair(key, std::make_pair(1, 0))); + } else { + it->second.first += val; + } +} + +void ApiTest::incr(std::string key) { + pincr(key, 1); +} + +void ApiTest::printAll() { + fprintf (stderr, "**************** cuda call analysis ****************\n"); + fprintf (stderr, "call times\n"); + for (std::map >::iterator it = counter.begin(); + it != counter.end(); it++) { + fprintf(stderr, "%-50s %d\t%d\n", it->first.c_str(), it->second.first, it->second.second); + } + fprintf (stderr, "**************** cuda call analysis ****************\n"); +} diff --git a/packages/tpetra/core/test/KokkosIntegration/ApiTest.h b/packages/tpetra/core/test/KokkosIntegration/ApiTest.h new file mode 100644 index 000000000000..d6642fc42e5c --- /dev/null +++ b/packages/tpetra/core/test/KokkosIntegration/ApiTest.h @@ -0,0 +1,39 @@ +#ifndef __API_TEST_H__ +#define __API_TEST_H__ + +class ApiTest { + public: + ApiTest(); + ~ApiTest(); + int setExpectations(std::map &exp); + void map_zero(); + void pincr(std::string key, int value); + void incr(std::string key); + void printAll(); + + private: + std::map > counter; + std::list funcs { + "cudaDeviceSynchronize", + "cudaMemcpy2DAsync", + "cudaMemcpy3DAsync", + "cudaMemcpyAsync", + "cudaMemcpy", + "cudaMemcpy2D", + "cudaMemcpy2DArrayToArray", + "cudaMemcpy2DFromArray", + "cudaMemcpy2DFromArrayAsync", + "cudaMemcpy2DToArray", + "cudaMemcpy2DToArrayAsync" + "cudaMemcpy3D", + "cudaMemcpy3DPeer", + "cudaMemcpy3DPeerAsync", + "cudaMemcpyFromSymbol" + "cudaMemcpyFromSymbolAsync", + "cudaMemcpyPeer", + "cudaMemcpyPeerAsync", + "cudaMemcpyToSymbol", + "cudaMemcpyToSymbolAsync" }; +}; + +#endif diff --git a/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp b/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp index a0a77ab4cf5b..f0476871dce3 100644 --- a/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp +++ b/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp @@ -48,10 +48,8 @@ #include //strategy: kokkos::deepcopy a view, count the intercepts. For right now, just report them when mpi_finalize happens. -void OnHost2Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); +void OnHost2Arg(Kokkos::View &a, + Kokkos::View &b) { /* using range_policy = Kokkos::RangePolicy; Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { @@ -61,23 +59,19 @@ void OnHost2Arg() { Kokkos::deep_copy(b, a); } -void OnDevice2Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); - using range_policy = Kokkos::RangePolicy; - +void OnDevice2Arg(Kokkos::View &a, + Kokkos::View &b) { + using range_policy = Kokkos::RangePolicy; + /* Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { a[i] = 2; }); - + */ Kokkos::deep_copy(b, a); } -void HostToDevice2Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); +void HostToDevice2Arg(Kokkos::View &a, + Kokkos::View &b) { /* Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { a[i] = 2; @@ -86,10 +80,8 @@ void HostToDevice2Arg() { Kokkos::deep_copy(b, a); } -void DeviceToHost2Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); +void DeviceToHost2Arg(Kokkos::View &a, + Kokkos::View &b) { /* Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { a[i] = 2; @@ -98,10 +90,8 @@ void DeviceToHost2Arg() { Kokkos::deep_copy(b, a); } -void OnHost3Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); +void OnHost3Arg(Kokkos::View &a, + Kokkos::View &b) { Kokkos::DefaultExecutionSpace mySpace; /* using range_policy = Kokkos::RangePolicy; @@ -113,24 +103,21 @@ void OnHost3Arg() { Kokkos::deep_copy(mySpace, b, a); } -void OnDevice3Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); +void OnDevice3Arg(Kokkos::View &a, + Kokkos::View &b) { Kokkos::DefaultExecutionSpace mySpace; using range_policy = Kokkos::RangePolicy; + /* Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { a[i] = 2; }); - + */ Kokkos::deep_copy(mySpace, b, a); } -void HostToDevice3Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); +void HostToDevice3Arg(Kokkos::View &a, + Kokkos::View &b) { Kokkos::DefaultExecutionSpace mySpace; /* Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { @@ -140,10 +127,8 @@ void HostToDevice3Arg() { Kokkos::deep_copy(mySpace, b, a); } -void DeviceToHost3Arg() { - int N=100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); +void DeviceToHost3Arg(Kokkos::View &a, + Kokkos::View &b) { Kokkos::DefaultExecutionSpace mySpace; /* Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { @@ -157,20 +142,23 @@ int main(int argc, char *argv[]) { //initialize MPI_Init(&argc, &argv); Kokkos::initialize(argc, argv); - - fprintf (stderr, "Starting copies\n"); - //OnHost2Arg(); - //OnDevice2Arg(); - //HostToDevice2Arg(); - //DeviceToHost2Arg(); - //OnHost3Arg(); - //OnDevice3Arg(); - //HostToDevice3Arg(); - DeviceToHost3Arg(); - fprintf (stderr, "Finished copies\n"); - + { + const int N = 100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + Kokkos::View c ("c", N); + Kokkos::View d ("d", N); + + OnHost2Arg(a, b); + OnDevice2Arg(c, d); + HostToDevice2Arg(a, c); + DeviceToHost2Arg(c, a); + OnHost3Arg(a, b); + OnDevice3Arg(c, d); + HostToDevice3Arg(a, c); + DeviceToHost3Arg(c, a); + } fprintf(stderr, "summary statistics\n"); - //finalize Kokkos::finalize(); MPI_Finalize(); diff --git a/packages/tpetra/core/test/KokkosIntegration/intercept.cpp b/packages/tpetra/core/test/KokkosIntegration/intercept.cpp new file mode 100644 index 000000000000..1135d53659b7 --- /dev/null +++ b/packages/tpetra/core/test/KokkosIntegration/intercept.cpp @@ -0,0 +1,262 @@ +/* + * a cuda intercept for kokkos deep copies, now with counts + */ + +#include +#include +#include +#include "ApiTest.h" +#include +#include +#include +#include +#include +#include +#include + +/* +cudaDeviceSynchronize +cudaMemcpy2DAsync +cudaMemcpy3DAsync +cudaMemcpyAsync +cudaMemcpy +cudaMemcpy2D +cudaMemcpy2DArrayToArray +cudaMemcpy2DFromArray +cudaMemcpy2DFromArrayAsync +cudaMemcpy2DToArray +cudaMemcpy2DToArrayAsync +cudaMemcpy3D +cudaMemcpy3DPeer +cudaMemcpy3DPeerAsync +cudaMemcpyFromSymbol +cudaMemcpyFromSymbolAsync +cudaMemcpyPeer +cudaMemcpyPeerAsync +cudaMemcpyToSymbol +cudaMemcpyToSymbolAsync + */ + +class KokkosPDeviceInfo; + +namespace KokkosTest { + ApiTest counter; +} + +int MPI_Init(int *argc, char ***argv) { + int (*o_mpi_init)(int *, char ***); + o_mpi_init = (int (*)(int *, char ***))dlsym(RTLD_NEXT, "MPI_Init"); + + return o_mpi_init(argc, argv); +} + +int MPI_Finalize(void) { + int (*o_mpi_finalize)(void); + o_mpi_finalize = (int (*)(void))dlsym(RTLD_NEXT, "MPI_Finalize"); + + return o_mpi_finalize(); +} + +namespace Kokkos { +void initialize(int& narg, char* arg[]) { + void (*o_init)(int&, char **); + o_init = (void (*)(int&, char **))dlsym(RTLD_NEXT, "_ZN6Kokkos10initializeERiPPc"); + + fprintf(stderr, "Kokkos::initialize()\n"); + o_init(narg, arg); + KokkosTest::counter.map_zero(); +} + +void finalize() { + void (*o_finalize)(void); + o_finalize = (void (*)(void))dlsym(RTLD_NEXT, "_ZN6Kokkos8finalizeEv"); + + KokkosTest::counter.printAll(); + fprintf(stderr, "Kokkos::finalize()\n"); + o_finalize(); +} + +extern "C" void kokkosp_init_library(int loadseq, uint64_t version, uint32_t ndevinfos, KokkosPDeviceInfo* devinfos) { + void (*o_init)(int, uint64_t, uint32_t, KokkosPDeviceInfo*); + o_init = (void (*)(int, uint64_t, uint32_t, KokkosPDeviceInfo*))dlsym(RTLD_NEXT, "kokkosp_init_library"); + + fprintf(stderr, "kokkosp_init_library\n"); + o_init(loadseq, version, ndevinfos, devinfos); +} + +extern "C" void kokkosp_finalize_library() { + void (*o_finalize)(void); + o_finalize = (void (*)(void))dlsym(RTLD_NEXT, "kokkosp_finalize_library"); + fprintf(stderr, "kokkosp_finalize_library\n"); + o_finalize(); +} + +}; + +__host__ __device__ cudaError_t cudaDeviceSynchronize() { + cudaError_t (*o_cudaDeviceSynchronize)(); + o_cudaDeviceSynchronize = (cudaError_t (*)())dlsym(RTLD_NEXT, "cudaDeviceSynchronize"); +#ifndef __CUDA_ARCH__ + KokkosTest::counter.incr("cudaDeviceSynchronize"); +#endif + return o_cudaDeviceSynchronize(); +} + +//Copies data between host and device. Don't care about __device__ calls, so count only if from host. +__host__ __device__ cudaError_t cudaMemcpy2DAsync ( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy2DAsync) (void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); + o_cudaMemcpy2DAsync = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DAsync"); +#ifndef __CUDA_ARCH__ + KokkosTest::counter.incr("cudaMemcpy2DAsync"); +#endif + return o_cudaMemcpy2DAsync(dst, dpitch, src, spitch, width, height, kind, stream); +} + +//Copies data between 3D objects. +__host__ __device__ cudaError_t cudaMemcpy3DAsync ( const cudaMemcpy3DParms* p, cudaStream_t stream ) { + cudaError_t (*o_cudaMemcpy3DAsync) ( const cudaMemcpy3DParms* , cudaStream_t ); + o_cudaMemcpy3DAsync = (cudaError_t (*)(const cudaMemcpy3DParms* , cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DAsync"); +#ifndef __CUDA_ARCH__ + KokkosTest::counter.incr("cudaMemcpy3DAsync"); +#endif + return o_cudaMemcpy3DAsync(p, stream); +} + +//Copies data between host and device. +__host__ __device__ cudaError_t cudaMemcpyAsync ( void* dst, const void* src, size_t count, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpyAsync) ( void*, const void*, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpyAsync = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpyAsync"); +#ifndef __CUDA_ARCH__ + KokkosTest::counter.incr("cudaMemcpyAsync"); +#endif + return o_cudaMemcpyAsync(dst, src, count, kind, stream); +} + +//Copies data to the given symbol on the device. +__host__ cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpy)(void*, const void*, size_t, cudaMemcpyKind); + o_cudaMemcpy = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy"); + KokkosTest::counter.incr("cudaMemcpy"); + return o_cudaMemcpy(dst, src, count, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpy2D)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind); + o_cudaMemcpy2D = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2D"); + KokkosTest::counter.incr("cudaMemcpy2D"); + return o_cudaMemcpy2D(dst, dpitch, src, spitch, width, height, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DArrayToArray ( cudaArray_t dst, size_t wOffsetDst, size_t hOffsetDst, cudaArray_const_t src, size_t wOffsetSrc, size_t hOffsetSrc, size_t width, size_t height, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpy2DArrayToArray) (cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); + o_cudaMemcpy2DArrayToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DArrayToArray"); + KokkosTest::counter.incr("cudaMemcpy2DArrayToArray"); + return o_cudaMemcpy2DArrayToArray(dst, wOffsetDst, hOffsetDst, src, wOffsetSrc, hOffsetSrc, width, height, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DFromArray ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind ) { + cudaError_t (*o_cudaMemcpy2DFromArray) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); + o_cudaMemcpy2DFromArray = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArray"); + KokkosTest::counter.incr("cudaMemcpy2DFromArray"); + return o_cudaMemcpy2DFromArray(dst, dpitch, src, wOffset, hOffset, width, height, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DFromArrayAsync ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy2DFromArrayAsync) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); + o_cudaMemcpy2DFromArrayAsync = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArrayAsync"); + KokkosTest::counter.incr("cudaMemcpy2DFromArrayAsync"); + return o_cudaMemcpy2DFromArrayAsync(dst, dpitch, src, wOffset, hOffset, width, height, kind, stream); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DToArray ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind ) { + cudaError_t (*o_cudaMemcpy2DToArray) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind ); + o_cudaMemcpy2DToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DToArray"); + KokkosTest::counter.incr("cudaMemcpy2DToArray"); + return o_cudaMemcpy2DToArray(dst, wOffset, hOffset, src, spitch, width, height, kind); +} + +//Copies data between host and device. +__host__ cudaError_t cudaMemcpy2DToArrayAsync ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy2DToArrayAsync) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpy2DToArrayAsync = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DToArrayAsync"); + KokkosTest::counter.incr("cudaMemcpy2DToArrayAsync"); + return o_cudaMemcpy2DToArrayAsync(dst, wOffset, hOffset, src, spitch, width, height, kind, stream); +} + +//Copies data between 3D objects. +__host__ cudaError_t cudaMemcpy3D ( const cudaMemcpy3DParms* p ) { + cudaError_t (*o_cudaMemcpy3D) ( const cudaMemcpy3DParms* ); + o_cudaMemcpy3D = (cudaError_t (*)(const cudaMemcpy3DParms*))dlsym(RTLD_NEXT, "cudaMemcpy3D"); + KokkosTest::counter.incr("cudaMemcpy3D"); + return o_cudaMemcpy3D(p); +} + + +//Copies memory between devices. +__host__ cudaError_t cudaMemcpy3DPeer ( const cudaMemcpy3DPeerParms* p ) { + cudaError_t (*o_cudaMemcpy3DPeer) ( const cudaMemcpy3DPeerParms* ); + o_cudaMemcpy3DPeer = (cudaError_t (*)(const cudaMemcpy3DPeerParms*))dlsym(RTLD_NEXT, "cudaMemcpy3DPeer"); + KokkosTest::counter.incr("cudaMemcpy3DPeer"); + return o_cudaMemcpy3DPeer(p); +} + +//Copies memory between devices asynchronously. +__host__ cudaError_t cudaMemcpy3DPeerAsync ( const cudaMemcpy3DPeerParms* p, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy3DPeerAsync) ( const cudaMemcpy3DPeerParms*, cudaStream_t ); + o_cudaMemcpy3DPeerAsync = (cudaError_t (*)(const cudaMemcpy3DPeerParms*, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DPeerAsync"); + KokkosTest::counter.incr("cudaMemcpy3DPeerAsync"); + return o_cudaMemcpy3DPeerAsync(p, stream); +} + +//Copies data from the given symbol on the device. +__host__ cudaError_t cudaMemcpyFromSymbol ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind) { + cudaError_t (*o_cudaMemcpyFromSymbol) ( void*, const void*, size_t, size_t, cudaMemcpyKind ); + o_cudaMemcpyFromSymbol = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbol"); + KokkosTest::counter.incr("cudaMemcpyFromSymbol"); + return o_cudaMemcpyFromSymbol(dst, symbol, count, offset, kind); +} + +//Copies data from the given symbol on the device. +__host__ cudaError_t cudaMemcpyFromSymbolAsync ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpyFromSymbolAsync) ( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpyFromSymbolAsync = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbolAsync"); + KokkosTest::counter.incr("cudaMemcpyFromSymbolAsync"); + return o_cudaMemcpyFromSymbolAsync(dst, symbol, count, offset, kind, stream); +} + +//Copies memory between two devices. +__host__ cudaError_t cudaMemcpyPeer ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count ) { + cudaError_t (*o_cudaMemcpyPeer) ( void*, int, const void*, int, size_t ); + o_cudaMemcpyPeer = (cudaError_t (*)( void*, int, const void*, int, size_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeer"); + KokkosTest::counter.incr("cudaMemcpyPeer"); + return o_cudaMemcpyPeer(dst, dstDevice, src, srcDevice, count); +} + +//Copies memory between two devices asynchronously. +__host__ cudaError_t cudaMemcpyPeerAsync ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpyPeerAsync) ( void*, int, const void*, int, size_t, cudaStream_t ); + o_cudaMemcpyPeerAsync = (cudaError_t (*)( void*, int, const void*, int, size_t, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeerAsync"); + KokkosTest::counter.incr("cudaMemcpyPeerAsync"); + return o_cudaMemcpyPeerAsync(dst, dstDevice, src, srcDevice, count, stream); +} + +//Copies data to the given symbol on the device. +__host__ cudaError_t cudaMemcpyToSymbol ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind ) { + cudaError_t (*o_cudaMemcpyToSymbol) ( const void*, const void*, size_t, size_t, cudaMemcpyKind ); + o_cudaMemcpyToSymbol = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbol"); + KokkosTest::counter.incr("cudaMemcpyToSymbol"); + return o_cudaMemcpyToSymbol(symbol, src, count, offset, kind); +} + +//Copies data to the given symbol on the device. +__host__ cudaError_t cudaMemcpyToSymbolAsync ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream ) { + cudaError_t (*o_cudaMemcpyToSymbolAsync) ( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpyToSymbolAsync = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbolAsync"); + KokkosTest::counter.incr("cudaMemcpyToSymbolAsync"); + return o_cudaMemcpyToSymbolAsync(symbol, src, count, offset, kind, stream); +} From a3355e306c55e89bce11a5c9b4e3b2dbeab274ae Mon Sep 17 00:00:00 2001 From: Geoffrey C Danielson Date: Fri, 30 Oct 2020 12:45:36 -0600 Subject: [PATCH 005/147] this doesn't build but it has all the standalone pieces --- .../core/test/KokkosIntegration/ApiTest.cpp | 25 ++++- .../core/test/KokkosIntegration/ApiTest.h | 7 +- .../test/KokkosIntegration/KokkosDeepcopy.cpp | 32 +++++- .../core/test/KokkosIntegration/intercept.cpp | 104 +++++++++++------- 4 files changed, 121 insertions(+), 47 deletions(-) diff --git a/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp b/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp index 705f73a92541..fe3ca076bce6 100644 --- a/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp +++ b/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp @@ -4,6 +4,19 @@ #include #include "ApiTest.h" +ApiTest *instance = NULL; + +ApiTest *ApiTest::getInstance() { + if (instance == NULL) + instance = new ApiTest; + return instance; +} + +void ApiTest::finalizeInstance() { + if (instance != NULL) + delete instance; +} + ApiTest::ApiTest() { } ApiTest::~ApiTest() { } @@ -21,6 +34,15 @@ int ApiTest::setExpectations(std::map &exp) { return 0; } +bool ApiTest::testExpectations() { + for (std::map >::iterator it = counter.begin(); + it != counter.end(); it++) { + if (it->second.first != it->second.second) + return false; + } + return true; +} + void ApiTest::map_zero() { for (std::list::iterator it = ApiTest::funcs.begin(); it != ApiTest::funcs.end(); it++) { std::map >::iterator found = counter.find(*it); @@ -50,7 +72,8 @@ void ApiTest::printAll() { fprintf (stderr, "call times\n"); for (std::map >::iterator it = counter.begin(); it != counter.end(); it++) { - fprintf(stderr, "%-50s %d\t%d\n", it->first.c_str(), it->second.first, it->second.second); + if (it->second.first != 0 || it->second.second != 0) + fprintf(stderr, "%-50s %d\t%d\n", it->first.c_str(), it->second.first, it->second.second); } fprintf (stderr, "**************** cuda call analysis ****************\n"); } diff --git a/packages/tpetra/core/test/KokkosIntegration/ApiTest.h b/packages/tpetra/core/test/KokkosIntegration/ApiTest.h index d6642fc42e5c..497ef9621423 100644 --- a/packages/tpetra/core/test/KokkosIntegration/ApiTest.h +++ b/packages/tpetra/core/test/KokkosIntegration/ApiTest.h @@ -3,15 +3,18 @@ class ApiTest { public: - ApiTest(); - ~ApiTest(); + static ApiTest *getInstance(); + void finalizeInstance(); int setExpectations(std::map &exp); + bool testExpectations(); void map_zero(); void pincr(std::string key, int value); void incr(std::string key); void printAll(); private: + ApiTest(); + ~ApiTest(); std::map > counter; std::list funcs { "cudaDeviceSynchronize", diff --git a/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp b/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp index f0476871dce3..051a23df881d 100644 --- a/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp +++ b/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp @@ -46,6 +46,10 @@ #include #include #include +#include +#include +#include +#include "ApiTest.h" //strategy: kokkos::deepcopy a view, count the intercepts. For right now, just report them when mpi_finalize happens. void OnHost2Arg(Kokkos::View &a, @@ -139,6 +143,7 @@ void DeviceToHost3Arg(Kokkos::View } int main(int argc, char *argv[]) { + ApiTest *counter = ApiTest::getInstance(); //initialize MPI_Init(&argc, &argv); Kokkos::initialize(argc, argv); @@ -148,17 +153,40 @@ int main(int argc, char *argv[]) { Kokkos::View b ("b", N); Kokkos::View c ("c", N); Kokkos::View d ("d", N); - + + counter->map_zero(); OnHost2Arg(a, b); + fprintf(stderr, "OnHost2Arg()\n"); + counter->printAll(); + counter->map_zero(); OnDevice2Arg(c, d); + fprintf(stderr, "OnDevice2Arg()\n"); + counter->printAll(); + counter->map_zero(); HostToDevice2Arg(a, c); + fprintf(stderr, "HostToDevice2Arg()\n"); + counter->printAll(); + counter->map_zero(); DeviceToHost2Arg(c, a); + fprintf(stderr, "DeviceToHost2Arg()\n"); + counter->printAll(); + counter->map_zero(); OnHost3Arg(a, b); + fprintf(stderr, "OnHost3Arg()\n"); + counter->printAll(); + counter->map_zero(); OnDevice3Arg(c, d); + fprintf(stderr, "OnDevice3Arg()\n"); + counter->printAll(); + counter->map_zero(); HostToDevice3Arg(a, c); + fprintf(stderr, "HostToDevice3Arg()\n"); + counter->printAll(); + counter->map_zero(); DeviceToHost3Arg(c, a); + fprintf(stderr, "DeviceToHost3Arg()\n"); + counter->printAll(); } - fprintf(stderr, "summary statistics\n"); Kokkos::finalize(); MPI_Finalize(); diff --git a/packages/tpetra/core/test/KokkosIntegration/intercept.cpp b/packages/tpetra/core/test/KokkosIntegration/intercept.cpp index 1135d53659b7..e8bdd1739259 100644 --- a/packages/tpetra/core/test/KokkosIntegration/intercept.cpp +++ b/packages/tpetra/core/test/KokkosIntegration/intercept.cpp @@ -39,14 +39,11 @@ cudaMemcpyToSymbolAsync class KokkosPDeviceInfo; -namespace KokkosTest { - ApiTest counter; -} - int MPI_Init(int *argc, char ***argv) { int (*o_mpi_init)(int *, char ***); o_mpi_init = (int (*)(int *, char ***))dlsym(RTLD_NEXT, "MPI_Init"); + fprintf(stderr, "MPI_Init()\n"); return o_mpi_init(argc, argv); } @@ -54,6 +51,7 @@ int MPI_Finalize(void) { int (*o_mpi_finalize)(void); o_mpi_finalize = (int (*)(void))dlsym(RTLD_NEXT, "MPI_Finalize"); + fprintf(stderr, "MPI_Finalize()\n"); return o_mpi_finalize(); } @@ -64,40 +62,24 @@ void initialize(int& narg, char* arg[]) { fprintf(stderr, "Kokkos::initialize()\n"); o_init(narg, arg); - KokkosTest::counter.map_zero(); } void finalize() { void (*o_finalize)(void); o_finalize = (void (*)(void))dlsym(RTLD_NEXT, "_ZN6Kokkos8finalizeEv"); - KokkosTest::counter.printAll(); fprintf(stderr, "Kokkos::finalize()\n"); o_finalize(); } - -extern "C" void kokkosp_init_library(int loadseq, uint64_t version, uint32_t ndevinfos, KokkosPDeviceInfo* devinfos) { - void (*o_init)(int, uint64_t, uint32_t, KokkosPDeviceInfo*); - o_init = (void (*)(int, uint64_t, uint32_t, KokkosPDeviceInfo*))dlsym(RTLD_NEXT, "kokkosp_init_library"); - - fprintf(stderr, "kokkosp_init_library\n"); - o_init(loadseq, version, ndevinfos, devinfos); -} - -extern "C" void kokkosp_finalize_library() { - void (*o_finalize)(void); - o_finalize = (void (*)(void))dlsym(RTLD_NEXT, "kokkosp_finalize_library"); - fprintf(stderr, "kokkosp_finalize_library\n"); - o_finalize(); -} - }; __host__ __device__ cudaError_t cudaDeviceSynchronize() { cudaError_t (*o_cudaDeviceSynchronize)(); o_cudaDeviceSynchronize = (cudaError_t (*)())dlsym(RTLD_NEXT, "cudaDeviceSynchronize"); #ifndef __CUDA_ARCH__ - KokkosTest::counter.incr("cudaDeviceSynchronize"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaDeviceSynchronize"); #endif return o_cudaDeviceSynchronize(); } @@ -107,7 +89,9 @@ __host__ __device__ cudaError_t cudaMemcpy2DAsync ( void* dst, size_t dpitch, co cudaError_t (*o_cudaMemcpy2DAsync) (void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); o_cudaMemcpy2DAsync = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DAsync"); #ifndef __CUDA_ARCH__ - KokkosTest::counter.incr("cudaMemcpy2DAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DAsync"); #endif return o_cudaMemcpy2DAsync(dst, dpitch, src, spitch, width, height, kind, stream); } @@ -117,7 +101,9 @@ __host__ __device__ cudaError_t cudaMemcpy3DAsync ( const cudaMemcpy3DParms* p, cudaError_t (*o_cudaMemcpy3DAsync) ( const cudaMemcpy3DParms* , cudaStream_t ); o_cudaMemcpy3DAsync = (cudaError_t (*)(const cudaMemcpy3DParms* , cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DAsync"); #ifndef __CUDA_ARCH__ - KokkosTest::counter.incr("cudaMemcpy3DAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy3DAsync"); #endif return o_cudaMemcpy3DAsync(p, stream); } @@ -127,7 +113,9 @@ __host__ __device__ cudaError_t cudaMemcpyAsync ( void* dst, const void* src, si cudaError_t (*o_cudaMemcpyAsync) ( void*, const void*, size_t, cudaMemcpyKind, cudaStream_t ); o_cudaMemcpyAsync = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpyAsync"); #ifndef __CUDA_ARCH__ - KokkosTest::counter.incr("cudaMemcpyAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyAsync"); #endif return o_cudaMemcpyAsync(dst, src, count, kind, stream); } @@ -136,7 +124,9 @@ __host__ __device__ cudaError_t cudaMemcpyAsync ( void* dst, const void* src, si __host__ cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMemcpyKind kind) { cudaError_t (*o_cudaMemcpy)(void*, const void*, size_t, cudaMemcpyKind); o_cudaMemcpy = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy"); - KokkosTest::counter.incr("cudaMemcpy"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy"); return o_cudaMemcpy(dst, src, count, kind); } @@ -144,7 +134,9 @@ __host__ cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMe __host__ cudaError_t cudaMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind) { cudaError_t (*o_cudaMemcpy2D)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind); o_cudaMemcpy2D = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2D"); - KokkosTest::counter.incr("cudaMemcpy2D"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2D"); return o_cudaMemcpy2D(dst, dpitch, src, spitch, width, height, kind); } @@ -152,7 +144,9 @@ __host__ cudaError_t cudaMemcpy2D(void* dst, size_t dpitch, const void* src, siz __host__ cudaError_t cudaMemcpy2DArrayToArray ( cudaArray_t dst, size_t wOffsetDst, size_t hOffsetDst, cudaArray_const_t src, size_t wOffsetSrc, size_t hOffsetSrc, size_t width, size_t height, cudaMemcpyKind kind) { cudaError_t (*o_cudaMemcpy2DArrayToArray) (cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); o_cudaMemcpy2DArrayToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DArrayToArray"); - KokkosTest::counter.incr("cudaMemcpy2DArrayToArray"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DArrayToArray"); return o_cudaMemcpy2DArrayToArray(dst, wOffsetDst, hOffsetDst, src, wOffsetSrc, hOffsetSrc, width, height, kind); } @@ -160,7 +154,9 @@ __host__ cudaError_t cudaMemcpy2DArrayToArray ( cudaArray_t dst, size_t wOffsetD __host__ cudaError_t cudaMemcpy2DFromArray ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind ) { cudaError_t (*o_cudaMemcpy2DFromArray) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); o_cudaMemcpy2DFromArray = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArray"); - KokkosTest::counter.incr("cudaMemcpy2DFromArray"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DFromArray"); return o_cudaMemcpy2DFromArray(dst, dpitch, src, wOffset, hOffset, width, height, kind); } @@ -168,7 +164,9 @@ __host__ cudaError_t cudaMemcpy2DFromArray ( void* dst, size_t dpitch, cudaArray __host__ cudaError_t cudaMemcpy2DFromArrayAsync ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { cudaError_t (*o_cudaMemcpy2DFromArrayAsync) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); o_cudaMemcpy2DFromArrayAsync = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArrayAsync"); - KokkosTest::counter.incr("cudaMemcpy2DFromArrayAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DFromArrayAsync"); return o_cudaMemcpy2DFromArrayAsync(dst, dpitch, src, wOffset, hOffset, width, height, kind, stream); } @@ -176,7 +174,9 @@ __host__ cudaError_t cudaMemcpy2DFromArrayAsync ( void* dst, size_t dpitch, cuda __host__ cudaError_t cudaMemcpy2DToArray ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind ) { cudaError_t (*o_cudaMemcpy2DToArray) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind ); o_cudaMemcpy2DToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DToArray"); - KokkosTest::counter.incr("cudaMemcpy2DToArray"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DToArray"); return o_cudaMemcpy2DToArray(dst, wOffset, hOffset, src, spitch, width, height, kind); } @@ -184,7 +184,9 @@ __host__ cudaError_t cudaMemcpy2DToArray ( cudaArray_t dst, size_t wOffset, size __host__ cudaError_t cudaMemcpy2DToArrayAsync ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { cudaError_t (*o_cudaMemcpy2DToArrayAsync) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t ); o_cudaMemcpy2DToArrayAsync = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DToArrayAsync"); - KokkosTest::counter.incr("cudaMemcpy2DToArrayAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DToArrayAsync"); return o_cudaMemcpy2DToArrayAsync(dst, wOffset, hOffset, src, spitch, width, height, kind, stream); } @@ -192,7 +194,9 @@ __host__ cudaError_t cudaMemcpy2DToArrayAsync ( cudaArray_t dst, size_t wOffset, __host__ cudaError_t cudaMemcpy3D ( const cudaMemcpy3DParms* p ) { cudaError_t (*o_cudaMemcpy3D) ( const cudaMemcpy3DParms* ); o_cudaMemcpy3D = (cudaError_t (*)(const cudaMemcpy3DParms*))dlsym(RTLD_NEXT, "cudaMemcpy3D"); - KokkosTest::counter.incr("cudaMemcpy3D"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy3D"); return o_cudaMemcpy3D(p); } @@ -201,7 +205,9 @@ __host__ cudaError_t cudaMemcpy3D ( const cudaMemcpy3DParms* p ) { __host__ cudaError_t cudaMemcpy3DPeer ( const cudaMemcpy3DPeerParms* p ) { cudaError_t (*o_cudaMemcpy3DPeer) ( const cudaMemcpy3DPeerParms* ); o_cudaMemcpy3DPeer = (cudaError_t (*)(const cudaMemcpy3DPeerParms*))dlsym(RTLD_NEXT, "cudaMemcpy3DPeer"); - KokkosTest::counter.incr("cudaMemcpy3DPeer"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy3DPeer"); return o_cudaMemcpy3DPeer(p); } @@ -209,7 +215,9 @@ __host__ cudaError_t cudaMemcpy3DPeer ( const cudaMemcpy3DPeerParms* p ) { __host__ cudaError_t cudaMemcpy3DPeerAsync ( const cudaMemcpy3DPeerParms* p, cudaStream_t stream) { cudaError_t (*o_cudaMemcpy3DPeerAsync) ( const cudaMemcpy3DPeerParms*, cudaStream_t ); o_cudaMemcpy3DPeerAsync = (cudaError_t (*)(const cudaMemcpy3DPeerParms*, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DPeerAsync"); - KokkosTest::counter.incr("cudaMemcpy3DPeerAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy3DPeerAsync"); return o_cudaMemcpy3DPeerAsync(p, stream); } @@ -217,7 +225,9 @@ __host__ cudaError_t cudaMemcpy3DPeerAsync ( const cudaMemcpy3DPeerParms* p, cud __host__ cudaError_t cudaMemcpyFromSymbol ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind) { cudaError_t (*o_cudaMemcpyFromSymbol) ( void*, const void*, size_t, size_t, cudaMemcpyKind ); o_cudaMemcpyFromSymbol = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbol"); - KokkosTest::counter.incr("cudaMemcpyFromSymbol"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyFromSymbol"); return o_cudaMemcpyFromSymbol(dst, symbol, count, offset, kind); } @@ -225,7 +235,9 @@ __host__ cudaError_t cudaMemcpyFromSymbol ( void* dst, const void* symbol, size_ __host__ cudaError_t cudaMemcpyFromSymbolAsync ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream) { cudaError_t (*o_cudaMemcpyFromSymbolAsync) ( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); o_cudaMemcpyFromSymbolAsync = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbolAsync"); - KokkosTest::counter.incr("cudaMemcpyFromSymbolAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyFromSymbolAsync"); return o_cudaMemcpyFromSymbolAsync(dst, symbol, count, offset, kind, stream); } @@ -233,7 +245,9 @@ __host__ cudaError_t cudaMemcpyFromSymbolAsync ( void* dst, const void* symbol, __host__ cudaError_t cudaMemcpyPeer ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count ) { cudaError_t (*o_cudaMemcpyPeer) ( void*, int, const void*, int, size_t ); o_cudaMemcpyPeer = (cudaError_t (*)( void*, int, const void*, int, size_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeer"); - KokkosTest::counter.incr("cudaMemcpyPeer"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyPeer"); return o_cudaMemcpyPeer(dst, dstDevice, src, srcDevice, count); } @@ -241,7 +255,9 @@ __host__ cudaError_t cudaMemcpyPeer ( void* dst, int dstDevice, const void* src __host__ cudaError_t cudaMemcpyPeerAsync ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count, cudaStream_t stream) { cudaError_t (*o_cudaMemcpyPeerAsync) ( void*, int, const void*, int, size_t, cudaStream_t ); o_cudaMemcpyPeerAsync = (cudaError_t (*)( void*, int, const void*, int, size_t, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeerAsync"); - KokkosTest::counter.incr("cudaMemcpyPeerAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyPeerAsync"); return o_cudaMemcpyPeerAsync(dst, dstDevice, src, srcDevice, count, stream); } @@ -249,7 +265,9 @@ __host__ cudaError_t cudaMemcpyPeerAsync ( void* dst, int dstDevice, const void __host__ cudaError_t cudaMemcpyToSymbol ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind ) { cudaError_t (*o_cudaMemcpyToSymbol) ( const void*, const void*, size_t, size_t, cudaMemcpyKind ); o_cudaMemcpyToSymbol = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbol"); - KokkosTest::counter.incr("cudaMemcpyToSymbol"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyToSymbol"); return o_cudaMemcpyToSymbol(symbol, src, count, offset, kind); } @@ -257,6 +275,8 @@ __host__ cudaError_t cudaMemcpyToSymbol ( const void* symbol, const void* src, s __host__ cudaError_t cudaMemcpyToSymbolAsync ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream ) { cudaError_t (*o_cudaMemcpyToSymbolAsync) ( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); o_cudaMemcpyToSymbolAsync = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbolAsync"); - KokkosTest::counter.incr("cudaMemcpyToSymbolAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyToSymbolAsync"); return o_cudaMemcpyToSymbolAsync(symbol, src, count, offset, kind, stream); } From a344b4021837eef09f64e05fa58c1def492c1ba9 Mon Sep 17 00:00:00 2001 From: Geoffrey C Danielson Date: Fri, 6 Nov 2020 10:35:28 -0700 Subject: [PATCH 006/147] closer --- .../test/KokkosIntegration/CMakeLists.txt | 6 + .../core/test/KokkosIntegration/Intercept.cpp | 264 ++++++++-------- .../core/test/KokkosIntegration/intercept.cpp | 282 ------------------ 3 files changed, 123 insertions(+), 429 deletions(-) delete mode 100644 packages/tpetra/core/test/KokkosIntegration/intercept.cpp diff --git a/packages/tpetra/core/test/KokkosIntegration/CMakeLists.txt b/packages/tpetra/core/test/KokkosIntegration/CMakeLists.txt index 89488f3e9d31..e1bb2e1a934a 100644 --- a/packages/tpetra/core/test/KokkosIntegration/CMakeLists.txt +++ b/packages/tpetra/core/test/KokkosIntegration/CMakeLists.txt @@ -10,6 +10,12 @@ IF (Tpetra_ENABLE_CUDA) SOURCES KokkosDeepcopy COMM serial ) + TRIBITS_ADD_LIBRARY( + ApiTest + SOURCES ApiTest + SHARED + TESTONLY + ) TRIBITS_ADD_LIBRARY( Intercept SOURCES Intercept diff --git a/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp b/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp index 0fbe47546acb..e8bdd1739259 100644 --- a/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp +++ b/packages/tpetra/core/test/KokkosIntegration/Intercept.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include "ApiTest.h" #include #include #include @@ -12,88 +14,44 @@ #include #include -namespace ApiTest { - enum devCalls { - cudaDeviceSynchronize, - cudaMemcpy2DAsync, - cudaMemcpy3DAsync, - cudaMemcpyAsync - }; - - std::map totalCounter; - const int numCounters = 4; - - __device__ int *cudaCounters; - int *hostCounters; -} - -int pincr(std::map &store, std::string key, int val) { - std::map::iterator it = store.find(key); - if (it == store.end()) { - store.insert(std::make_pair(key, 1)); - } else { - it->second += val; - } - return 0; -} - -int incr(std::map &store, std::string key) { - return pincr(store, key, 1); -} +/* +cudaDeviceSynchronize +cudaMemcpy2DAsync +cudaMemcpy3DAsync +cudaMemcpyAsync +cudaMemcpy +cudaMemcpy2D +cudaMemcpy2DArrayToArray +cudaMemcpy2DFromArray +cudaMemcpy2DFromArrayAsync +cudaMemcpy2DToArray +cudaMemcpy2DToArrayAsync +cudaMemcpy3D +cudaMemcpy3DPeer +cudaMemcpy3DPeerAsync +cudaMemcpyFromSymbol +cudaMemcpyFromSymbolAsync +cudaMemcpyPeer +cudaMemcpyPeerAsync +cudaMemcpyToSymbol +cudaMemcpyToSymbolAsync + */ -void printAll(std::map &store) { - std::map::iterator it = store.begin(); - fprintf (stderr, "**************** cuda call analysis ****************\n"); - fprintf (stderr, "call\t\ttimes\n"); - while (it != store.end()) { - fprintf(stderr, "%s:\t%d\n", it->first.c_str(), it->second); - it++; - } - fprintf (stderr, "**************** cuda call analysis ****************\n"); -} +class KokkosPDeviceInfo; int MPI_Init(int *argc, char ***argv) { int (*o_mpi_init)(int *, char ***); o_mpi_init = (int (*)(int *, char ***))dlsym(RTLD_NEXT, "MPI_Init"); - ApiTest::hostCounters = (int *)malloc (sizeof(int)*4); - for (size_t i = 0; i < 4; i++) { - ApiTest::hostCounters[i] = 0; - } - + fprintf(stderr, "MPI_Init()\n"); return o_mpi_init(argc, argv); } int MPI_Finalize(void) { - fprintf(stderr, "MPI_Finalize()\n"); int (*o_mpi_finalize)(void); - std::map::iterator f; o_mpi_finalize = (int (*)(void))dlsym(RTLD_NEXT, "MPI_Finalize"); - //copies out the device calls - pincr(ApiTest::totalCounter, "cudaDeviceSynchronize", - ApiTest::hostCounters[ApiTest::devCalls::cudaDeviceSynchronize]); - pincr(ApiTest::totalCounter, "cudaMemcpy2DAsync", - ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpy2DAsync]); - pincr(ApiTest::totalCounter, "cudaMemcpy3DAsync", - ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpy3DAsync]); - pincr(ApiTest::totalCounter, "cudaMemcpyAsync", - ApiTest::hostCounters[ApiTest::devCalls::cudaMemcpyAsync]); - - //baseline: these numbers are magic, happen with kokkos initialization - //to update, run KokkosDeepcopy with no deep copies performed and comment - //this section out. - pincr(ApiTest::totalCounter, "cudaDeviceSynchronize", -5); - pincr(ApiTest::totalCounter, "cudaMemcpy", -11); - pincr(ApiTest::totalCounter, "cudaMemcpyToSymbol", -1); - pincr(ApiTest::totalCounter, "cudaMemcpy2DAsync", -1); - pincr(ApiTest::totalCounter, "cudaMemcpy3DAsync", -1); - pincr(ApiTest::totalCounter, "cudaMemcpyAsync", -1); - - free(ApiTest::hostCounters); - - printAll(ApiTest::totalCounter); - + fprintf(stderr, "MPI_Finalize()\n"); return o_mpi_finalize(); } @@ -102,56 +60,73 @@ void initialize(int& narg, char* arg[]) { void (*o_init)(int&, char **); o_init = (void (*)(int&, char **))dlsym(RTLD_NEXT, "_ZN6Kokkos10initializeERiPPc"); + fprintf(stderr, "Kokkos::initialize()\n"); o_init(narg, arg); - - ApiTest::cudaCounters = (int *)Kokkos::kokkos_malloc("cuda calls", sizeof(int)*4); } void finalize() { - fprintf(stderr, "Kokkos::finalize()\n"); void (*o_finalize)(void); o_finalize = (void (*)(void))dlsym(RTLD_NEXT, "_ZN6Kokkos8finalizeEv"); - //copy ApiTest::cudaCounters into ApiTest::hostCounters - { - // This scoping is important since it ensures the Views deallocate *before* the real Kokkos::finalize() is called. - Kokkos::View h_cudaCounters("host counter temp",ApiTest::numCounters); - Kokkos::View d_cudaCounters(ApiTest::cudaCounters,ApiTest::numCounters); - Kokkos::deep_copy(h_cudaCounters,d_cudaCounters); - - for(int i=0; i(ApiTest::cudaCounters); - } + fprintf(stderr, "Kokkos::finalize()\n"); o_finalize(); } - }; __host__ __device__ cudaError_t cudaDeviceSynchronize() { cudaError_t (*o_cudaDeviceSynchronize)(); o_cudaDeviceSynchronize = (cudaError_t (*)())dlsym(RTLD_NEXT, "cudaDeviceSynchronize"); -#ifdef __CUDA_ARCH__ - Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaDeviceSynchronize]); -#else - incr(ApiTest::totalCounter, "cudaDeviceSynchronize"); +#ifndef __CUDA_ARCH__ + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaDeviceSynchronize"); #endif return o_cudaDeviceSynchronize(); } +//Copies data between host and device. Don't care about __device__ calls, so count only if from host. +__host__ __device__ cudaError_t cudaMemcpy2DAsync ( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpy2DAsync) (void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); + o_cudaMemcpy2DAsync = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DAsync"); +#ifndef __CUDA_ARCH__ + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DAsync"); +#endif + return o_cudaMemcpy2DAsync(dst, dpitch, src, spitch, width, height, kind, stream); +} + +//Copies data between 3D objects. +__host__ __device__ cudaError_t cudaMemcpy3DAsync ( const cudaMemcpy3DParms* p, cudaStream_t stream ) { + cudaError_t (*o_cudaMemcpy3DAsync) ( const cudaMemcpy3DParms* , cudaStream_t ); + o_cudaMemcpy3DAsync = (cudaError_t (*)(const cudaMemcpy3DParms* , cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DAsync"); +#ifndef __CUDA_ARCH__ + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy3DAsync"); +#endif + return o_cudaMemcpy3DAsync(p, stream); +} + +//Copies data between host and device. +__host__ __device__ cudaError_t cudaMemcpyAsync ( void* dst, const void* src, size_t count, cudaMemcpyKind kind, cudaStream_t stream) { + cudaError_t (*o_cudaMemcpyAsync) ( void*, const void*, size_t, cudaMemcpyKind, cudaStream_t ); + o_cudaMemcpyAsync = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpyAsync"); +#ifndef __CUDA_ARCH__ + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyAsync"); +#endif + return o_cudaMemcpyAsync(dst, src, count, kind, stream); +} + //Copies data to the given symbol on the device. __host__ cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMemcpyKind kind) { cudaError_t (*o_cudaMemcpy)(void*, const void*, size_t, cudaMemcpyKind); o_cudaMemcpy = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy"); - incr(ApiTest::totalCounter, "cudaMemcpy"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy"); return o_cudaMemcpy(dst, src, count, kind); } @@ -159,7 +134,9 @@ __host__ cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMe __host__ cudaError_t cudaMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind) { cudaError_t (*o_cudaMemcpy2D)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind); o_cudaMemcpy2D = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2D"); - incr(ApiTest::totalCounter, "cudaMemcpy2D"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2D"); return o_cudaMemcpy2D(dst, dpitch, src, spitch, width, height, kind); } @@ -167,27 +144,19 @@ __host__ cudaError_t cudaMemcpy2D(void* dst, size_t dpitch, const void* src, siz __host__ cudaError_t cudaMemcpy2DArrayToArray ( cudaArray_t dst, size_t wOffsetDst, size_t hOffsetDst, cudaArray_const_t src, size_t wOffsetSrc, size_t hOffsetSrc, size_t width, size_t height, cudaMemcpyKind kind) { cudaError_t (*o_cudaMemcpy2DArrayToArray) (cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); o_cudaMemcpy2DArrayToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DArrayToArray"); - incr(ApiTest::totalCounter, "cudaMemcpy2DArrayToArray"); - return o_cudaMemcpy2DArrayToArray(dst, wOffsetDst, hOffsetDst, src, wOffsetSrc, hOffsetSrc, width, height, kind); -} + ApiTest *ctr = ApiTest::getInstance(); -//Copies data between host and device. -__host__ __device__ cudaError_t cudaMemcpy2DAsync ( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpy2DAsync) (void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); - o_cudaMemcpy2DAsync = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DAsync"); -#ifdef __CUDA_ARCH__ - Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpy2DAsync]); -#else - incr(ApiTest::totalCounter, "cudaMemcpy2DAsync"); -#endif - return o_cudaMemcpy2DAsync(dst, dpitch, src, spitch, width, height, kind, stream); + ctr->incr("cudaMemcpy2DArrayToArray"); + return o_cudaMemcpy2DArrayToArray(dst, wOffsetDst, hOffsetDst, src, wOffsetSrc, hOffsetSrc, width, height, kind); } //Copies data between host and device. __host__ cudaError_t cudaMemcpy2DFromArray ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind ) { cudaError_t (*o_cudaMemcpy2DFromArray) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); o_cudaMemcpy2DFromArray = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArray"); - incr(ApiTest::totalCounter, "cudaMemcpy2DFromArray"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DFromArray"); return o_cudaMemcpy2DFromArray(dst, dpitch, src, wOffset, hOffset, width, height, kind); } @@ -195,7 +164,9 @@ __host__ cudaError_t cudaMemcpy2DFromArray ( void* dst, size_t dpitch, cudaArray __host__ cudaError_t cudaMemcpy2DFromArrayAsync ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { cudaError_t (*o_cudaMemcpy2DFromArrayAsync) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); o_cudaMemcpy2DFromArrayAsync = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArrayAsync"); - incr(ApiTest::totalCounter, "cudaMemcpy2DFromArrayAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DFromArrayAsync"); return o_cudaMemcpy2DFromArrayAsync(dst, dpitch, src, wOffset, hOffset, width, height, kind, stream); } @@ -203,7 +174,9 @@ __host__ cudaError_t cudaMemcpy2DFromArrayAsync ( void* dst, size_t dpitch, cuda __host__ cudaError_t cudaMemcpy2DToArray ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind ) { cudaError_t (*o_cudaMemcpy2DToArray) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind ); o_cudaMemcpy2DToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DToArray"); - incr(ApiTest::totalCounter, "cudaMemcpy2DToArray"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DToArray"); return o_cudaMemcpy2DToArray(dst, wOffset, hOffset, src, spitch, width, height, kind); } @@ -211,7 +184,9 @@ __host__ cudaError_t cudaMemcpy2DToArray ( cudaArray_t dst, size_t wOffset, size __host__ cudaError_t cudaMemcpy2DToArrayAsync ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { cudaError_t (*o_cudaMemcpy2DToArrayAsync) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t ); o_cudaMemcpy2DToArrayAsync = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DToArrayAsync"); - incr(ApiTest::totalCounter, "cudaMemcpy2DToArrayAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy2DToArrayAsync"); return o_cudaMemcpy2DToArrayAsync(dst, wOffset, hOffset, src, spitch, width, height, kind, stream); } @@ -219,27 +194,20 @@ __host__ cudaError_t cudaMemcpy2DToArrayAsync ( cudaArray_t dst, size_t wOffset, __host__ cudaError_t cudaMemcpy3D ( const cudaMemcpy3DParms* p ) { cudaError_t (*o_cudaMemcpy3D) ( const cudaMemcpy3DParms* ); o_cudaMemcpy3D = (cudaError_t (*)(const cudaMemcpy3DParms*))dlsym(RTLD_NEXT, "cudaMemcpy3D"); - incr(ApiTest::totalCounter, "cudaMemcpy3D"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy3D"); return o_cudaMemcpy3D(p); } -//Copies data between 3D objects. -__host__ __device__ cudaError_t cudaMemcpy3DAsync ( const cudaMemcpy3DParms* p, cudaStream_t stream ) { - cudaError_t (*o_cudaMemcpy3DAsync) ( const cudaMemcpy3DParms* , cudaStream_t ); - o_cudaMemcpy3DAsync = (cudaError_t (*)(const cudaMemcpy3DParms* , cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DAsync"); -#ifdef __CUDA_ARCH__ - Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpy3DAsync]); -#else - incr(ApiTest::totalCounter, "cudaMemcpy3DAsync"); -#endif - return o_cudaMemcpy3DAsync(p, stream); -} //Copies memory between devices. __host__ cudaError_t cudaMemcpy3DPeer ( const cudaMemcpy3DPeerParms* p ) { cudaError_t (*o_cudaMemcpy3DPeer) ( const cudaMemcpy3DPeerParms* ); o_cudaMemcpy3DPeer = (cudaError_t (*)(const cudaMemcpy3DPeerParms*))dlsym(RTLD_NEXT, "cudaMemcpy3DPeer"); - incr(ApiTest::totalCounter, "cudaMemcpy3DPeer"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpy3DPeer"); return o_cudaMemcpy3DPeer(p); } @@ -247,27 +215,19 @@ __host__ cudaError_t cudaMemcpy3DPeer ( const cudaMemcpy3DPeerParms* p ) { __host__ cudaError_t cudaMemcpy3DPeerAsync ( const cudaMemcpy3DPeerParms* p, cudaStream_t stream) { cudaError_t (*o_cudaMemcpy3DPeerAsync) ( const cudaMemcpy3DPeerParms*, cudaStream_t ); o_cudaMemcpy3DPeerAsync = (cudaError_t (*)(const cudaMemcpy3DPeerParms*, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DPeerAsync"); - incr(ApiTest::totalCounter, "cudaMemcpy3DPeerAsync"); - return o_cudaMemcpy3DPeerAsync(p, stream); -} + ApiTest *ctr = ApiTest::getInstance(); -//Copies data between host and device. -__host__ __device__ cudaError_t cudaMemcpyAsync ( void* dst, const void* src, size_t count, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpyAsync) ( void*, const void*, size_t, cudaMemcpyKind, cudaStream_t ); - o_cudaMemcpyAsync = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpyAsync"); -#ifdef __CUDA_ARCH__ - Kokkos::atomic_increment(&ApiTest::cudaCounters[ApiTest::devCalls::cudaMemcpyAsync]); -#else - incr(ApiTest::totalCounter, "cudaMemcpyAsync"); -#endif - return o_cudaMemcpyAsync(dst, src, count, kind, stream); + ctr->incr("cudaMemcpy3DPeerAsync"); + return o_cudaMemcpy3DPeerAsync(p, stream); } //Copies data from the given symbol on the device. __host__ cudaError_t cudaMemcpyFromSymbol ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind) { cudaError_t (*o_cudaMemcpyFromSymbol) ( void*, const void*, size_t, size_t, cudaMemcpyKind ); o_cudaMemcpyFromSymbol = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbol"); - incr(ApiTest::totalCounter, "cudaMemcpyFromSymbol"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyFromSymbol"); return o_cudaMemcpyFromSymbol(dst, symbol, count, offset, kind); } @@ -275,7 +235,9 @@ __host__ cudaError_t cudaMemcpyFromSymbol ( void* dst, const void* symbol, size_ __host__ cudaError_t cudaMemcpyFromSymbolAsync ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream) { cudaError_t (*o_cudaMemcpyFromSymbolAsync) ( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); o_cudaMemcpyFromSymbolAsync = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbolAsync"); - incr(ApiTest::totalCounter, "cudaMemcpyFromSymbolAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyFromSymbolAsync"); return o_cudaMemcpyFromSymbolAsync(dst, symbol, count, offset, kind, stream); } @@ -283,7 +245,9 @@ __host__ cudaError_t cudaMemcpyFromSymbolAsync ( void* dst, const void* symbol, __host__ cudaError_t cudaMemcpyPeer ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count ) { cudaError_t (*o_cudaMemcpyPeer) ( void*, int, const void*, int, size_t ); o_cudaMemcpyPeer = (cudaError_t (*)( void*, int, const void*, int, size_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeer"); - incr(ApiTest::totalCounter, "cudaMemcpyPeer"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyPeer"); return o_cudaMemcpyPeer(dst, dstDevice, src, srcDevice, count); } @@ -291,7 +255,9 @@ __host__ cudaError_t cudaMemcpyPeer ( void* dst, int dstDevice, const void* src __host__ cudaError_t cudaMemcpyPeerAsync ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count, cudaStream_t stream) { cudaError_t (*o_cudaMemcpyPeerAsync) ( void*, int, const void*, int, size_t, cudaStream_t ); o_cudaMemcpyPeerAsync = (cudaError_t (*)( void*, int, const void*, int, size_t, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeerAsync"); - incr(ApiTest::totalCounter, "cudaMemcpyPeerAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyPeerAsync"); return o_cudaMemcpyPeerAsync(dst, dstDevice, src, srcDevice, count, stream); } @@ -299,7 +265,9 @@ __host__ cudaError_t cudaMemcpyPeerAsync ( void* dst, int dstDevice, const void __host__ cudaError_t cudaMemcpyToSymbol ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind ) { cudaError_t (*o_cudaMemcpyToSymbol) ( const void*, const void*, size_t, size_t, cudaMemcpyKind ); o_cudaMemcpyToSymbol = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbol"); - incr(ApiTest::totalCounter, "cudaMemcpyToSymbol"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyToSymbol"); return o_cudaMemcpyToSymbol(symbol, src, count, offset, kind); } @@ -307,6 +275,8 @@ __host__ cudaError_t cudaMemcpyToSymbol ( const void* symbol, const void* src, s __host__ cudaError_t cudaMemcpyToSymbolAsync ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream ) { cudaError_t (*o_cudaMemcpyToSymbolAsync) ( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); o_cudaMemcpyToSymbolAsync = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbolAsync"); - incr(ApiTest::totalCounter, "cudaMemcpyToSymbolAsync"); + ApiTest *ctr = ApiTest::getInstance(); + + ctr->incr("cudaMemcpyToSymbolAsync"); return o_cudaMemcpyToSymbolAsync(symbol, src, count, offset, kind, stream); } diff --git a/packages/tpetra/core/test/KokkosIntegration/intercept.cpp b/packages/tpetra/core/test/KokkosIntegration/intercept.cpp deleted file mode 100644 index e8bdd1739259..000000000000 --- a/packages/tpetra/core/test/KokkosIntegration/intercept.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/* - * a cuda intercept for kokkos deep copies, now with counts - */ - -#include -#include -#include -#include "ApiTest.h" -#include -#include -#include -#include -#include -#include -#include - -/* -cudaDeviceSynchronize -cudaMemcpy2DAsync -cudaMemcpy3DAsync -cudaMemcpyAsync -cudaMemcpy -cudaMemcpy2D -cudaMemcpy2DArrayToArray -cudaMemcpy2DFromArray -cudaMemcpy2DFromArrayAsync -cudaMemcpy2DToArray -cudaMemcpy2DToArrayAsync -cudaMemcpy3D -cudaMemcpy3DPeer -cudaMemcpy3DPeerAsync -cudaMemcpyFromSymbol -cudaMemcpyFromSymbolAsync -cudaMemcpyPeer -cudaMemcpyPeerAsync -cudaMemcpyToSymbol -cudaMemcpyToSymbolAsync - */ - -class KokkosPDeviceInfo; - -int MPI_Init(int *argc, char ***argv) { - int (*o_mpi_init)(int *, char ***); - o_mpi_init = (int (*)(int *, char ***))dlsym(RTLD_NEXT, "MPI_Init"); - - fprintf(stderr, "MPI_Init()\n"); - return o_mpi_init(argc, argv); -} - -int MPI_Finalize(void) { - int (*o_mpi_finalize)(void); - o_mpi_finalize = (int (*)(void))dlsym(RTLD_NEXT, "MPI_Finalize"); - - fprintf(stderr, "MPI_Finalize()\n"); - return o_mpi_finalize(); -} - -namespace Kokkos { -void initialize(int& narg, char* arg[]) { - void (*o_init)(int&, char **); - o_init = (void (*)(int&, char **))dlsym(RTLD_NEXT, "_ZN6Kokkos10initializeERiPPc"); - - fprintf(stderr, "Kokkos::initialize()\n"); - o_init(narg, arg); -} - -void finalize() { - void (*o_finalize)(void); - o_finalize = (void (*)(void))dlsym(RTLD_NEXT, "_ZN6Kokkos8finalizeEv"); - - fprintf(stderr, "Kokkos::finalize()\n"); - o_finalize(); -} -}; - -__host__ __device__ cudaError_t cudaDeviceSynchronize() { - cudaError_t (*o_cudaDeviceSynchronize)(); - o_cudaDeviceSynchronize = (cudaError_t (*)())dlsym(RTLD_NEXT, "cudaDeviceSynchronize"); -#ifndef __CUDA_ARCH__ - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaDeviceSynchronize"); -#endif - return o_cudaDeviceSynchronize(); -} - -//Copies data between host and device. Don't care about __device__ calls, so count only if from host. -__host__ __device__ cudaError_t cudaMemcpy2DAsync ( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpy2DAsync) (void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); - o_cudaMemcpy2DAsync = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DAsync"); -#ifndef __CUDA_ARCH__ - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy2DAsync"); -#endif - return o_cudaMemcpy2DAsync(dst, dpitch, src, spitch, width, height, kind, stream); -} - -//Copies data between 3D objects. -__host__ __device__ cudaError_t cudaMemcpy3DAsync ( const cudaMemcpy3DParms* p, cudaStream_t stream ) { - cudaError_t (*o_cudaMemcpy3DAsync) ( const cudaMemcpy3DParms* , cudaStream_t ); - o_cudaMemcpy3DAsync = (cudaError_t (*)(const cudaMemcpy3DParms* , cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DAsync"); -#ifndef __CUDA_ARCH__ - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy3DAsync"); -#endif - return o_cudaMemcpy3DAsync(p, stream); -} - -//Copies data between host and device. -__host__ __device__ cudaError_t cudaMemcpyAsync ( void* dst, const void* src, size_t count, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpyAsync) ( void*, const void*, size_t, cudaMemcpyKind, cudaStream_t ); - o_cudaMemcpyAsync = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpyAsync"); -#ifndef __CUDA_ARCH__ - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpyAsync"); -#endif - return o_cudaMemcpyAsync(dst, src, count, kind, stream); -} - -//Copies data to the given symbol on the device. -__host__ cudaError_t cudaMemcpy(void* dst, const void* src, size_t count, cudaMemcpyKind kind) { - cudaError_t (*o_cudaMemcpy)(void*, const void*, size_t, cudaMemcpyKind); - o_cudaMemcpy = (cudaError_t (*)(void*, const void*, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy"); - return o_cudaMemcpy(dst, src, count, kind); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2D(void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind) { - cudaError_t (*o_cudaMemcpy2D)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind); - o_cudaMemcpy2D = (cudaError_t (*)(void*, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2D"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy2D"); - return o_cudaMemcpy2D(dst, dpitch, src, spitch, width, height, kind); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2DArrayToArray ( cudaArray_t dst, size_t wOffsetDst, size_t hOffsetDst, cudaArray_const_t src, size_t wOffsetSrc, size_t hOffsetSrc, size_t width, size_t height, cudaMemcpyKind kind) { - cudaError_t (*o_cudaMemcpy2DArrayToArray) (cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); - o_cudaMemcpy2DArrayToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DArrayToArray"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy2DArrayToArray"); - return o_cudaMemcpy2DArrayToArray(dst, wOffsetDst, hOffsetDst, src, wOffsetSrc, hOffsetSrc, width, height, kind); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2DFromArray ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind ) { - cudaError_t (*o_cudaMemcpy2DFromArray) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind); - o_cudaMemcpy2DFromArray = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArray"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy2DFromArray"); - return o_cudaMemcpy2DFromArray(dst, dpitch, src, wOffset, hOffset, width, height, kind); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2DFromArrayAsync ( void* dst, size_t dpitch, cudaArray_const_t src, size_t wOffset, size_t hOffset, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpy2DFromArrayAsync) ( void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t); - o_cudaMemcpy2DFromArrayAsync = (cudaError_t (*)(void*, size_t, cudaArray_const_t, size_t, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DFromArrayAsync"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy2DFromArrayAsync"); - return o_cudaMemcpy2DFromArrayAsync(dst, dpitch, src, wOffset, hOffset, width, height, kind, stream); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2DToArray ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind ) { - cudaError_t (*o_cudaMemcpy2DToArray) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind ); - o_cudaMemcpy2DToArray = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind))dlsym(RTLD_NEXT, "cudaMemcpy2DToArray"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy2DToArray"); - return o_cudaMemcpy2DToArray(dst, wOffset, hOffset, src, spitch, width, height, kind); -} - -//Copies data between host and device. -__host__ cudaError_t cudaMemcpy2DToArrayAsync ( cudaArray_t dst, size_t wOffset, size_t hOffset, const void* src, size_t spitch, size_t width, size_t height, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpy2DToArrayAsync) ( cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t ); - o_cudaMemcpy2DToArrayAsync = (cudaError_t (*)(cudaArray_t, size_t, size_t, const void*, size_t, size_t, size_t, cudaMemcpyKind, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy2DToArrayAsync"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy2DToArrayAsync"); - return o_cudaMemcpy2DToArrayAsync(dst, wOffset, hOffset, src, spitch, width, height, kind, stream); -} - -//Copies data between 3D objects. -__host__ cudaError_t cudaMemcpy3D ( const cudaMemcpy3DParms* p ) { - cudaError_t (*o_cudaMemcpy3D) ( const cudaMemcpy3DParms* ); - o_cudaMemcpy3D = (cudaError_t (*)(const cudaMemcpy3DParms*))dlsym(RTLD_NEXT, "cudaMemcpy3D"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy3D"); - return o_cudaMemcpy3D(p); -} - - -//Copies memory between devices. -__host__ cudaError_t cudaMemcpy3DPeer ( const cudaMemcpy3DPeerParms* p ) { - cudaError_t (*o_cudaMemcpy3DPeer) ( const cudaMemcpy3DPeerParms* ); - o_cudaMemcpy3DPeer = (cudaError_t (*)(const cudaMemcpy3DPeerParms*))dlsym(RTLD_NEXT, "cudaMemcpy3DPeer"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy3DPeer"); - return o_cudaMemcpy3DPeer(p); -} - -//Copies memory between devices asynchronously. -__host__ cudaError_t cudaMemcpy3DPeerAsync ( const cudaMemcpy3DPeerParms* p, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpy3DPeerAsync) ( const cudaMemcpy3DPeerParms*, cudaStream_t ); - o_cudaMemcpy3DPeerAsync = (cudaError_t (*)(const cudaMemcpy3DPeerParms*, cudaStream_t))dlsym(RTLD_NEXT, "cudaMemcpy3DPeerAsync"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpy3DPeerAsync"); - return o_cudaMemcpy3DPeerAsync(p, stream); -} - -//Copies data from the given symbol on the device. -__host__ cudaError_t cudaMemcpyFromSymbol ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind) { - cudaError_t (*o_cudaMemcpyFromSymbol) ( void*, const void*, size_t, size_t, cudaMemcpyKind ); - o_cudaMemcpyFromSymbol = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbol"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpyFromSymbol"); - return o_cudaMemcpyFromSymbol(dst, symbol, count, offset, kind); -} - -//Copies data from the given symbol on the device. -__host__ cudaError_t cudaMemcpyFromSymbolAsync ( void* dst, const void* symbol, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpyFromSymbolAsync) ( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); - o_cudaMemcpyFromSymbolAsync = (cudaError_t (*)( void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyFromSymbolAsync"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpyFromSymbolAsync"); - return o_cudaMemcpyFromSymbolAsync(dst, symbol, count, offset, kind, stream); -} - -//Copies memory between two devices. -__host__ cudaError_t cudaMemcpyPeer ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count ) { - cudaError_t (*o_cudaMemcpyPeer) ( void*, int, const void*, int, size_t ); - o_cudaMemcpyPeer = (cudaError_t (*)( void*, int, const void*, int, size_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeer"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpyPeer"); - return o_cudaMemcpyPeer(dst, dstDevice, src, srcDevice, count); -} - -//Copies memory between two devices asynchronously. -__host__ cudaError_t cudaMemcpyPeerAsync ( void* dst, int dstDevice, const void* src, int srcDevice, size_t count, cudaStream_t stream) { - cudaError_t (*o_cudaMemcpyPeerAsync) ( void*, int, const void*, int, size_t, cudaStream_t ); - o_cudaMemcpyPeerAsync = (cudaError_t (*)( void*, int, const void*, int, size_t, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyPeerAsync"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpyPeerAsync"); - return o_cudaMemcpyPeerAsync(dst, dstDevice, src, srcDevice, count, stream); -} - -//Copies data to the given symbol on the device. -__host__ cudaError_t cudaMemcpyToSymbol ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind ) { - cudaError_t (*o_cudaMemcpyToSymbol) ( const void*, const void*, size_t, size_t, cudaMemcpyKind ); - o_cudaMemcpyToSymbol = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbol"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpyToSymbol"); - return o_cudaMemcpyToSymbol(symbol, src, count, offset, kind); -} - -//Copies data to the given symbol on the device. -__host__ cudaError_t cudaMemcpyToSymbolAsync ( const void* symbol, const void* src, size_t count, size_t offset, cudaMemcpyKind kind, cudaStream_t stream ) { - cudaError_t (*o_cudaMemcpyToSymbolAsync) ( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ); - o_cudaMemcpyToSymbolAsync = (cudaError_t (*)( const void*, const void*, size_t, size_t, cudaMemcpyKind, cudaStream_t ))dlsym(RTLD_NEXT, "cudaMemcpyToSymbolAsync"); - ApiTest *ctr = ApiTest::getInstance(); - - ctr->incr("cudaMemcpyToSymbolAsync"); - return o_cudaMemcpyToSymbolAsync(symbol, src, count, offset, kind, stream); -} From 296a6034c53c9a66949301f413a37a83128738a6 Mon Sep 17 00:00:00 2001 From: Geoffrey C Danielson Date: Tue, 10 Nov 2020 08:47:21 -0700 Subject: [PATCH 007/147] wrap it all up, building ready for WIP --- .../core/test/KokkosIntegration/ApiTest.cpp | 9 + .../core/test/KokkosIntegration/ApiTest.h | 1 + .../test/KokkosIntegration/KokkosDeepcopy.cpp | 303 +++++++++++------- 3 files changed, 192 insertions(+), 121 deletions(-) diff --git a/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp b/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp index fe3ca076bce6..931d6fdc8f8c 100644 --- a/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp +++ b/packages/tpetra/core/test/KokkosIntegration/ApiTest.cpp @@ -21,6 +21,15 @@ ApiTest::ApiTest() { } ApiTest::~ApiTest() { } +int ApiTest::setExpectation(std::string key, int value) { + std::map >::iterator found = counter.find(key); + if (found != counter.end()) { + found->second.second = value; + return 0; + } + return -1; +} + int ApiTest::setExpectations(std::map &exp) { for (std::map::iterator it = exp.begin(); it != exp.end(); it++) { diff --git a/packages/tpetra/core/test/KokkosIntegration/ApiTest.h b/packages/tpetra/core/test/KokkosIntegration/ApiTest.h index 497ef9621423..41d435502a05 100644 --- a/packages/tpetra/core/test/KokkosIntegration/ApiTest.h +++ b/packages/tpetra/core/test/KokkosIntegration/ApiTest.h @@ -5,6 +5,7 @@ class ApiTest { public: static ApiTest *getInstance(); void finalizeInstance(); + int setExpectation(std::string, int); int setExpectations(std::map &exp); bool testExpectations(); void map_zero(); diff --git a/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp b/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp index 051a23df881d..33c39737a106 100644 --- a/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp +++ b/packages/tpetra/core/test/KokkosIntegration/KokkosDeepcopy.cpp @@ -51,145 +51,206 @@ #include #include "ApiTest.h" -//strategy: kokkos::deepcopy a view, count the intercepts. For right now, just report them when mpi_finalize happens. -void OnHost2Arg(Kokkos::View &a, - Kokkos::View &b) { - /* using range_policy = Kokkos::RangePolicy; +class DeepCopyTester { +public: + DeepCopyTester() {} + void run() { + log("Tpetra Kokkos DeepCopy Regression test start"); - Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - */ - Kokkos::deep_copy(b, a); -} + std::string cudaSync("cudaDeviceSynchronize"); + std::string cudaMemcpy("cudaMemcpy"); + std::string cudaMemcpyAsync("cudaMemcpyAsync"); + ApiTest *counter = ApiTest::getInstance(); + //initialize + MPI_Init(&argc, &argv); + Kokkos::initialize(argc, argv); + { + isConsistent = true; + const int N = 100; + Kokkos::View a ("a", N); + Kokkos::View b ("b", N); + Kokkos::View c ("c", N); + Kokkos::View d ("d", N); -void OnDevice2Arg(Kokkos::View &a, - Kokkos::View &b) { - using range_policy = Kokkos::RangePolicy; - /* - Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - */ - Kokkos::deep_copy(b, a); -} + counter->map_zero(); + counter->setExpectation(cudaSync, 2); + OnHost2Arg(a, b); + if (!counter->testExpectations()) { + log("OnHost2Arg()"); + isConsistent = false; + } -void HostToDevice2Arg(Kokkos::View &a, - Kokkos::View &b) { - /* - Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { - a[i] = 2; - }); - */ - Kokkos::deep_copy(b, a); -} + counter->map_zero(); + counter->setExpectation(cudaSync, 2); + counter->setExpectation(cudaMemcpy, 1); + OnDevice2Arg(c, d); + if (!counter->testExpectations()) { + log("OnDevice2Arg()"); + isConsistent = false; + } + + counter->map_zero(); + counter->setExpectation(cudaSync, 2); + counter->setExpectation(cudaMemcpy, 1); + HostToDevice2Arg(a, c); + if (!counter->testExpectations()) { + log("HostToDevice2Arg()"); + isConsistent = false; + } + + counter->map_zero(); + counter->setExpectation(cudaSync, 2); + counter->setExpectation(cudaMemcpy, 1); + DeviceToHost2Arg(c, a); + if (!counter->testExpectations()) { + log("DeviceToHost2Arg()"); + isConsistent = false; + } + + counter->map_zero(); + OnHost3Arg(a, b); + if (!counter->testExpectations()) { + log("OnHost3Arg()"); + isConsistent = false; + } + + counter->map_zero(); + counter->setExpectation(cudaMemcpyAsync, 1); + OnDevice3Arg(c, d); + if (!counter->testExpectations()) { + log("OnDevice3Arg()"); + isConsistent = false; + } + + counter->map_zero(); + counter->setExpectation(cudaMemcpyAsync, 1); + HostToDevice3Arg(a, c); + if (!counter->testExpectations()) { + log("HostToDevice3Arg()"); + isConsistent = false; + } + + counter->map_zero(); + counter->setExpectation(cudaMemcpyAsync, 1); + DeviceToHost3Arg(c, a); + if (!counter->testExpectations()) { + log("DeviceToHost3Arg()"); + isConsistent = false; + } + } + Kokkos::finalize(); + MPI_Finalize(); + + return 0; + } + + bool getConsistency() { + return isConsistent; + } + + void OnHost2Arg(Kokkos::View &a, + Kokkos::View &b) { + /* using range_policy = Kokkos::RangePolicy; + + Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(b, a); + } -void DeviceToHost2Arg(Kokkos::View &a, - Kokkos::View &b) { - /* - Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { + void OnDevice2Arg(Kokkos::View &a, + Kokkos::View &b) { + using range_policy = Kokkos::RangePolicy; + /* + Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { a[i] = 2; - }); - */ - Kokkos::deep_copy(b, a); -} + }); + */ + Kokkos::deep_copy(b, a); + } -void OnHost3Arg(Kokkos::View &a, - Kokkos::View &b) { - Kokkos::DefaultExecutionSpace mySpace; - /* - using range_policy = Kokkos::RangePolicy; + void HostToDevice2Arg(Kokkos::View &a, + Kokkos::View &b) { + /* + Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(b, a); + } - Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + void DeviceToHost2Arg(Kokkos::View &a, + Kokkos::View &b) { + /* + Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { a[i] = 2; - }); - */ - Kokkos::deep_copy(mySpace, b, a); -} + }); + */ + Kokkos::deep_copy(b, a); + } -void OnDevice3Arg(Kokkos::View &a, - Kokkos::View &b) { - Kokkos::DefaultExecutionSpace mySpace; - using range_policy = Kokkos::RangePolicy; + void OnHost3Arg(Kokkos::View &a, + Kokkos::View &b) { + Kokkos::DefaultExecutionSpace mySpace; + /* + using range_policy = Kokkos::RangePolicy; + + Kokkos::parallel_for("onHost initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + a[i] = 2; + }); + */ + Kokkos::deep_copy(mySpace, b, a); + } - /* - Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { + void OnDevice3Arg(Kokkos::View &a, + Kokkos::View &b) { + Kokkos::DefaultExecutionSpace mySpace; + using range_policy = Kokkos::RangePolicy; + + /* + Kokkos::parallel_for("onDevice initialize", range_policy(0,N), KOKKOS_LAMBDA(const int &i) { a[i] = 2; - }); - */ - Kokkos::deep_copy(mySpace, b, a); -} + }); + */ + Kokkos::deep_copy(mySpace, b, a); + } -void HostToDevice3Arg(Kokkos::View &a, - Kokkos::View &b) { - Kokkos::DefaultExecutionSpace mySpace; - /* - Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { + void HostToDevice3Arg(Kokkos::View &a, + Kokkos::View &b) { + Kokkos::DefaultExecutionSpace mySpace; + /* + Kokkos::parallel_for("host to device initialize", N, KOKKOS_LAMBDA(const int &i) { a[i] = 2; - }); - */ - Kokkos::deep_copy(mySpace, b, a); -} + }); + */ + Kokkos::deep_copy(mySpace, b, a); + } -void DeviceToHost3Arg(Kokkos::View &a, - Kokkos::View &b) { - Kokkos::DefaultExecutionSpace mySpace; - /* - Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { + void DeviceToHost3Arg(Kokkos::View &a, + Kokkos::View &b) { + Kokkos::DefaultExecutionSpace mySpace; + /* + Kokkos::parallel_for("device to host initialize", N, KOKKOS_LAMBDA(const int &i) { a[i] = 2; - }); - */ - Kokkos::deep_copy(mySpace, b, a); -} + }); + */ + Kokkos::deep_copy(mySpace, b, a); + } -int main(int argc, char *argv[]) { - ApiTest *counter = ApiTest::getInstance(); - //initialize - MPI_Init(&argc, &argv); - Kokkos::initialize(argc, argv); - { - const int N = 100; - Kokkos::View a ("a", N); - Kokkos::View b ("b", N); - Kokkos::View c ("c", N); - Kokkos::View d ("d", N); - - counter->map_zero(); - OnHost2Arg(a, b); - fprintf(stderr, "OnHost2Arg()\n"); - counter->printAll(); - counter->map_zero(); - OnDevice2Arg(c, d); - fprintf(stderr, "OnDevice2Arg()\n"); - counter->printAll(); - counter->map_zero(); - HostToDevice2Arg(a, c); - fprintf(stderr, "HostToDevice2Arg()\n"); - counter->printAll(); - counter->map_zero(); - DeviceToHost2Arg(c, a); - fprintf(stderr, "DeviceToHost2Arg()\n"); - counter->printAll(); - counter->map_zero(); - OnHost3Arg(a, b); - fprintf(stderr, "OnHost3Arg()\n"); - counter->printAll(); - counter->map_zero(); - OnDevice3Arg(c, d); - fprintf(stderr, "OnDevice3Arg()\n"); - counter->printAll(); - counter->map_zero(); - HostToDevice3Arg(a, c); - fprintf(stderr, "HostToDevice3Arg()\n"); - counter->printAll(); - counter->map_zero(); - DeviceToHost3Arg(c, a); - fprintf(stderr, "DeviceToHost3Arg()\n"); - counter->printAll(); +private: + bool isConsistent; + void log(const std::string& msg) { + std::cout << msg << std::endl; } - Kokkos::finalize(); - MPI_Finalize(); +}; + +int main(int argc, char *argv[]) { + DeepCopyTester tester; + tester.run(); + if (!tester.getConsistency()) + return -1; return 0; } From a587f5f326e5ca404931dceee0f469e1432385ea Mon Sep 17 00:00:00 2001 From: Luc Berger-Vergiat Date: Tue, 1 Mar 2022 07:49:29 -0700 Subject: [PATCH 008/147] MueLu: region MG new adapter using composite data structures Adding a new interface to solver the region problem, this interface accepts A, X and B in composite format and still needs the hierarchy in region format. With such an interface hooking the preconditioner with Belos should be a lot easier although we need to be careful how the composite vectors are transfered to region format. Next step will be adding a CG solver using composite vectors and compostie A but preconditioned with region MG. --- .../regionMG/src/SetupRegionMatrix_def.hpp | 5 + .../regionMG/src/SolveRegionHierarchy_def.hpp | 383 ++++++++++++++++-- .../structured/Driver_Structured_Regions.cpp | 22 +- 3 files changed, 362 insertions(+), 48 deletions(-) diff --git a/packages/muelu/research/regionMG/src/SetupRegionMatrix_def.hpp b/packages/muelu/research/regionMG/src/SetupRegionMatrix_def.hpp index 286e0b760527..d1ed9d258424 100644 --- a/packages/muelu/research/regionMG/src/SetupRegionMatrix_def.hpp +++ b/packages/muelu/research/regionMG/src/SetupRegionMatrix_def.hpp @@ -524,6 +524,11 @@ computeResidual(RCP >& const ArrayRCP regionInterfaceLIDs = params.get>("Fast MatVec: interface LIDs"); const RCP regionInterfaceImporter = params.get>("Fast MatVec: interface importer"); + // Todo: would it be faster to store this in regRes: + // regRes = A*x + // regRes->update(one, regB, -one); + // and avoid allocating and de-allocating memory for y vector? + // Step 1: Compute region version of y = Ax RCP aTimesX = VectorFactory::Build(regionMats->getRangeMap(), true); regionMats->apply(*regX, *aTimesX, Teuchos::NO_TRANS, TST::one(), TST::zero(), true, regionInterfaceImporter, regionInterfaceLIDs); diff --git a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp index ac5b9a72b663..c12c2683e12d 100644 --- a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp +++ b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp @@ -309,6 +309,66 @@ void vCycle(const int l, ///< ID of current level return; } // vCycle +//! Adapter that uses composite vectors and a region hierarchy +// and performs a region vCycle on them. +template +void vCycleAdapter(const int numLevels, ///< Total number of levels + const std::string cycleType, + RCP > & regHierarchy, + RCP >& X, ///< solution + RCP > B, ///< right hand side + Array > smootherParams, ///< region smoother parameter list + bool& zeroInitGuess, + RCP coarseSolverData = Teuchos::null, + RCP hierarchyData = Teuchos::null) { + + using LO = LocalOrdinal; + using GO = GlobalOrdinal; + using NO = Node; + using SC = Scalar; + + using Level = MueLu::Level; + using Map = Xpetra::Map; + using Import = Xpetra::Import; + using Matrix = Xpetra::Matrix; + using Vector = Xpetra::Vector; + using VectorFactory = Xpetra::VectorFactory; + + // Extract some info from the hierarchy + // to convert vectors from composite to regional and back + RCP level0 = regHierarchy->GetLevel(0); + RCP regMat = level0->Get >("A"); + RCP revisedRowMap = regMat->getRowMap(); + RCP rowImport = level0->Get >("rowImport"); + + // Compute region vectors for B and X + RCP quasiRegB; + RCP regB; + compositeToRegional(B, quasiRegB, regB, + revisedRowMap, rowImport); + + RCP quasiRegX; + RCP regX; + compositeToRegional(X, quasiRegX, regX, + revisedRowMap, rowImport); + + Teuchos::RCP regCorrect; + regCorrect = VectorFactory::Build(revisedRowMap, true); + + // std::cout << "regB->norm2() " << regB->norm2() << std::endl; + + vCycle(0, numLevels, cycleType, regHierarchy, + regX, regB, + smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); + + // std::cout << "regX->norm2() " << regX->norm2() << std::endl; + + // Bring solution back to composite format + RCP regInterfaceScalings = level0->Get >("regInterfaceScalings"); + scaleInterfaceDOFs(regX, regInterfaceScalings, true); + regionalToComposite(regX, X, rowImport); +} // vCycleAdapter + template void solveRegionProblem(const double tol, const bool scaleResidualHist, const int maxIts, const std::string cycleType, const std::string convergenceLog, @@ -334,8 +394,8 @@ void solveRegionProblem(const double tol, const bool scaleResidualHist, const in using STS = Teuchos::ScalarTraits; using magnitude_type = typename STS::magnitudeType; - // const Scalar zero = STS::zero(); - const Scalar one = STS::one(); + const Scalar SC_zero = STS::zero(); + const Scalar SC_one = STS::one(); // we start by extracting some basic data from the hierarchy const int numLevels = regHierarchy->GetNumLevels(); @@ -351,6 +411,23 @@ void solveRegionProblem(const double tol, const bool scaleResidualHist, const in Teuchos::FancyOStream& out = *fancy; out.setOutputToRootOnly(0); + // Prepare output of residual norm to file + RCP log; + if (myRank == 0) + { + log = rcp(new std::ofstream(convergenceLog.c_str())); + (*log) << "# num procs = " << dofMap->getComm()->getSize() << "\n" + << "# iteration | res-norm (scaled=" << scaleResidualHist << ")\n" + << "#\n"; + *log << std::setprecision(16) << std::scientific; + } + + // Print type of residual norm to the screen + if (scaleResidualHist) + out << "Using scaled residual norm." << std::endl; + else + out << "Using unscaled residual norm." << std::endl; + TEUCHOS_TEST_FOR_EXCEPT_MSG(!(numLevels>0), "We require numLevel > 0. Probably, numLevel has not been set, yet."); // We first use the non-level container variables to setup the fine grid problem. @@ -363,6 +440,7 @@ void solveRegionProblem(const double tol, const bool scaleResidualHist, const in // Composite residual vector RCP compRes = VectorFactory::Build(dofMap, true); + compRes = VectorFactory::Build(dofMap, true); // transform composite vectors to regional layout Teuchos::RCP quasiRegX; @@ -378,10 +456,113 @@ void solveRegionProblem(const double tol, const bool scaleResidualHist, const in RCP regRes; regRes = VectorFactory::Build(revisedRowMap, true); + Teuchos::RCP regCorrect; + regCorrect = VectorFactory::Build(revisedRowMap, true); + ///////////////////////////////////////////////////////////////////////// // SWITCH TO RECURSIVE STYLE --> USE LEVEL CONTAINER VARIABLES ///////////////////////////////////////////////////////////////////////// + + // Richardson iterations + magnitude_type normResIni = Teuchos::ScalarTraits::zero(); + const int old_precision = std::cout.precision(); + std::cout << std::setprecision(8) << std::scientific; + int cycle = 0; + + // Get Stuff out of Hierarchy + RCP level = regHierarchy->GetLevel(0); + RCP regInterfaceScalings = level->Get >("regInterfaceScalings"); + bool zeroInitGuess = true; + for (cycle = 0; cycle < maxIts; ++cycle) { + regCorrect->putScalar(SC_zero); + // check for convergence + { + //////////////////////////////////////////////////////////////////////// + // SWITCH BACK TO NON-LEVEL VARIABLES + //////////////////////////////////////////////////////////////////////// + computeResidual(regRes, regX, regB, regMat, *smootherParams[0]); + scaleInterfaceDOFs(regRes, regInterfaceScalings, true); + regionalToComposite(regRes, compRes, rowImport); + + typename Teuchos::ScalarTraits::magnitudeType normRes = compRes->norm2(); + if(cycle == 0) { normResIni = normRes; }// out << "NormResIni = " << normResIni << std::endl; } + if(scaleResidualHist) { normRes /= normResIni; } + + // Output current residual norm to screen (on proc 0 only) + out << cycle << "\t" << normRes << std::endl; + if (myRank == 0) + (*log) << cycle << "\t" << normRes << "\n"; + + if (normRes < tol) + break; + } + + ///////////////////////////////////////////////////////////////////////// + // SWITCH TO RECURSIVE STYLE --> USE LEVEL CONTAINER VARIABLES + ///////////////////////////////////////////////////////////////////////// + + scaleInterfaceDOFs(regRes, regInterfaceScalings, false); + + // std::cout << "regB->norm2() " << regRes->norm2() << std::endl; + vCycle(0, numLevels, cycleType, regHierarchy, + regCorrect, regRes, + smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); + + // std::cout << "regX->norm2() " << regCorrect->norm2() << std::endl; + + regX->update(SC_one, *regCorrect, SC_one); + + } + out << "Number of iterations performed for this solve: " << cycle << std::endl; + + std::cout << std::setprecision(old_precision); + std::cout.unsetf(std::ios::fixed | std::ios::scientific); +} // solveRegionProblem + +template +void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, const int maxIts, + const std::string cycleType, const std::string convergenceLog, + RCP& coarseSolverData, + Array >& smootherParams, + RCP hierarchyData, + RCP > & regHierarchy, + RCP >& A, + RCP >& X, + RCP >& B) { + + using LO = LocalOrdinal; + using GO = GlobalOrdinal; + using NO = Node; + using SC = Scalar; + + using Map = Xpetra::Map; + using Import = Xpetra::Import; + using Matrix = Xpetra::Matrix; + using Vector = Xpetra::Vector; + using VectorFactory = Xpetra::VectorFactory; + + using Level = MueLu::Level; + + using STS = Teuchos::ScalarTraits; + using magnitude_type = typename STS::magnitudeType; + const Scalar SC_zero = STS::zero(); + const Scalar SC_one = STS::one(); + + // we start by extracting some basic data from the hierarchy + const int numLevels = regHierarchy->GetNumLevels(); + RCP level0 = regHierarchy->GetLevel(0); + RCP regMat = level0->Get >("A"); + RCP revisedRowMap = regMat->getRowMap(); + RCP rowImport = level0->Get >("rowImport"); + RCP dofMap = X->getMap(); + const int myRank = dofMap->getComm()->getRank(); + + // Instead of checking each time for rank, create a rank 0 stream + RCP fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout)); + Teuchos::FancyOStream& out = *fancy; + out.setOutputToRootOnly(0); + // Prepare output of residual norm to file RCP log; if (myRank == 0) @@ -399,64 +580,182 @@ void solveRegionProblem(const double tol, const bool scaleResidualHist, const in else out << "Using unscaled residual norm." << std::endl; + TEUCHOS_TEST_FOR_EXCEPT_MSG(!(numLevels>0), "We require numLevel > 0. Probably, numLevel has not been set, yet."); - // Richardson iterations - magnitude_type normResIni = Teuchos::ScalarTraits::zero(); + // PCG iterations const int old_precision = std::cout.precision(); std::cout << std::setprecision(8) << std::scientific; + + // Get Stuff out of Hierarchy + RCP level = regHierarchy->GetLevel(0); + RCP regInterfaceScalings = level->Get >("regInterfaceScalings"); + bool zeroInitGuess = true; + + // Set variables for iterations int cycle = 0; + RCP Res = VectorFactory::Build(dofMap, true); + RCP Z = VectorFactory::Build(dofMap, true); + RCP P = VectorFactory::Build(dofMap, true); + RCP AP = VectorFactory::Build(dofMap, true); + magnitude_type normResIni = Teuchos::ScalarTraits::zero(); + magnitude_type normRes = Teuchos::ScalarTraits::zero(); + + A->apply(*X, *Res, Teuchos::NO_TRANS, -SC_one, SC_zero); + Res->update(SC_one, *B, SC_one); + normRes = Res->norm2(); + Z->putScalar(SC_zero); + + vCycleAdapter(numLevels, cycleType, regHierarchy, + Z, Res, + smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); + *P = *Z; // deep copy values of Z into P + + Scalar alpha = SC_zero, beta = SC_zero; + for (cycle = 0; cycle < maxIts; ++cycle) { + A->apply(*P, *AP, Teuchos::NO_TRANS, SC_one, SC_zero); + alpha = Res->dot(*Z); + beta = 1 / alpha; // Res and Z get overwritten later so we store 1 / (R^T * Z); + alpha = alpha / P->dot(*AP); + X->update(alpha, *P, SC_one); + Res->update(-alpha, *AP, SC_one); + + // check for convergence + { + normRes = Res->norm2(); - Teuchos::RCP regCorrect; - regCorrect = VectorFactory::Build(revisedRowMap, true); - for (cycle = 0; cycle < maxIts; ++cycle) + if(cycle == 0) { normResIni = normRes; }// out << "NormResIni = " << normResIni << std::endl;} + if(scaleResidualHist) { normRes /= normResIni; } + + // Output current residual norm to screen (on proc 0 only) + out << cycle << "\t" << normRes << std::endl; + if (myRank == 0) + (*log) << cycle << "\t" << normRes << "\n"; + + if (normRes < tol) + break; + } + + vCycleAdapter(numLevels, cycleType, regHierarchy, + Z, Res, + smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); + beta = Res->dot(*Z)*beta; + P->update(SC_one, *Z, beta); + } + out << "Number of iterations performed for this solve: " << cycle << std::endl; + + std::cout << std::setprecision(old_precision); + std::cout.unsetf(std::ios::fixed | std::ios::scientific); +} // solveCompositeProblemPCG + +template +void solveCompositeProblemRichardson(const double tol, const bool scaleResidualHist, const int maxIts, + const std::string cycleType, const std::string convergenceLog, + RCP& coarseSolverData, + Array >& smootherParams, + RCP hierarchyData, + RCP > & regHierarchy, + RCP >& A, + RCP >& X, + RCP >& B) { + + using LO = LocalOrdinal; + using GO = GlobalOrdinal; + using NO = Node; + using SC = Scalar; + + using Map = Xpetra::Map; + using Import = Xpetra::Import; + using Matrix = Xpetra::Matrix; + using Vector = Xpetra::Vector; + using VectorFactory = Xpetra::VectorFactory; + + using Level = MueLu::Level; + + using STS = Teuchos::ScalarTraits; + using magnitude_type = typename STS::magnitudeType; + const Scalar SC_zero = STS::zero(); + const Scalar SC_one = STS::one(); + + // we start by extracting some basic data from the hierarchy + const int numLevels = regHierarchy->GetNumLevels(); + RCP level0 = regHierarchy->GetLevel(0); + RCP regMat = level0->Get >("A"); + RCP revisedRowMap = regMat->getRowMap(); + RCP rowImport = level0->Get >("rowImport"); + RCP dofMap = X->getMap(); + const int myRank = dofMap->getComm()->getRank(); + + // Instead of checking each time for rank, create a rank 0 stream + RCP fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout)); + Teuchos::FancyOStream& out = *fancy; + out.setOutputToRootOnly(0); + + // Prepare output of residual norm to file + RCP log; + if (myRank == 0) { - const Scalar SC_ZERO = Teuchos::ScalarTraits::zero(); - regCorrect->putScalar(SC_ZERO); - // Get Stuff out of Hierarchy - RCP level = regHierarchy->GetLevel(0); - RCP regInterfaceScalings = level->Get >("regInterfaceScalings"); - // check for convergence - { - //////////////////////////////////////////////////////////////////////// - // SWITCH BACK TO NON-LEVEL VARIABLES - //////////////////////////////////////////////////////////////////////// - computeResidual(regRes, regX, regB, regMat, *smootherParams[0]); - scaleInterfaceDOFs(regRes, regInterfaceScalings, true); + log = rcp(new std::ofstream(convergenceLog.c_str())); + (*log) << "# num procs = " << dofMap->getComm()->getSize() << "\n" + << "# iteration | res-norm (scaled=" << scaleResidualHist << ")\n" + << "#\n"; + *log << std::setprecision(16) << std::scientific; + } - compRes = VectorFactory::Build(dofMap, true); - regionalToComposite(regRes, compRes, rowImport); + // Print type of residual norm to the screen + if (scaleResidualHist) + out << "Using scaled residual norm." << std::endl; + else + out << "Using unscaled residual norm." << std::endl; - typename Teuchos::ScalarTraits::magnitudeType normRes = compRes->norm2(); - if(cycle == 0) { normResIni = normRes; } + TEUCHOS_TEST_FOR_EXCEPT_MSG(!(numLevels>0), "We require numLevel > 0. Probably, numLevel has not been set, yet."); - if (scaleResidualHist) - normRes /= normResIni; + // Richardson iterations + const int old_precision = std::cout.precision(); + std::cout << std::setprecision(8) << std::scientific; - // Output current residual norm to screen (on proc 0 only) - out << cycle << "\t" << normRes << std::endl; - if (myRank == 0) - (*log) << cycle << "\t" << normRes << "\n"; + // Set variables for iterations + int cycle = 0; + RCP Correct = VectorFactory::Build(dofMap, true); + RCP Res = VectorFactory::Build(dofMap, true); + magnitude_type normResIni = Teuchos::ScalarTraits::zero(); + magnitude_type normRes = Teuchos::ScalarTraits::zero(); - if (normRes < tol) - break; - } + // out << "X->norm2() " << X->norm2() << std::endl; - ///////////////////////////////////////////////////////////////////////// - // SWITCH TO RECURSIVE STYLE --> USE LEVEL CONTAINER VARIABLES - ///////////////////////////////////////////////////////////////////////// + // Get Stuff out of Hierarchy + RCP level = regHierarchy->GetLevel(0); + RCP regInterfaceScalings = level->Get >("regInterfaceScalings"); + bool zeroInitGuess = true; + for (cycle = 0; cycle < maxIts; ++cycle) { + Correct->putScalar(SC_zero); + // check for convergence + { + A->apply(*X, *Res, Teuchos::NO_TRANS, -SC_one, SC_zero); + Res->update(SC_one, *B, SC_one); + normRes = Res->norm2(); + + if(cycle == 0) { normResIni = normRes; }// out << "NormResIni = " << normResIni << std::endl;} + if(scaleResidualHist) { normRes /= normResIni; } - bool zeroInitGuess = true; - scaleInterfaceDOFs(regRes, regInterfaceScalings, false); - vCycle(0, numLevels, cycleType, regHierarchy, - regCorrect, regRes, - smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); + // Output current residual norm to screen (on proc 0 only) + out << cycle << "\t" << normRes << std::endl; + if (myRank == 0) + (*log) << cycle << "\t" << normRes << "\n"; - regX->update(one, *regCorrect, one); + if (normRes < tol) + break; } + + vCycleAdapter(numLevels, cycleType, regHierarchy, + Correct, Res, + smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); + + X->update(SC_one, *Correct, SC_one); + } out << "Number of iterations performed for this solve: " << cycle << std::endl; std::cout << std::setprecision(old_precision); std::cout.unsetf(std::ios::fixed | std::ios::scientific); -} +} // solveCompositeProblemRichardson #endif // MUELU_SOLVEREGIONHIERARCHY_DEF_HPP diff --git a/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp b/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp index dc36c40140dc..c293cc44b075 100644 --- a/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp +++ b/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp @@ -597,8 +597,10 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar revisedRowMap, revisedColMap, rowImport, quasiRegionMats, regionMats); - // We don't need the composite operator on the fine level anymore. Free it! - A = Teuchos::null; + // Actually for now we are keeping it so we can implement + // iterative solvers using composite operator and vectors. + // // We don't need the composite operator on the fine level anymore. Free it! + // A = Teuchos::null; comm->barrier(); tmLocal = Teuchos::null; @@ -766,10 +768,18 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar // fclose(fp); #endif - solveRegionProblem(tol, scaleResidualHist, maxIts, - cycleType, convergenceLog, - coarseSolverData, smootherParams, hierarchyData, - regHierarchy, X, B); + // solveRegionProblem(tol, scaleResidualHist, maxIts, + // cycleType, convergenceLog, + // coarseSolverData, smootherParams, hierarchyData, + // regHierarchy, X, B); + // solveCompositeProblemRichardson(tol, scaleResidualHist, maxIts, + // cycleType, convergenceLog, + // coarseSolverData, smootherParams, hierarchyData, + // regHierarchy, A, X, B); + solveCompositeProblemPCG(tol, scaleResidualHist, maxIts, + cycleType, convergenceLog, + coarseSolverData, smootherParams, hierarchyData, + regHierarchy, A, X, B); comm->barrier(); tm = Teuchos::null; From 8904ed2119e67f02ad1c9365ccdb04f4f4a174c0 Mon Sep 17 00:00:00 2001 From: Luc Berger-Vergiat Date: Tue, 1 Mar 2022 10:24:24 -0700 Subject: [PATCH 009/147] MueLu: region MG small clean-ups --- .../regionMG/src/SolveRegionHierarchy_def.hpp | 21 +++++++------------ .../structured/Driver_Structured_Regions.cpp | 20 +++++++++--------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp index c12c2683e12d..03bab0b4163a 100644 --- a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp +++ b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp @@ -336,35 +336,30 @@ void vCycleAdapter(const int numLevels, ///< Total number of levels // Extract some info from the hierarchy // to convert vectors from composite to regional and back - RCP level0 = regHierarchy->GetLevel(0); - RCP regMat = level0->Get >("A"); - RCP revisedRowMap = regMat->getRowMap(); - RCP rowImport = level0->Get >("rowImport"); + RCP level0 = regHierarchy->GetLevel(0); + RCP rowImport = level0->Get >("rowImport"); + RCP regInterfaceScalings = level0->Get >("regInterfaceScalings"); + RCP regMat = level0->Get >("A"); + RCP revisedRowMap = regMat->getRowMap(); // Compute region vectors for B and X RCP quasiRegB; RCP regB; compositeToRegional(B, quasiRegB, regB, revisedRowMap, rowImport); + // scaleInterfaceDOFs(regB, regInterfaceScalings, false); RCP quasiRegX; RCP regX; compositeToRegional(X, quasiRegX, regX, revisedRowMap, rowImport); - - Teuchos::RCP regCorrect; - regCorrect = VectorFactory::Build(revisedRowMap, true); - - // std::cout << "regB->norm2() " << regB->norm2() << std::endl; + scaleInterfaceDOFs(regX, regInterfaceScalings, true); vCycle(0, numLevels, cycleType, regHierarchy, regX, regB, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); - // std::cout << "regX->norm2() " << regX->norm2() << std::endl; - // Bring solution back to composite format - RCP regInterfaceScalings = level0->Get >("regInterfaceScalings"); scaleInterfaceDOFs(regX, regInterfaceScalings, true); regionalToComposite(regX, X, rowImport); } // vCycleAdapter @@ -608,7 +603,7 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co vCycleAdapter(numLevels, cycleType, regHierarchy, Z, Res, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); - *P = *Z; // deep copy values of Z into P + P->update(SC_one, *Z, SC_zero); // deep copy values of Z into P Scalar alpha = SC_zero, beta = SC_zero; for (cycle = 0; cycle < maxIts; ++cycle) { diff --git a/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp b/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp index c293cc44b075..d8ec3941e479 100644 --- a/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp +++ b/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp @@ -430,7 +430,7 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar procsPerDim[2] = galeriList.get("mz"); } - const LO numLocalCompositeNodes = lNodesPerDim[0]*lNodesPerDim[1]*lNodesPerDim[2]; + // const LO numLocalCompositeNodes = lNodesPerDim[0]*lNodesPerDim[1]*lNodesPerDim[2]; // Rule for boundary duplication // For any two ranks that share an interface: @@ -472,7 +472,7 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar quasiRegionGIDs, quasiRegionCoordGIDs, compositeToRegionLIDs, interfaceGIDs, interfaceLIDsData); - const LO numSend = static_cast(sendGIDs.size()); + // const LO numSend = static_cast(sendGIDs.size()); // std::cout << "p=" << myRank << " | numSend=" << numSend << std::endl; // << ", numReceive=" << numReceive << std::endl; @@ -768,18 +768,18 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar // fclose(fp); #endif - // solveRegionProblem(tol, scaleResidualHist, maxIts, - // cycleType, convergenceLog, - // coarseSolverData, smootherParams, hierarchyData, - // regHierarchy, X, B); + solveRegionProblem(tol, scaleResidualHist, maxIts, + cycleType, convergenceLog, + coarseSolverData, smootherParams, hierarchyData, + regHierarchy, X, B); // solveCompositeProblemRichardson(tol, scaleResidualHist, maxIts, // cycleType, convergenceLog, // coarseSolverData, smootherParams, hierarchyData, // regHierarchy, A, X, B); - solveCompositeProblemPCG(tol, scaleResidualHist, maxIts, - cycleType, convergenceLog, - coarseSolverData, smootherParams, hierarchyData, - regHierarchy, A, X, B); + // solveCompositeProblemPCG(tol, scaleResidualHist, maxIts, + // cycleType, convergenceLog, + // coarseSolverData, smootherParams, hierarchyData, + // regHierarchy, A, X, B); comm->barrier(); tm = Teuchos::null; From 973756df6869ffb6c72ec74091451262c0935ca9 Mon Sep 17 00:00:00 2001 From: Luc Berger-Vergiat Date: Tue, 1 Mar 2022 16:18:51 -0700 Subject: [PATCH 010/147] MueLu: region MG driver update and CG fix Updating the region MG driver to allow switch between region solver, composite Richardson and composite CG at runtime. This makes it easier to debug code and also just makes more sense in the long run as we will probably want to switch between various solvers depending on the problem we try to solve. Adding some code fixes for CG, it now converges on one of our regression tests which is a good sign but it is still slower than the Richardson iteration which probably points to more issues. --- .../regionMG/src/SolveRegionHierarchy_def.hpp | 23 ++++++++---- .../structured/Driver_Structured_Regions.cpp | 37 +++++++++++-------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp index 03bab0b4163a..6709f5bf8626 100644 --- a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp +++ b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp @@ -347,13 +347,13 @@ void vCycleAdapter(const int numLevels, ///< Total number of levels RCP regB; compositeToRegional(B, quasiRegB, regB, revisedRowMap, rowImport); - // scaleInterfaceDOFs(regB, regInterfaceScalings, false); + // scaleInterfaceDOFs(regB, regInterfaceScalings, true); RCP quasiRegX; RCP regX; compositeToRegional(X, quasiRegX, regX, revisedRowMap, rowImport); - scaleInterfaceDOFs(regX, regInterfaceScalings, true); + // scaleInterfaceDOFs(regX, regInterfaceScalings, true); vCycle(0, numLevels, cycleType, regHierarchy, regX, regB, @@ -605,12 +605,18 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); P->update(SC_one, *Z, SC_zero); // deep copy values of Z into P - Scalar alpha = SC_zero, beta = SC_zero; + Scalar alpha = SC_zero, beta_old = SC_zero, beta_new = SC_zero, PAP = SC_zero; for (cycle = 0; cycle < maxIts; ++cycle) { A->apply(*P, *AP, Teuchos::NO_TRANS, SC_one, SC_zero); - alpha = Res->dot(*Z); - beta = 1 / alpha; // Res and Z get overwritten later so we store 1 / (R^T * Z); - alpha = alpha / P->dot(*AP); + PAP = P->dot(*AP); + + TEUCHOS_TEST_FOR_EXCEPTION(PAP <= SC_zero, std::runtime_error, + "At iteration " << (cycle) << " out of " << maxIts + << ", P.dot(AP) = " << PAP << " <= 0. This usually means that " + "the matrix A is not symmetric (Hermitian) positive definite."); + + beta_old = Res->dot(*Z); + alpha = beta_old / PAP; X->update(alpha, *P, SC_one); Res->update(-alpha, *AP, SC_one); @@ -633,8 +639,9 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co vCycleAdapter(numLevels, cycleType, regHierarchy, Z, Res, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); - beta = Res->dot(*Z)*beta; - P->update(SC_one, *Z, beta); + + P->update(SC_one, *Z, (beta_new / beta_old)); + beta_old = beta_new; } out << "Number of iterations performed for this solve: " << cycle << std::endl; diff --git a/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp b/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp index d8ec3941e479..880290013311 100644 --- a/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp +++ b/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp @@ -165,16 +165,17 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar std::string xmlFileName = ""; clp.setOption("xml", &xmlFileName, "read parameters from an xml file"); std::string yamlFileName = ""; clp.setOption("yaml", &yamlFileName, "read parameters from a yaml file"); + std::string solverType = "region"; clp.setOption("solverType", &solverType, "iterative solver to be used: (region | Richardson | CG)"); std::string convergenceLog = "residual_norm.txt"; clp.setOption("convergence-log", &convergenceLog, "file in which the convergence history of the linear solver is stored"); int maxIts = 200; clp.setOption("its", &maxIts, "maximum number of solver iterations"); + double tol = 1e-12; clp.setOption("tol", &tol, "solver convergence tolerance"); + bool scaleResidualHist = true; clp.setOption("scale", "noscale", &scaleResidualHist, "scaled Krylov residual history"); + bool serialRandom = false; clp.setOption("use-serial-random", "no-use-serial-random", &serialRandom, "generate the random vector serially and then broadcast it"); std::string smootherType = "Jacobi"; clp.setOption("smootherType", &smootherType, "smoother to be used: (None | Jacobi | Gauss | Chebyshev)"); int smootherIts = 2; clp.setOption("smootherIts", &smootherIts, "number of smoother iterations"); double smootherDamp = 0.67; clp.setOption("smootherDamp", &smootherDamp, "damping parameter for the level smoother"); double smootherChebyEigRatio = 2.0; clp.setOption("smootherChebyEigRatio", &smootherChebyEigRatio, "eigenvalue ratio max/min used to approximate the smallest eigenvalue for Chebyshev relaxation"); double smootherChebyBoostFactor = 1.1; clp.setOption("smootherChebyBoostFactor", &smootherChebyBoostFactor, "boost factor for Chebyshev smoother"); - double tol = 1e-12; clp.setOption("tol", &tol, "solver convergence tolerance"); - bool scaleResidualHist = true; clp.setOption("scale", "noscale", &scaleResidualHist, "scaled Krylov residual history"); - bool serialRandom = false; clp.setOption("use-serial-random", "no-use-serial-random", &serialRandom, "generate the random vector serially and then broadcast it"); bool keepCoarseCoords = false; clp.setOption("keep-coarse-coords", "no-keep-coarse-coords", &keepCoarseCoords, "keep coordinates on coarsest level of region hierarchy"); bool coarseSolverRebalance = false; clp.setOption("rebalance-coarse", "no-rebalance-coarse", &coarseSolverRebalance, "rebalance before AMG coarse grid solve"); int rebalanceNumPartitions = -1; clp.setOption("numPartitions", &rebalanceNumPartitions, "number of partitions for rebalancing the coarse grid AMG solve"); @@ -768,18 +769,24 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar // fclose(fp); #endif - solveRegionProblem(tol, scaleResidualHist, maxIts, - cycleType, convergenceLog, - coarseSolverData, smootherParams, hierarchyData, - regHierarchy, X, B); - // solveCompositeProblemRichardson(tol, scaleResidualHist, maxIts, - // cycleType, convergenceLog, - // coarseSolverData, smootherParams, hierarchyData, - // regHierarchy, A, X, B); - // solveCompositeProblemPCG(tol, scaleResidualHist, maxIts, - // cycleType, convergenceLog, - // coarseSolverData, smootherParams, hierarchyData, - // regHierarchy, A, X, B); + if(solverType == "region") { + solveRegionProblem(tol, scaleResidualHist, maxIts, + cycleType, convergenceLog, + coarseSolverData, smootherParams, hierarchyData, + regHierarchy, X, B); + } else if(solverType == "Richardson") { + solveCompositeProblemRichardson(tol, scaleResidualHist, maxIts, + cycleType, convergenceLog, + coarseSolverData, smootherParams, hierarchyData, + regHierarchy, A, X, B); + } else if(solverType == "CG") { + solveCompositeProblemPCG(tol, scaleResidualHist, maxIts, + cycleType, convergenceLog, + coarseSolverData, smootherParams, hierarchyData, + regHierarchy, A, X, B); + } else { + throw std::runtime_error("Unknown solverType: "+solverType); + } comm->barrier(); tm = Teuchos::null; From c104a10e253755b1279bc3cab3152cb57dc31477 Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Wed, 2 Mar 2022 10:55:18 +0100 Subject: [PATCH 011/147] MueLu: fix CG in region code - zero-out Z before handing it to the preconditioner - update beta in every CG iteration --- .../muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp index 6709f5bf8626..417db388dadc 100644 --- a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp +++ b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp @@ -597,7 +597,7 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co A->apply(*X, *Res, Teuchos::NO_TRANS, -SC_one, SC_zero); Res->update(SC_one, *B, SC_one); - normRes = Res->norm2(); + // normRes = Res->norm2(); Z->putScalar(SC_zero); vCycleAdapter(numLevels, cycleType, regHierarchy, @@ -636,10 +636,12 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co break; } + Z->putScalar(SC_zero); vCycleAdapter(numLevels, cycleType, regHierarchy, Z, Res, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); + beta_new = Res->dot(*Z); P->update(SC_one, *Z, (beta_new / beta_old)); beta_old = beta_new; } From 9af4085e05e2d07b4ab095ce8bd1cd6ff0d52cd4 Mon Sep 17 00:00:00 2001 From: Luc Berger-Vergiat Date: Wed, 2 Mar 2022 07:40:37 -0700 Subject: [PATCH 012/147] MueLu: region MG printing name of solver for sanity check --- .../research/regionMG/src/SolveRegionHierarchy_def.hpp | 7 +++++-- .../regionMG/test/structured/Driver_Structured_Regions.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp index 417db388dadc..1ebf12f63bfd 100644 --- a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp +++ b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp @@ -418,6 +418,7 @@ void solveRegionProblem(const double tol, const bool scaleResidualHist, const in } // Print type of residual norm to the screen + out << "using region solver" << std::endl; if (scaleResidualHist) out << "Using scaled residual norm." << std::endl; else @@ -570,6 +571,7 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co } // Print type of residual norm to the screen + out << "Using CG solver" << std::endl; if (scaleResidualHist) out << "Using scaled residual norm." << std::endl; else @@ -597,7 +599,7 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co A->apply(*X, *Res, Teuchos::NO_TRANS, -SC_one, SC_zero); Res->update(SC_one, *B, SC_one); - // normRes = Res->norm2(); + normResIni = Res->norm2(); Z->putScalar(SC_zero); vCycleAdapter(numLevels, cycleType, regHierarchy, @@ -624,7 +626,7 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co { normRes = Res->norm2(); - if(cycle == 0) { normResIni = normRes; }// out << "NormResIni = " << normResIni << std::endl;} + // if(cycle == 0) { normResIni = normRes; }// out << "NormResIni = " << normResIni << std::endl;} if(scaleResidualHist) { normRes /= normResIni; } // Output current residual norm to screen (on proc 0 only) @@ -706,6 +708,7 @@ void solveCompositeProblemRichardson(const double tol, const bool scaleResidualH } // Print type of residual norm to the screen + out << "Using Richardson solver" << std::endl; if (scaleResidualHist) out << "Using scaled residual norm." << std::endl; else diff --git a/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp b/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp index 880290013311..704714ce4a93 100644 --- a/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp +++ b/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp @@ -171,6 +171,7 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar double tol = 1e-12; clp.setOption("tol", &tol, "solver convergence tolerance"); bool scaleResidualHist = true; clp.setOption("scale", "noscale", &scaleResidualHist, "scaled Krylov residual history"); bool serialRandom = false; clp.setOption("use-serial-random", "no-use-serial-random", &serialRandom, "generate the random vector serially and then broadcast it"); + std::string cycleType = "V"; clp.setOption("cycleType", &cycleType, "{Multigrid cycle type. Possible values: V, W."); std::string smootherType = "Jacobi"; clp.setOption("smootherType", &smootherType, "smoother to be used: (None | Jacobi | Gauss | Chebyshev)"); int smootherIts = 2; clp.setOption("smootherIts", &smootherIts, "number of smoother iterations"); double smootherDamp = 0.67; clp.setOption("smootherDamp", &smootherDamp, "damping parameter for the level smoother"); @@ -193,7 +194,6 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar int cacheSize = 0; clp.setOption("cachesize", &cacheSize, "cache size (in KB)"); bool useStackedTimer = false; clp.setOption("stacked-timer","no-stacked-timer", &useStackedTimer, "use stacked timer"); bool showTimerSummary = true; clp.setOption("show-timer-summary", "no-show-timer-summary", &showTimerSummary, "Switch on/off the timer summary at the end of the run."); - std::string cycleType = "V"; clp.setOption("cycleType", &cycleType, "{Multigrid cycle type. Possible values: V, W."); clp.recogniseAllOptions(true); switch (clp.parse(argc, argv)) { From 411b413487a13ab8f7757299de1f184277e67247 Mon Sep 17 00:00:00 2001 From: Jonathan Hu Date: Mon, 7 Mar 2022 20:38:04 -0700 Subject: [PATCH 013/147] MueLu: speed up amalgamation --- .../MueLu_AmalgamationFactory_def.hpp | 4 +- .../test/unit_tests/AmalgamationFactory.cpp | 41 ++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/packages/muelu/src/Graph/MatrixTransformation/MueLu_AmalgamationFactory_def.hpp b/packages/muelu/src/Graph/MatrixTransformation/MueLu_AmalgamationFactory_def.hpp index 1ab221d0ae14..549b00075d81 100644 --- a/packages/muelu/src/Graph/MatrixTransformation/MueLu_AmalgamationFactory_def.hpp +++ b/packages/muelu/src/Graph/MatrixTransformation/MueLu_AmalgamationFactory_def.hpp @@ -158,12 +158,12 @@ namespace MueLu { template void AmalgamationFactory::AmalgamateMap(const Map& sourceMap, const Matrix& A, RCP& amalgamatedMap, Array& translation) { typedef typename ArrayView::size_type size_type; - typedef std::map container; + typedef std::unordered_map container; GO indexBase = sourceMap.getIndexBase(); ArrayView elementAList = sourceMap.getLocalElementList(); size_type numElements = elementAList.size(); - container filter; // TODO: replace std::set with an object having faster lookup/insert, hashtable for instance + container filter; GO offset = 0; LO blkSize = A.GetFixedBlockSize(); diff --git a/packages/muelu/test/unit_tests/AmalgamationFactory.cpp b/packages/muelu/test/unit_tests/AmalgamationFactory.cpp index 528c3c2a3b0e..b01af40454af 100644 --- a/packages/muelu/test/unit_tests/AmalgamationFactory.cpp +++ b/packages/muelu/test/unit_tests/AmalgamationFactory.cpp @@ -99,10 +99,49 @@ namespace MueLuTests { } } // DOFGid2NodeId + TEUCHOS_UNIT_TEST_TEMPLATE_4_DECL(AmalgamationFactory, AmalgamateMap, Scalar, LocalOrdinal, GlobalOrdinal, Node) + { + // Test static method AmalgamationFactory::AmalgamateMap(). +# include + MUELU_TESTING_SET_OSTREAM; + MUELU_TESTING_LIMIT_SCOPE(Scalar,GlobalOrdinal,Node); + out << "Test static method AmalgamationFactory::AmalgamateMap()." << std::endl; + + RCP > comm = TestHelpers::Parameters::getDefaultComm(); + + const GlobalOrdinal nx = 32; + Teuchos::ParameterList matrixList; + matrixList.set("nx", nx); + matrixList.set("matrixType","Laplace1D"); + RCP Op = TestHelpers::TestFactory::BuildMatrix(matrixList,TestHelpers::Parameters::getLib()); + LO blkSize=2; + Op->SetFixedBlockSize(blkSize); + + RCP > theRowTranslation = rcp(new Array); + RCP uniqueMap; + AmalgamationFactory::AmalgamateMap(*(Op->getRowMap()), *Op, uniqueMap, *theRowTranslation); + + Teuchos::ArrayView localEltList = uniqueMap->getLocalElementList(); + for (size_t j=0; jgetLocalNumElements(); j++) { + TEST_EQUALITY(uniqueMap->getLocalElement(localEltList[j]),static_cast(j)); + } + + RCP > theColTranslation = rcp(new Array); + RCP nonUniqueMap; + AmalgamationFactory::AmalgamateMap(*(Op->getColMap()), *Op, nonUniqueMap, *theColTranslation); + + localEltList = nonUniqueMap->getLocalElementList(); + for (size_t j=0; jgetLocalNumElements(); j++) { + TEST_EQUALITY(nonUniqueMap->getLocalElement(localEltList[j]),static_cast(j)); + } + + } // AmalgamateMap + # define MUELU_ETI_GROUP(Scalar, LO, GO, Node) \ TEUCHOS_UNIT_TEST_TEMPLATE_4_INSTANT(AmalgamationFactory, Constructor, Scalar, LO, GO, Node) \ - TEUCHOS_UNIT_TEST_TEMPLATE_4_INSTANT(AmalgamationFactory, DOFGid2NodeId, Scalar, LO, GO, Node) + TEUCHOS_UNIT_TEST_TEMPLATE_4_INSTANT(AmalgamationFactory, DOFGid2NodeId, Scalar, LO, GO, Node) \ + TEUCHOS_UNIT_TEST_TEMPLATE_4_INSTANT(AmalgamationFactory, AmalgamateMap, Scalar, LO, GO, Node) # include From 5860b59717323824b32304aa8fe8ad1d6b22fcb1 Mon Sep 17 00:00:00 2001 From: Evan Harvey Date: Mon, 14 Mar 2022 07:49:02 -0600 Subject: [PATCH 014/147] packages/framework: Add LaunchDriver script - Added a new script that determines how to launch pull request driver scripts based on the system it is running on. --- packages/framework/pr_tools/LaunchDriver.py | 106 ++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100755 packages/framework/pr_tools/LaunchDriver.py diff --git a/packages/framework/pr_tools/LaunchDriver.py b/packages/framework/pr_tools/LaunchDriver.py new file mode 100755 index 000000000000..5cc2a47aa513 --- /dev/null +++ b/packages/framework/pr_tools/LaunchDriver.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 + +import argparse +from pathlib import Path +import sys +import subprocess + +# Packages are snapshotted via install_reqs.sh or these are in Python's site-packages +try: # pragma: no cover + from .determinesystem import DetermineSystem + +except ImportError: # pragma: no cover + try: # Perhaps this file is being imported from another directory + p = Path(__file__).parents[0] + sys.path.insert(0, str(p)) + + from determinesystem import DetermineSystem + + except ImportError: # Perhaps LoadEnv was snapshotted and these packages lie up one dir. + p = Path(__file__).parents[1] # One dir up from the path to this file + sys.path.insert(0, str(p)) + + from determinesystem import DetermineSystem + + + +def get_launch_env(build_name : str, system : str): + """ + Gets the launch environment based on the detected system. + This is an early environment that's required for running the driver. + + Returns: + str: The environment used to launch the driver. + """ + env = "" + if "_rdc" in build_name: + env += " TRILINOS_MAX_CORES=10" + + if system == "weaver" or system == "ats2": + env += " Trilinos_CTEST_DO_ALL_AT_ONCE=TRUE" + + if env == "": + return "" + else: + return "env" + env + " " + + +def get_launch_cmd(build_name : str, system : str): + """ + Gets the launch command based on the detected system. + + Returns: + str: The command used to launch the driver. + """ + if system == "weaver" or system == "ats2": + cmd = "bsub -Is -J " + build_name + " -W 12:00" + else: + cmd = "" + + return cmd + " " + + +def get_driver_args(system : str): + """ + Gets the driver arguments based on the detected system. + + Returns: + str: The arguments passed to the driver. + """ + return " " + "--on_" + system + + +def main(argv): + """ + This python script determines what system it is running on and then launches + the trilinos driver script appropriatly. + """ + parser = argparse.ArgumentParser(description='Launch a trilinos driver script on this system.') + parser.add_argument('--build-name', required=True, + help='The name of the build being launched') + parser.add_argument('--driver', required=False, + default='./PullRequestLinuxDriver.sh', + help='The driver script to launch') + parser.add_argument('--supported-systems', required=False, + default='./LoadEnv/ini_files/supported-systems.ini', + help='The INI file containing supported systems') + args = parser.parse_args() + + ds = DetermineSystem(args.build_name, args.supported_systems) + + launch_env = get_launch_env(args.build_name, ds.system_name) + launch_cmd = get_launch_cmd(args.build_name, ds.system_name) + driver_args = get_driver_args(ds.system_name) + + cmd = launch_env + launch_cmd + args.driver + driver_args + + print("LaunchDriver> exec: " + cmd) + + cmd_output = subprocess.run(cmd, shell=True) + + sys.exit(cmd_output.returncode) + + +if __name__ == "__main__": + main(sys.argv[1 :]) + From 03bba16271cc0880b2d304d968d31044d61c585b Mon Sep 17 00:00:00 2001 From: Evan Harvey Date: Mon, 14 Mar 2022 09:44:34 -0600 Subject: [PATCH 015/147] packages/framework: - Add "--on_$SYSTEM" flags. - Simplify bootstrap_modules logic. - Add weaver bootstrap branch. --- .../pr_tools/PullRequestLinuxDriver.sh | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/packages/framework/pr_tools/PullRequestLinuxDriver.sh b/packages/framework/pr_tools/PullRequestLinuxDriver.sh index 86122244a7d8..742576887304 100755 --- a/packages/framework/pr_tools/PullRequestLinuxDriver.sh +++ b/packages/framework/pr_tools/PullRequestLinuxDriver.sh @@ -4,6 +4,9 @@ SCRIPTPATH=$(dirname $SCRIPTFILE) source ${SCRIPTPATH:?}/common.bash # set -x # echo commands +# Fetch out arguments +on_cuda=$(echo "$@" | grep '\-\-on_weaver' && echo "1") +on_ats2=$(echo "$@" | grep '\-\-on_ats2' && echo "1") # Load the right version of Git / Python based on a regex @@ -11,28 +14,21 @@ source ${SCRIPTPATH:?}/common.bash function bootstrap_modules() { print_banner "Bootstrap environment modules start" - cuda_regex=".*(_cuda_).*" - ride_regex=".*(ride).*" vortex_regex=".*(vortex).*" - if [[ ${JOB_BASE_NAME:?} =~ ${cuda_regex} ]]; then - if [[ ${NODE_NAME:?} =~ ${ride_regex} ]]; then - message_std "PRDriver> " "Job is CUDA" - execute_command_checked "module unload git" - execute_command_checked "module unload python" - execute_command_checked "module load git/2.10.1" - execute_command_checked "module load python/3.7.3" - get_python_packages pip3 - envvar_set_or_create PYTHON_EXE python3 - elif [[ ${NODE_NAME:?} =~ ${vortex_regex} ]]; then - echo -e "Job is CUDA node is vortex" - execute_command_checked "module load git/2.20.0" - execute_command_checked "module load python/3.7.2" - get_python_packages pip3 - envvar_set_or_create PYTHON_EXE python3 - else - message_std "PRDriver> " "ERROR: Unable to find matching environment for CUDA job not on Ride." - exit -1 - fi + if [[ ${NODE_NAME:?} =~ ${vortex_regex} || ${on_ats2} == "1" ]]; then + message_std "PRDriver> " "Job is CUDA on ats2" + execute_command_checked "module load git/2.20.0" + execute_command_checked "module load python/3.7.2" + get_python_packages pip3 + envvar_set_or_create PYTHON_EXE python3 + elif [[ ${on_weaver} == "1" ]]; then + message_std "PRDriver> " "Job is CUDA on weaver" + module unload git + module unload python + module load git/2.10.1 + module load python/3.7.3 + get_python_packages pip3 + export PYTHON_EXE=python3 else execute_command_checked "module load apps/anaconda3.7" source /projects/sems/modulefiles/utils/sems-archive-modules-init.sh From b8d4bca0f66b78f586f5c1a98f446db488227fb1 Mon Sep 17 00:00:00 2001 From: Evan Harvey Date: Mon, 14 Mar 2022 09:47:56 -0600 Subject: [PATCH 016/147] packages/framework: Flush LaunchDriver print --- packages/framework/pr_tools/LaunchDriver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/pr_tools/LaunchDriver.py b/packages/framework/pr_tools/LaunchDriver.py index 5cc2a47aa513..a350da202f4a 100755 --- a/packages/framework/pr_tools/LaunchDriver.py +++ b/packages/framework/pr_tools/LaunchDriver.py @@ -94,7 +94,7 @@ def main(argv): cmd = launch_env + launch_cmd + args.driver + driver_args - print("LaunchDriver> exec: " + cmd) + print("LaunchDriver> exec: " + cmd, flush=True) cmd_output = subprocess.run(cmd, shell=True) From 6203803c1abff86532f68587acd44599d194d674 Mon Sep 17 00:00:00 2001 From: Evan Harvey Date: Mon, 14 Mar 2022 10:03:53 -0600 Subject: [PATCH 017/147] package/framework: Require TRILINOS_DIR & cleanup --- packages/framework/pr_tools/LaunchDriver.py | 11 ++++++++++- packages/framework/pr_tools/PullRequestLinuxDriver.sh | 5 ++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/framework/pr_tools/LaunchDriver.py b/packages/framework/pr_tools/LaunchDriver.py index a350da202f4a..b0d97dc007b5 100755 --- a/packages/framework/pr_tools/LaunchDriver.py +++ b/packages/framework/pr_tools/LaunchDriver.py @@ -4,6 +4,7 @@ from pathlib import Path import sys import subprocess +import os # Packages are snapshotted via install_reqs.sh or these are in Python's site-packages try: # pragma: no cover @@ -74,6 +75,8 @@ def main(argv): """ This python script determines what system it is running on and then launches the trilinos driver script appropriatly. + + The script returns 0 upon success and non-zero otherwise. """ parser = argparse.ArgumentParser(description='Launch a trilinos driver script on this system.') parser.add_argument('--build-name', required=True, @@ -86,6 +89,12 @@ def main(argv): help='The INI file containing supported systems') args = parser.parse_args() + if os.getenv("TRILINOS_DIR") == None: + print("LaunchDriver> ERROR: Please set TRILINOS_DIR.", flush=True) + sys.exit(1) + + print("LaunchDriver> INFO: TRILINOS_DIR=\"" + os.environ["TRILINOS_DIR"] + "\"", flush=True) + ds = DetermineSystem(args.build_name, args.supported_systems) launch_env = get_launch_env(args.build_name, ds.system_name) @@ -94,7 +103,7 @@ def main(argv): cmd = launch_env + launch_cmd + args.driver + driver_args - print("LaunchDriver> exec: " + cmd, flush=True) + print("LaunchDriver> EXEC: " + cmd, flush=True) cmd_output = subprocess.run(cmd, shell=True) diff --git a/packages/framework/pr_tools/PullRequestLinuxDriver.sh b/packages/framework/pr_tools/PullRequestLinuxDriver.sh index 742576887304..1ddb9a66fae1 100755 --- a/packages/framework/pr_tools/PullRequestLinuxDriver.sh +++ b/packages/framework/pr_tools/PullRequestLinuxDriver.sh @@ -4,7 +4,7 @@ SCRIPTPATH=$(dirname $SCRIPTFILE) source ${SCRIPTPATH:?}/common.bash # set -x # echo commands -# Fetch out arguments +# Fetch arguments on_cuda=$(echo "$@" | grep '\-\-on_weaver' && echo "1") on_ats2=$(echo "$@" | grep '\-\-on_ats2' && echo "1") @@ -13,16 +13,15 @@ on_ats2=$(echo "$@" | grep '\-\-on_ats2' && echo "1") # match to the Jenkins job name. function bootstrap_modules() { print_banner "Bootstrap environment modules start" + message_std "PRDriver> " "Job is $JOB_BASE_NAME" vortex_regex=".*(vortex).*" if [[ ${NODE_NAME:?} =~ ${vortex_regex} || ${on_ats2} == "1" ]]; then - message_std "PRDriver> " "Job is CUDA on ats2" execute_command_checked "module load git/2.20.0" execute_command_checked "module load python/3.7.2" get_python_packages pip3 envvar_set_or_create PYTHON_EXE python3 elif [[ ${on_weaver} == "1" ]]; then - message_std "PRDriver> " "Job is CUDA on weaver" module unload git module unload python module load git/2.10.1 From 9841642681fdb2c1dcf3e03f2faeedbca905044c Mon Sep 17 00:00:00 2001 From: Evan Harvey Date: Mon, 14 Mar 2022 11:03:25 -0600 Subject: [PATCH 018/147] packages/framework: Remove load of anaconda3.7 --- packages/framework/pr_tools/PullRequestLinuxDriver.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/framework/pr_tools/PullRequestLinuxDriver.sh b/packages/framework/pr_tools/PullRequestLinuxDriver.sh index 1ddb9a66fae1..a94c6e33c0bf 100755 --- a/packages/framework/pr_tools/PullRequestLinuxDriver.sh +++ b/packages/framework/pr_tools/PullRequestLinuxDriver.sh @@ -29,7 +29,6 @@ function bootstrap_modules() { get_python_packages pip3 export PYTHON_EXE=python3 else - execute_command_checked "module load apps/anaconda3.7" source /projects/sems/modulefiles/utils/sems-archive-modules-init.sh execute_command_checked "module unload sems-archive-git" execute_command_checked "module unload sems-archive-python" From 2f3e4538c36ce555b298793d55a26c0ab3a85645 Mon Sep 17 00:00:00 2001 From: Brian Kelley Date: Mon, 14 Mar 2022 13:51:07 -0600 Subject: [PATCH 019/147] Tpetra: tell user about runtime CUDA-aware setting Fix #4370: At configure time, if Tpetra can't figure out for certain that the MPI is CUDA-aware, remind the user that they can still assume CUDA-aware with a runtime environment variable. --- packages/tpetra/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/tpetra/CMakeLists.txt b/packages/tpetra/CMakeLists.txt index 9d269f441bb9..991059c53223 100644 --- a/packages/tpetra/CMakeLists.txt +++ b/packages/tpetra/CMakeLists.txt @@ -247,15 +247,15 @@ ELSE () MESSAGE (STATUS " - \"ompi_info\" explicitly claims that your MPI implementation is CUDA aware.") SET (Tpetra_ASSUME_CUDA_AWARE_MPI_DEFAULT ON) ELSEIF (NOT (Tpetra_OMPI_INFO_OUTPUT_FOUND_FALSE EQUAL -1)) - MESSAGE (STATUS " - \"ompi_info\" explicitly claims that your MPI implementation is NOT CUDA aware. You may want to use a different OpenMPI installation that is CUDA aware, or reconfigure and rebuild OpenMPI in order to make it CUDA aware. For details, please refer to OpenMPI's website: https://www.open-mpi.org/faq/?category=runcuda") + MESSAGE (STATUS " - \"ompi_info\" explicitly claims that your MPI implementation is NOT CUDA aware. You may want to use a different OpenMPI installation that is CUDA aware, or reconfigure and rebuild OpenMPI in order to make it CUDA aware. For details, please refer to OpenMPI's website: https://www.open-mpi.org/faq/?category=runcuda . You can still override this at runtime with the environment variable TPETRA_ASSUME_CUDA_AWARE_MPI=ON or OFF.") ELSE () MESSAGE (STATUS " - \"ompi_info\" claims to know nothing about whether your MPI implementation is CUDA aware. Its output is \"${Tpetra_OMPI_INFO_OUTPUT}\".") ENDIF () ELSE () - MESSAGE (STATUS " - While I found the \"ompi_info\" executable, it would not run. Thus, I will make the sane assumption that your MPI implementation is NOT CUDA aware.") + MESSAGE (STATUS " - While I found the \"ompi_info\" executable, it would not run. Thus, I will make the sane assumption that your MPI implementation is NOT CUDA aware. You can change this at configure time with the option Tpetra_ASSUME_CUDA_AWARE_MPI=ON, and override the configure-time setting at runtime with the environment variable TPETRA_ASSUME_CUDA_AWARE_MPI=ON or OFF.") ENDIF () ELSE () - MESSAGE (STATUS " - Tpetra did not find the \"ompi_info\" executable. This may not be bad; for example, if your MPI implementation is not OpenMPI, then you won't have this executable. Tpetra will conservatively assume that your MPI implementation is NOT CUDA aware. If you would like to change this, please set the CMake variable Tpetra_ASSUME_CUDA_AWARE_MPI:BOOL=ON explicitly at configure time.") + MESSAGE (STATUS " - Tpetra did not find the \"ompi_info\" executable. This may not be bad; for example, if your MPI implementation is not OpenMPI, then you won't have this executable. Tpetra will conservatively assume that your MPI implementation is NOT CUDA aware. If you would like to change this, please set the CMake variable Tpetra_ASSUME_CUDA_AWARE_MPI:BOOL=ON explicitly at configure time. You can also override this at runtime with the environment variable TPETRA_ASSUME_CUDA_AWARE_MPI=ON or OFF.") ENDIF () # Tpetra_FOUND_OMPI_INFO_EXECUTABLE ENDIF () # Whether we are cross compiling ENDIF () # Whether we have CUDA and MPI From d734b4e61f0d55654b270aa7f43e9ec8e498516e Mon Sep 17 00:00:00 2001 From: Evan Harvey Date: Mon, 14 Mar 2022 16:03:25 -0600 Subject: [PATCH 020/147] packages/framework: - LaunchDriver: parse argv - PullRequestLinuxDriver: --on_cuda -> --on_weaver --- packages/framework/pr_tools/LaunchDriver.py | 2 +- packages/framework/pr_tools/PullRequestLinuxDriver.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/pr_tools/LaunchDriver.py b/packages/framework/pr_tools/LaunchDriver.py index b0d97dc007b5..7d03004c25ca 100755 --- a/packages/framework/pr_tools/LaunchDriver.py +++ b/packages/framework/pr_tools/LaunchDriver.py @@ -87,7 +87,7 @@ def main(argv): parser.add_argument('--supported-systems', required=False, default='./LoadEnv/ini_files/supported-systems.ini', help='The INI file containing supported systems') - args = parser.parse_args() + args = parser.parse_args(argv) if os.getenv("TRILINOS_DIR") == None: print("LaunchDriver> ERROR: Please set TRILINOS_DIR.", flush=True) diff --git a/packages/framework/pr_tools/PullRequestLinuxDriver.sh b/packages/framework/pr_tools/PullRequestLinuxDriver.sh index a94c6e33c0bf..20d7c38d3218 100755 --- a/packages/framework/pr_tools/PullRequestLinuxDriver.sh +++ b/packages/framework/pr_tools/PullRequestLinuxDriver.sh @@ -5,7 +5,7 @@ source ${SCRIPTPATH:?}/common.bash # set -x # echo commands # Fetch arguments -on_cuda=$(echo "$@" | grep '\-\-on_weaver' && echo "1") +on_weaver=$(echo "$@" | grep '\-\-on_weaver' && echo "1") on_ats2=$(echo "$@" | grep '\-\-on_ats2' && echo "1") From 9f4873ded5d7e4e650f17f6e422f295a3d0b0e22 Mon Sep 17 00:00:00 2001 From: Evan Harvey Date: Mon, 14 Mar 2022 16:05:42 -0600 Subject: [PATCH 021/147] packages/framework: Add LaunchDriver tests --- .../pr_tools/unittests/DriverTest0.sh | 5 ++ .../pr_tools/unittests/DriverTest1.sh | 5 ++ .../supporting_files/supported-systems.ini | 2 + .../pr_tools/unittests/test_LaunchDriver.py | 76 +++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100755 packages/framework/pr_tools/unittests/DriverTest0.sh create mode 100755 packages/framework/pr_tools/unittests/DriverTest1.sh create mode 100644 packages/framework/pr_tools/unittests/supporting_files/supported-systems.ini create mode 100755 packages/framework/pr_tools/unittests/test_LaunchDriver.py diff --git a/packages/framework/pr_tools/unittests/DriverTest0.sh b/packages/framework/pr_tools/unittests/DriverTest0.sh new file mode 100755 index 000000000000..bedd4dc717fc --- /dev/null +++ b/packages/framework/pr_tools/unittests/DriverTest0.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +echo "testing... $TESTVAR" + +exit 0 diff --git a/packages/framework/pr_tools/unittests/DriverTest1.sh b/packages/framework/pr_tools/unittests/DriverTest1.sh new file mode 100755 index 000000000000..1936a04e1699 --- /dev/null +++ b/packages/framework/pr_tools/unittests/DriverTest1.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +echo "testing... $TESTVAR" + +exit 1 diff --git a/packages/framework/pr_tools/unittests/supporting_files/supported-systems.ini b/packages/framework/pr_tools/unittests/supporting_files/supported-systems.ini new file mode 100644 index 000000000000..be4659f40677 --- /dev/null +++ b/packages/framework/pr_tools/unittests/supporting_files/supported-systems.ini @@ -0,0 +1,2 @@ +[rhel7] +.* diff --git a/packages/framework/pr_tools/unittests/test_LaunchDriver.py b/packages/framework/pr_tools/unittests/test_LaunchDriver.py new file mode 100755 index 000000000000..8069efbd306c --- /dev/null +++ b/packages/framework/pr_tools/unittests/test_LaunchDriver.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# -*- mode: python; py-indent-offset: 4; py-continuation-offset: 4 -*- +''' +Tests for LaunchDriver +''' +from __future__ import print_function +import sys +sys.dont_write_bytecode = True + +import os +sys.path.insert(1, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +import unittest + +import LaunchDriver as ld + + + +class Test_LaunchDriver(unittest.TestCase): + def setUp(self): + pr_tools_path = os.path.dirname(os.path.realpath(__file__)) + self.build_name = "rhel7_stack0" + args = ["--supported-systems="+pr_tools_path+"/supporting_files/supported-systems.ini", "--build-name="+self.build_name] + self.args0 = args + ["--driver="+pr_tools_path+"/DriverTest0.sh"] + self.args1 = args + ["--driver="+pr_tools_path+"/DriverTest1.sh"] + + + ## Test LaunchDriver methods + def testUnitGetLaunchEnv(self): + env = ld.get_launch_env(self.build_name, "weaver") + self.assertEqual(env, "env Trilinos_CTEST_DO_ALL_AT_ONCE=TRUE ") + + env = ld.get_launch_env(self.build_name, "ats2") + self.assertEqual(env, "env Trilinos_CTEST_DO_ALL_AT_ONCE=TRUE ") + + env = ld.get_launch_env(self.build_name+"_rdc", "weaver") + self.assertEqual(env, "env TRILINOS_MAX_CORES=10 Trilinos_CTEST_DO_ALL_AT_ONCE=TRUE ") + + env = ld.get_launch_env(self.build_name, "dne") + self.assertEqual(env, "") + + + def testUnitGetLaunchCmd(self): + cmd = ld.get_launch_cmd(self.build_name, "weaver") + self.assertEqual(cmd, "bsub -Is -J " + self.build_name + " -W 12:00 ") + + cmd = ld.get_launch_cmd(self.build_name, "ats2") + self.assertEqual(cmd, "bsub -Is -J " + self.build_name + " -W 12:00 ") + + cmd = ld.get_launch_cmd(self.build_name, "dne") + self.assertEqual(cmd, " ") + + + def testUnitGetDriverArgs(self): + args = ld.get_driver_args("ats2") + self.assertEqual(args, " --on_ats2") + + args = ld.get_driver_args("dne1") + self.assertEqual(args, " --on_dne1") + + + ## Test LaunchDriver main + def testIntegration0(self): + with self.assertRaises(SystemExit) as se: + ld.main(self.args0) + self.assertEqual(se.exception.code, 0) + + + def testIntegration1(self): + with self.assertRaises(SystemExit) as se: + ld.main(self.args1) + self.assertEqual(se.exception.code, 1) + + +if __name__ == '__main__': + unittest.main() # pragma nocover From 7407ca62f8089776170896c792d591767ff5b3fe Mon Sep 17 00:00:00 2001 From: Brian Kelley Date: Mon, 14 Mar 2022 17:02:55 -0600 Subject: [PATCH 022/147] Tpetra: fix Vector_offsetViewCtor test (#8309). Just a few minor changes were needed to make it build and pass on Serial and Cuda, with and without MPI. --- .../core/test/MultiVector/CMakeLists.txt | 20 ++++++-------- .../MultiVector/Vector_offsetViewCtor.cpp | 27 +++++++++---------- 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/packages/tpetra/core/test/MultiVector/CMakeLists.txt b/packages/tpetra/core/test/MultiVector/CMakeLists.txt index ad0957fbcb11..bf7b213065bc 100644 --- a/packages/tpetra/core/test/MultiVector/CMakeLists.txt +++ b/packages/tpetra/core/test/MultiVector/CMakeLists.txt @@ -200,18 +200,14 @@ TRIBITS_ADD_EXECUTABLE_AND_TEST( STANDARD_PASS_OUTPUT ) -# mfh 14 Apr 2019: Weirdly, this unit test was set to build the wrong -# file. When I fixed that, it turns out that the unit test didn't -# build correctly. We will fix that later. -# -#TRIBITS_ADD_EXECUTABLE_AND_TEST( -# Vector_offsetViewCtor -# SOURCES -# Vector_offsetViewCtor -# ${TEUCHOS_STD_UNIT_TEST_MAIN} -# COMM serial mpi -# STANDARD_PASS_OUTPUT -# ) +TRIBITS_ADD_EXECUTABLE_AND_TEST( + Vector_offsetViewCtor + SOURCES + Vector_offsetViewCtor + ${TEUCHOS_STD_UNIT_TEST_MAIN} + COMM serial mpi + STANDARD_PASS_OUTPUT + ) TRIBITS_ADD_EXECUTABLE_AND_TEST( aliased_deep_copy diff --git a/packages/tpetra/core/test/MultiVector/Vector_offsetViewCtor.cpp b/packages/tpetra/core/test/MultiVector/Vector_offsetViewCtor.cpp index 269e4e1944c9..8f09e4e2d9ee 100644 --- a/packages/tpetra/core/test/MultiVector/Vector_offsetViewCtor.cpp +++ b/packages/tpetra/core/test/MultiVector/Vector_offsetViewCtor.cpp @@ -60,18 +60,19 @@ namespace { // (anonymous) template void restoreVectorEntries (VectorType& x) { - using vector_type = VectorType; - using LO = typename vector_type::local_ordinal_type; + using LO = typename VectorType::local_ordinal_type; auto x_lcl_d_2d = x.getLocalViewDevice(Tpetra::Access::ReadWrite); auto x_lcl_d = Kokkos::subview (x_lcl_d_2d, Kokkos::ALL (), 0); - using execution_space = typename vector_type::execution_space; + using execution_space = typename VectorType::execution_space; using range_type = Kokkos::RangePolicy; + using IST = typename VectorType::impl_scalar_type; + auto lclNumRows = x.getLocalLength(); Kokkos::parallel_for ("Initial Vector fill", range_type (0, lclNumRows), KOKKOS_LAMBDA (const LO lclRow) { - x_lcl_d(lclRow) = toScalar (lclRow+1); + x_lcl_d(lclRow) = toScalar (lclRow); }); execution_space().fence (); } @@ -83,12 +84,10 @@ namespace { // (anonymous) VectorType& x_offset, const typename VectorType::local_ordinal_type rowOffset) { - using vector_type = VectorType; - using LO = typename vector_type::local_ordinal_type; + using LO = typename VectorType::local_ordinal_type; + using IST = typename VectorType::impl_scalar_type; - TEST_ASSERT( ! x_offset.need_sync_host () ); - - auto x_lcl_h_2d = x_offset.getLocalViewHost(Tpetra::Access::ReadWrite); + auto x_lcl_h_2d = x_offset.getLocalViewHost(Tpetra::Access::ReadOnly); auto x_lcl_h = Kokkos::subview (x_lcl_h_2d, Kokkos::ALL (), 0); const LO newLclNumRows = static_cast (x_offset.getLocalLength ()); @@ -130,7 +129,7 @@ namespace { // (anonymous) std::vector myGblRowInds (lclNumRows); for (LO lclRow = 0; lclRow < lclNumRows; ++lclRow) { - myGblRowInds = originalMap->getGlobalElement (lclRow); + myGblRowInds[lclRow] = originalMap->getGlobalElement (lclRow); } const GST INV = Teuchos::OrdinalTraits::invalid (); @@ -140,9 +139,9 @@ namespace { // (anonymous) RCP map_offset = rcp (new map_type (INV, myGblRowInds.data () + rowOffset, newLclNumRows, newIndexBase, comm)); - vector_type x_offset (x, map_offset); + vector_type x_offset (x, map_offset, rowOffset); - const bool expectedMap = map_offset->isSameAs (* (x_offset->getMap ())); + const bool expectedMap = map_offset->isSameAs (* (x_offset.getMap ())); TEST_ASSERT( expectedMap ); TEST_EQUALITY( static_cast (x_offset.getLocalLength ()), newLclNumRows ); @@ -162,7 +161,7 @@ namespace { // (anonymous) // That is, is the new Vector a view of the original Vector? { x.putScalar (Teuchos::ScalarTraits::one ()); - auto x_offset_lcl_h_2d = x_offset.getLocalViewDevice(Tpetra::Access::ReadWrite); + auto x_offset_lcl_h_2d = x_offset.getLocalViewHost(Tpetra::Access::ReadWrite); auto x_offset_lcl_h = Kokkos::subview (x_offset_lcl_h_2d, Kokkos::ALL (), 0); for (LO newLclRow = 0; newLclRow < newLclNumRows; ++newLclRow) { @@ -187,7 +186,7 @@ namespace { // (anonymous) // #define UNIT_TEST_GROUP( SCALAR, LO, GO, NODE ) \ - TEUCHOS_UNIT_TEST_TEMPLATE_4_INSTANT( Vector, OffsetViewCtor, ST, LO, GO, NT ) + TEUCHOS_UNIT_TEST_TEMPLATE_4_INSTANT( Vector, OffsetViewCtor, SCALAR, LO, GO, NODE ) TPETRA_ETI_MANGLING_TYPEDEFS() From 90a0ad88e0de2352b4b72c949e3c7acc17451dcb Mon Sep 17 00:00:00 2001 From: Kyungjoo Kim Date: Mon, 14 Mar 2022 18:24:06 -0600 Subject: [PATCH 023/147] Intrepid2 - working version --- .../Projection/Intrepid2_ProjectionTools.hpp | 286 ++++++++++++------ 1 file changed, 192 insertions(+), 94 deletions(-) diff --git a/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp b/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp index 8becabc1fe5c..d3b19e5eb445 100644 --- a/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp +++ b/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp @@ -648,10 +648,10 @@ class ProjectionTools { void solve(ViewType1 basisCoeffs, ViewType2 elemMat, ViewType2 elemRhs, ViewType2 tau, ViewType3 w,const ViewType4 elemDof, ordinal_type n, ordinal_type m=0) { #ifdef HAVE_INTREPID2_KOKKOSKERNELS - solveParallel(basisCoeffs, elemMat, elemRhs, tau, + solveDevice(basisCoeffs, elemMat, elemRhs, tau, w, elemDof, n, m); #else - solveSerial(basisCoeffs, elemMat, elemRhs, tau, + solveHost(basisCoeffs, elemMat, elemRhs, tau, w, elemDof, n, m); #endif @@ -661,7 +661,7 @@ class ProjectionTools { */ #ifdef HAVE_INTREPID2_KOKKOSKERNELS template - void solveParallel(ViewType1 basisCoeffs, ViewType2 elemMat, ViewType2 elemRhs, ViewType2 taul, + void solveDevice(ViewType1 basisCoeffs, ViewType2 elemMat, ViewType2 elemRhs, ViewType2 taul, ViewType3 work,const ViewType4 elemDof, ordinal_type n, ordinal_type m) { using HostDeviceType = Kokkos::Device; @@ -770,104 +770,202 @@ class ProjectionTools { */ template - void solveSerial(ViewType1 basisCoeffs, ViewType2 elemMat, ViewType2 elemRhs, ViewType2 , - ViewType3, const ViewType4 elemDof, ordinal_type n, ordinal_type m) { - using valueType = typename ViewType2::value_type; - using HostDeviceType = Kokkos::Device; - - Kokkos::View - serialElemMat("serialElemMat", n+m, n+m); - Teuchos::LAPACK lapack_; - ordinal_type numCells = basisCoeffs.extent(0); - - if(matrixIndependentOfCell_) { - ViewType2 elemRhsTrans("transRhs", elemRhs.extent(1), elemRhs.extent(0)); - Kokkos::View - pivVec("pivVec", m+n + std::max(m+n, numCells), 1); - - Kokkos::View serialElemRhs("serialElemRhs", n+m, numCells); - - Kokkos::DynRankView A_host("A0_host", elemMat.extent(1),elemMat.extent(2)); - auto A_device = Kokkos::create_mirror_view(typename DeviceType::memory_space(), A_host); - Kokkos::deep_copy(A_device, Kokkos::subview(elemMat, 0, Kokkos::ALL(), Kokkos::ALL())); - Kokkos::deep_copy(A_host, A_device); - - auto b = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), elemRhs); - - auto serialBasisCoeffs = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), basisCoeffs); - - for(ordinal_type i=0; i; + using vector_host_type = Kokkos::View; + using scratch_host_type = Kokkos::View; + using matrix_host_type = Kokkos::View; + using matrix_device_type = Kokkos::View; + using view_rank_2d_host_type = Kokkos::View; + using do_not_init_tag = Kokkos::ViewAllocateWithoutInitializing; + using host_policy_type = Kokkos::TeamPolicy; + + /// const values + const ordinal_type numCells = basisCoeffs.extent(0); + const ordinal_type numRows = m+n, numCols = n; + + /// capture without this pointer + Teuchos::LAPACK lapack; + + /// mirror view to host + auto elemRhs_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemRhs); + auto elemDof_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemDof); + auto elemMat_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemMat); + + if (matrixIndependentOfCell_) { + /// invert the first matrix and apply for all + matrix_host_type A(do_not_init_tag("A"), numRows, numRows); + { + for (ordinal_type j=0;j(0, numCells), [=](const ordinal_type &ic) { + for (ordinal_type i=0;i(0, numCells), [=](const ordinal_type &ic) { + for (ordinal_type i=0;i pivVec("pivVec", 2*(m+n), 1); - Kokkos::View serialElemRhs("serialElemRhs", n+m, 1 ); - for (ordinal_type ic = 0; ic < numCells; ic++) { - auto A = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), - Kokkos::subview(elemMat, ic, Kokkos::ALL(), Kokkos::ALL())); - auto b = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), - Kokkos::subview(elemRhs, ic, Kokkos::ALL())); - auto basisCoeffs_ = Kokkos::subview(basisCoeffs, ic, Kokkos::ALL()); - auto serialBasisCoeffs = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), - basisCoeffs_); - - Kokkos::deep_copy(serialElemMat,valueType(0)); //LAPACK might overwrite the matrix - - for(ordinal_type i=0; i>> ERROR (Intrepid::ProjectionTools::getBasisCoeffs): " - << "LAPACK return with error code: " - << info; - INTREPID2_TEST_FOR_EXCEPTION( true, std::runtime_error, ss.str().c_str() ); - } + // /// invert the first matrix and apply for all + // matrix_host_type A(do_not_init_tag("A"), numRows, numRows); + // vector_host_type tau(do_not_init_tag("tau"), numCols); + + // auto A_device = Kokkos::create_mirror_view(typename device_type::memory_space(), A); + // Kokkos::deep_copy(A_device, Kokkos::subview(elemMat, 0, Kokkos::ALL(), Kokkos::ALL())); + // Kokkos::deep_copy(A, A_device); + + // { + // for (ordinal_type j=0;j 0; + + // const ordinal_type level(0); + // host_policy_type policy(numChunks + isChunkRemaind, 1, 1); + + // const ordinal_type per_team_extent = numRows*chunkSize + std::max(numCols,2); + // const ordinal_type per_team_scratch = scratch_host_type::shmem_size(per_team_extent); + // policy.set_scratch_size(level, Kokkos::PerTeam(per_team_scratch)); + + // Kokkos::parallel_for + // ("ProjectionTools::solveHost::matrixIndependentOfCell::true", + // policy, [=](const typename host_policy_type::member_type& member) { + // const ordinal_type lrank = member.league_rank(); + // const ordinal_type + // icbeg = lrank*chunkSize, + // ictemp = icbeg+chunkSize, + // icend = (ictemp < numCells ? ictemp : numCells), + // icrange = icend - icbeg; + // scratch_host_type scratch(member.team_scratch(level), per_team_extent); + // value_type * sptr = scratch.data(); + + // matrix_host_type C(sptr, numRows, icrange); sptr += C.span(); + // for (ordinal_type ic=0;ic Date: Mon, 14 Mar 2022 22:43:57 -0600 Subject: [PATCH 024/147] Intrepid2 - little bit improvement on projection tools util --- .../Projection/Intrepid2_ProjectionTools.hpp | 168 +++++++----------- 1 file changed, 62 insertions(+), 106 deletions(-) diff --git a/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp b/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp index d3b19e5eb445..16c830a88bae 100644 --- a/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp +++ b/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp @@ -783,7 +783,8 @@ class ProjectionTools { using matrix_device_type = Kokkos::View; using view_rank_2d_host_type = Kokkos::View; using do_not_init_tag = Kokkos::ViewAllocateWithoutInitializing; - using host_policy_type = Kokkos::TeamPolicy; + using host_team_policy_type = Kokkos::TeamPolicy; + using host_range_policy_type = Kokkos::RangePolicy; /// const values const ordinal_type numCells = basisCoeffs.extent(0); @@ -796,6 +797,7 @@ class ProjectionTools { auto elemRhs_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemRhs); auto elemDof_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemDof); auto elemMat_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemMat); + auto basisCoeffs_host = Kokkos::create_mirror_view(basisCoeffs); if (matrixIndependentOfCell_) { /// invert the first matrix and apply for all @@ -809,123 +811,78 @@ class ProjectionTools { for (ordinal_type i=numCols;i(0, numCells), [=](const ordinal_type &ic) { + ("ProjectionTools::solveHost::matrixIndependentOfCell::pack", + policy, [=](const ordinal_type & ic) { for (ordinal_type i=0;i(0, numCells), [=](const ordinal_type &ic) { - for (ordinal_type i=0;i 0; - - // const ordinal_type level(0); - // host_policy_type policy(numChunks + isChunkRemaind, 1, 1); - - // const ordinal_type per_team_extent = numRows*chunkSize + std::max(numCols,2); - // const ordinal_type per_team_scratch = scratch_host_type::shmem_size(per_team_extent); - // policy.set_scratch_size(level, Kokkos::PerTeam(per_team_scratch)); - - // Kokkos::parallel_for - // ("ProjectionTools::solveHost::matrixIndependentOfCell::true", - // policy, [=](const typename host_policy_type::member_type& member) { - // const ordinal_type lrank = member.league_rank(); - // const ordinal_type - // icbeg = lrank*chunkSize, - // ictemp = icbeg+chunkSize, - // icend = (ictemp < numCells ? ictemp : numCells), - // icrange = icend - icbeg; - // scratch_host_type scratch(member.team_scratch(level), per_team_extent); - // value_type * sptr = scratch.data(); - - // matrix_host_type C(sptr, numRows, icrange); sptr += C.span(); - // for (ordinal_type ic=0;ic Date: Mon, 14 Mar 2022 23:48:47 -0600 Subject: [PATCH 025/147] Intrepid2 - strided view mirroring --- .../src/Projection/Intrepid2_ProjectionTools.hpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp b/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp index 16c830a88bae..f2a531626265 100644 --- a/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp +++ b/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp @@ -793,9 +793,16 @@ class ProjectionTools { /// capture without this pointer Teuchos::LAPACK lapack; + /// stride view copy + Kokkos::View elemDof_host(do_not_init_tag("elemDof_host"), elemDof.extent(0)); + { + auto elemDof_device = Kokkos::create_mirror_view(typename device_type::memory_space(), elemDof_host); + Kokkos::deep_copy(elemDof_device, elemDof); + Kokkos::deep_copy(elemDof_host, elemDof_device); + } + /// mirror view to host auto elemRhs_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemRhs); - auto elemDof_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemDof); auto elemMat_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemMat); auto basisCoeffs_host = Kokkos::create_mirror_view(basisCoeffs); From 388799647c7451664ccaebd6c1249dc7af5fd8db Mon Sep 17 00:00:00 2001 From: Kyungjoo Kim Date: Tue, 15 Mar 2022 00:53:29 -0600 Subject: [PATCH 026/147] Intrepid2 - enabling projection test on cuda without kokkoskernels --- .../Projection/Intrepid2_ProjectionTools.hpp | 11 ++- .../unit-test/Projection/CMakeLists.txt | 97 +++++++++---------- 2 files changed, 56 insertions(+), 52 deletions(-) diff --git a/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp b/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp index f2a531626265..caf32850a350 100644 --- a/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp +++ b/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp @@ -649,7 +649,7 @@ class ProjectionTools { ViewType3 w,const ViewType4 elemDof, ordinal_type n, ordinal_type m=0) { #ifdef HAVE_INTREPID2_KOKKOSKERNELS solveDevice(basisCoeffs, elemMat, elemRhs, tau, - w, elemDof, n, m); + w, elemDof, n, m); #else solveHost(basisCoeffs, elemMat, elemRhs, tau, w, elemDof, n, m); @@ -786,6 +786,9 @@ class ProjectionTools { using host_team_policy_type = Kokkos::TeamPolicy; using host_range_policy_type = Kokkos::RangePolicy; + /// make sure all on-going kernels are done + Kokkos::fence(); + /// const values const ordinal_type numCells = basisCoeffs.extent(0); const ordinal_type numRows = m+n, numCols = n; @@ -797,14 +800,16 @@ class ProjectionTools { Kokkos::View elemDof_host(do_not_init_tag("elemDof_host"), elemDof.extent(0)); { auto elemDof_device = Kokkos::create_mirror_view(typename device_type::memory_space(), elemDof_host); - Kokkos::deep_copy(elemDof_device, elemDof); + Kokkos::deep_copy(elemDof_device, elemDof); Kokkos::fence(); Kokkos::deep_copy(elemDof_host, elemDof_device); } /// mirror view to host auto elemRhs_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemRhs); auto elemMat_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), elemMat); - auto basisCoeffs_host = Kokkos::create_mirror_view(basisCoeffs); + + /// this in-out variable + auto basisCoeffs_host = Kokkos::create_mirror_view_and_copy(host_memory_space(), basisCoeffs); if (matrixIndependentOfCell_) { /// invert the first matrix and apply for all diff --git a/packages/intrepid2/unit-test/Projection/CMakeLists.txt b/packages/intrepid2/unit-test/Projection/CMakeLists.txt index 5b42ca51fa36..2981a9b5bbf2 100644 --- a/packages/intrepid2/unit-test/Projection/CMakeLists.txt +++ b/packages/intrepid2/unit-test/Projection/CMakeLists.txt @@ -70,63 +70,62 @@ IF (${ETI_DEVICE_COUNT} GREATER_EQUAL 0) ENDIF() -IF (Trilinos_ENABLE_KokkosKernels) - SET(Intrepid2_TEST_ETI_FILE "") - LIST(APPEND Intrepid2_TEST_ETI_FILE - "test_convergence_HEX" - "test_convergence_QUAD" - "test_convergence_TET" - "test_convergence_TRI" - "test_interpolation_projection_HEX" - "test_interpolation_projection_QUAD" - "test_interpolation_projection_TET" - "test_interpolation_projection_TRI" - ) +SET(Intrepid2_TEST_ETI_FILE "") +LIST(APPEND Intrepid2_TEST_ETI_FILE + "test_convergence_HEX" + "test_convergence_QUAD" + "test_convergence_TET" + "test_convergence_TRI" + "test_interpolation_projection_HEX" + "test_interpolation_projection_QUAD" + "test_interpolation_projection_TET" + "test_interpolation_projection_TRI" +) - SET(Intrepid2_TEST_ETI_DEVICE_NAME "") - SET(Intrepid2_TEST_ETI_DEVICE "") +SET(Intrepid2_TEST_ETI_DEVICE_NAME "") +SET(Intrepid2_TEST_ETI_DEVICE "") - IF(Kokkos_ENABLE_CUDA) - LIST(APPEND Intrepid2_TEST_ETI_DEVICE_NAME "CUDA") - LIST(APPEND Intrepid2_TEST_ETI_DEVICE "Kokkos::Device") - ENDIF() - IF(Kokkos_ENABLE_HIP) - LIST(APPEND Intrepid2_TEST_ETI_DEVICE_NAME "HIP") - LIST(APPEND Intrepid2_TEST_ETI_DEVICE "Kokkos::Device") - ENDIF() +IF(Kokkos_ENABLE_CUDA) + LIST(APPEND Intrepid2_TEST_ETI_DEVICE_NAME "CUDA") + LIST(APPEND Intrepid2_TEST_ETI_DEVICE "Kokkos::Device") +ENDIF() +IF(Kokkos_ENABLE_HIP) + LIST(APPEND Intrepid2_TEST_ETI_DEVICE_NAME "HIP") + LIST(APPEND Intrepid2_TEST_ETI_DEVICE "Kokkos::Device") +ENDIF() - LIST(LENGTH Intrepid2_TEST_ETI_DEVICE_NAME ETI_DEVICE_COUNT) - MATH(EXPR ETI_DEVICE_COUNT "${ETI_DEVICE_COUNT}-1") +LIST(LENGTH Intrepid2_TEST_ETI_DEVICE_NAME ETI_DEVICE_COUNT) +MATH(EXPR ETI_DEVICE_COUNT "${ETI_DEVICE_COUNT}-1") + +IF (${ETI_DEVICE_COUNT} GREATER_EQUAL 0) + FOREACH(I RANGE ${ETI_DEVICE_COUNT}) + LIST(GET Intrepid2_TEST_ETI_DEVICE_NAME ${I} ETI_DEVICE_NAME) + LIST(GET Intrepid2_TEST_ETI_DEVICE ${I} ETI_DEVICE) + #MESSAGE(STATUS "Generating TEST ProjectionTools for ${ETI_DEVICE_NAME} with ${ETI_DEVICE}") + FOREACH(J RANGE ${ETI_VALUETYPE_COUNT}) + LIST(GET Intrepid2_TEST_ETI_VALUETYPE_NAME ${J} ETI_VALUETYPE_NAME) + LIST(GET Intrepid2_TEST_ETI_VALUETYPE ${J} ETI_VALUETYPE) + LIST(GET Intrepid2_TEST_ETI_SACADO ${J} ETI_SACADO) + FOREACH(ETI_FILE IN LISTS Intrepid2_TEST_ETI_FILE) + SET(ETI_NAME "${ETI_FILE}_${ETI_DEVICE_NAME}_${ETI_VALUETYPE_NAME}") + MESSAGE(STATUS "Generating TEST: ProjectionTools ${ETI_NAME}.cpp") + CONFIGURE_FILE(eti/${ETI_FILE}_ETI.in ${ETI_NAME}.cpp) + + TRIBITS_ADD_EXECUTABLE_AND_TEST( + ${ETI_NAME} + SOURCES ${ETI_NAME}.cpp + ARGS PrintItAll + NUM_MPI_PROCS 1 + PASS_REGULAR_EXPRESSION "TEST PASSED" + ADD_DIR_TO_NAME + ) - IF (${ETI_DEVICE_COUNT} GREATER_EQUAL 0) - FOREACH(I RANGE ${ETI_DEVICE_COUNT}) - LIST(GET Intrepid2_TEST_ETI_DEVICE_NAME ${I} ETI_DEVICE_NAME) - LIST(GET Intrepid2_TEST_ETI_DEVICE ${I} ETI_DEVICE) - #MESSAGE(STATUS "Generating TEST ProjectionTools for ${ETI_DEVICE_NAME} with ${ETI_DEVICE}") - FOREACH(J RANGE ${ETI_VALUETYPE_COUNT}) - LIST(GET Intrepid2_TEST_ETI_VALUETYPE_NAME ${J} ETI_VALUETYPE_NAME) - LIST(GET Intrepid2_TEST_ETI_VALUETYPE ${J} ETI_VALUETYPE) - LIST(GET Intrepid2_TEST_ETI_SACADO ${J} ETI_SACADO) - FOREACH(ETI_FILE IN LISTS Intrepid2_TEST_ETI_FILE) - SET(ETI_NAME "${ETI_FILE}_${ETI_DEVICE_NAME}_${ETI_VALUETYPE_NAME}") - MESSAGE(STATUS "Generating TEST: ProjectionTools ${ETI_NAME}.cpp") - CONFIGURE_FILE(eti/${ETI_FILE}_ETI.in ${ETI_NAME}.cpp) - - TRIBITS_ADD_EXECUTABLE_AND_TEST( - ${ETI_NAME} - SOURCES ${ETI_NAME}.cpp - ARGS PrintItAll - NUM_MPI_PROCS 1 - PASS_REGULAR_EXPRESSION "TEST PASSED" - ADD_DIR_TO_NAME - ) - - ENDFOREACH() ENDFOREACH() ENDFOREACH() - ENDIF() + ENDFOREACH() ENDIF() + # Device test: Mauro, please fix uvm requirement in projection tools when it goes into serial path # uvm removal from projection tools is not done yet # This test is incomplete and it does not use a device type. Temporarily we From 5c13bdd48a43b37493d4f2fa0061ec50986c8066 Mon Sep 17 00:00:00 2001 From: Christian Glusa Date: Mon, 14 Mar 2022 16:03:30 -0600 Subject: [PATCH 027/147] Xpetra: Add unit test for matrix reader with missing rows --- packages/xpetra/test/CMakeLists.txt | 1 + packages/xpetra/test/IO/CMakeLists.txt | 14 ++ packages/xpetra/test/IO/IO_UnitTests.cpp | 180 +++++++++++++++++++++++ packages/xpetra/test/IO/test.mtx | 6 + packages/xpetra/test/IO/test.mtx.bin | Bin 0 -> 88 bytes 5 files changed, 201 insertions(+) create mode 100644 packages/xpetra/test/IO/CMakeLists.txt create mode 100644 packages/xpetra/test/IO/IO_UnitTests.cpp create mode 100644 packages/xpetra/test/IO/test.mtx create mode 100644 packages/xpetra/test/IO/test.mtx.bin diff --git a/packages/xpetra/test/CMakeLists.txt b/packages/xpetra/test/CMakeLists.txt index 1867da629ee2..1a7523051f88 100644 --- a/packages/xpetra/test/CMakeLists.txt +++ b/packages/xpetra/test/CMakeLists.txt @@ -16,6 +16,7 @@ ADD_SUBDIRECTORIES( CrsMatrix # Tests specifically written for Xpetra: + IO Matrix MatrixMatrix MatrixUtils diff --git a/packages/xpetra/test/IO/CMakeLists.txt b/packages/xpetra/test/IO/CMakeLists.txt new file mode 100644 index 000000000000..5829d8b511b5 --- /dev/null +++ b/packages/xpetra/test/IO/CMakeLists.txt @@ -0,0 +1,14 @@ + +TRIBITS_ADD_EXECUTABLE_AND_TEST( + IO_UnitTests + SOURCES + IO_UnitTests.cpp + ../Xpetra_UnitTests.cpp + COMM mpi + NUM_MPI_PROCS 1 + STANDARD_PASS_OUTPUT + ) + +TRIBITS_COPY_FILES_TO_BINARY_DIR(UnitTestsIO_cp + SOURCE_FILES test.mtx test.mtx.bin +) diff --git a/packages/xpetra/test/IO/IO_UnitTests.cpp b/packages/xpetra/test/IO/IO_UnitTests.cpp new file mode 100644 index 000000000000..f45947d0e7f6 --- /dev/null +++ b/packages/xpetra/test/IO/IO_UnitTests.cpp @@ -0,0 +1,180 @@ +// @HEADER +// +// *********************************************************************** +// +// Xpetra: A linear algebra interface package +// Copyright 2012 Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact +// Jonathan Hu (jhu@sandia.gov) +// Andrey Prokopenko (aprokop@sandia.gov) +// Ray Tuminaro (rstumin@sandia.gov) +// +// *********************************************************************** +// +// @HEADER +#include +#include +#include +#include "Xpetra_ConfigDefs.hpp" +#include "Xpetra_DefaultPlatform.hpp" +#include + + +namespace { + + TEUCHOS_UNIT_TEST_TEMPLATE_6_DECL( IO, MMMissingRows, M, MA, Scalar, LO, GO, Node ) + { + + // get a comm and node + Teuchos::RCP > comm = Xpetra::DefaultPlatform::getDefaultPlatform().getComm(); + TEUCHOS_ASSERT_EQUALITY(comm->getSize(), 1); + + if (Teuchos::ScalarTraits::isComplex) + return; + + M testMap(1,0,comm); + Xpetra::UnderlyingLib lib = testMap.lib(); + + auto A = Xpetra::IO::Read("test.mtx", lib, comm, false); + TEUCHOS_ASSERT_EQUALITY(A->getGlobalNumRows(), 5); + TEUCHOS_ASSERT_EQUALITY(A->getGlobalNumCols(), 5); + TEUCHOS_ASSERT_EQUALITY(A->getGlobalNumEntries(), 3); + + auto colmap = A->getColMap(); + auto crsA = Teuchos::rcp_dynamic_cast >(A, true)->getCrsMatrix(); + Teuchos::ArrayView< const LO > indices; + Teuchos::ArrayView< const Scalar > values; + crsA->getLocalRowView(0, indices, values); + TEST_EQUALITY(indices.size(), 2); + TEST_EQUALITY(colmap->getGlobalElement(indices[0]), 0); + TEST_EQUALITY(colmap->getGlobalElement(indices[1]), 3); + TEST_EQUALITY(values[0], 2.); + TEST_EQUALITY(values[1], 3.); + + crsA->getLocalRowView(1, indices, values); + TEST_EQUALITY(indices.size(), 1); + TEST_EQUALITY(colmap->getGlobalElement(indices[0]), 4); + TEST_EQUALITY(values[0], 4.); + + } + + TEUCHOS_UNIT_TEST_TEMPLATE_6_DECL( IO, BinaryMissingRows, M, MA, Scalar, LO, GO, Node ) + { + + // get a comm and node + Teuchos::RCP > comm = Xpetra::DefaultPlatform::getDefaultPlatform().getComm(); + TEUCHOS_ASSERT_EQUALITY(comm->getSize(), 1); + + M testMap(1,0,comm); + Xpetra::UnderlyingLib lib = testMap.lib(); + + auto A = Xpetra::IO::Read("test.mtx.bin", lib, comm, true); + TEUCHOS_ASSERT_EQUALITY(A->getGlobalNumRows(), 5); + TEUCHOS_ASSERT_EQUALITY(A->getGlobalNumCols(), 5); + TEUCHOS_ASSERT_EQUALITY(A->getGlobalNumEntries(), 3); + + auto colmap = A->getColMap(); + auto crsA = Teuchos::rcp_dynamic_cast >(A, true)->getCrsMatrix(); + Teuchos::ArrayView< const LO > indices; + Teuchos::ArrayView< const Scalar > values; + crsA->getLocalRowView(0, indices, values); + TEST_EQUALITY(indices.size(), 2); + TEST_EQUALITY(colmap->getGlobalElement(indices[0]), 0); + TEST_EQUALITY(colmap->getGlobalElement(indices[1]), 3); + TEST_EQUALITY(values[0], 2.); + TEST_EQUALITY(values[1], 3.); + + crsA->getLocalRowView(1, indices, values); + TEST_EQUALITY(indices.size(), 1); + TEST_EQUALITY(colmap->getGlobalElement(indices[0]), 4); + TEST_EQUALITY(values[0], 4.); + + } + + +// +// INSTANTIATIONS +// +#ifdef HAVE_XPETRA_TPETRA + + #define XPETRA_TPETRA_TYPES( S, LO, GO, N) \ + typedef typename Xpetra::TpetraMap M##LO##GO##N; \ + typedef typename Xpetra::TpetraCrsMatrix MA##S##LO##GO##N; + +#endif + +#ifdef HAVE_XPETRA_EPETRA + + #define XPETRA_EPETRA_TYPES( S, LO, GO, N) \ + typedef typename Xpetra::EpetraMapT M##LO##GO##N; \ + typedef typename Xpetra::EpetraCrsMatrixT MA##S##LO##GO##N; + +#endif + + + //list of all tests which run both with Epetra and Tpetra +#define XP_IO_INSTANT(S,LO,GO,N) \ + TEUCHOS_UNIT_TEST_TEMPLATE_6_INSTANT( IO, MMMissingRows, M##LO##GO##N , MA##S##LO##GO##N, S, LO, GO, N ) \ + TEUCHOS_UNIT_TEST_TEMPLATE_6_INSTANT( IO, BinaryMissingRows, M##LO##GO##N , MA##S##LO##GO##N, S, LO, GO, N ) + + +#if defined(HAVE_XPETRA_TPETRA) + +#include +#include + +TPETRA_ETI_MANGLING_TYPEDEFS() +TPETRA_INSTANTIATE_SLGN_NO_ORDINAL_SCALAR ( XPETRA_TPETRA_TYPES ) +TPETRA_INSTANTIATE_SLGN_NO_ORDINAL_SCALAR ( XP_IO_INSTANT ) + +#endif + + +#if defined(HAVE_XPETRA_EPETRA) + +#include "Xpetra_Map.hpp" // defines EpetraNode +typedef Xpetra::EpetraNode EpetraNode; +#ifndef XPETRA_EPETRA_NO_32BIT_GLOBAL_INDICES +XPETRA_EPETRA_TYPES(double,int,int,EpetraNode) +XP_IO_INSTANT(double,int,int,EpetraNode) +#endif +#ifndef XPETRA_EPETRA_NO_64BIT_GLOBAL_INDICES +typedef long long LongLong; +XPETRA_EPETRA_TYPES(double,int,LongLong,EpetraNode) +XP_IO_INSTANT(double,int,LongLong,EpetraNode) +#endif + +#endif + +} diff --git a/packages/xpetra/test/IO/test.mtx b/packages/xpetra/test/IO/test.mtx new file mode 100644 index 000000000000..3003948ee0df --- /dev/null +++ b/packages/xpetra/test/IO/test.mtx @@ -0,0 +1,6 @@ +%%MatrixMarket matrix coordinate real general +% +5 5 3 +1 1 2.000000000000000e+00 +1 4 3.000000000000000e+00 +2 5 4.000000000000000e+00 \ No newline at end of file diff --git a/packages/xpetra/test/IO/test.mtx.bin b/packages/xpetra/test/IO/test.mtx.bin new file mode 100644 index 0000000000000000000000000000000000000000..db6c80f1d116bbe1fc333c4edd1d104d3fd120bd GIT binary patch literal 88 rcmZQ&U|?VcVrC!)0VW6q=L5M85Fri+Mj!)(Ss(&HQosRSJxmS&DJTH? literal 0 HcmV?d00001 From cc51e85d595e3a852e8a60fb61d09b19096029b9 Mon Sep 17 00:00:00 2001 From: Christian Glusa Date: Mon, 14 Mar 2022 16:03:59 -0600 Subject: [PATCH 028/147] MueLu: Fix MM->binary converter for case with missing rows --- packages/muelu/utils/matrix/ascii2binary.cpp | 28 +++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/packages/muelu/utils/matrix/ascii2binary.cpp b/packages/muelu/utils/matrix/ascii2binary.cpp index f38deaee03d0..436bfcfe9c59 100644 --- a/packages/muelu/utils/matrix/ascii2binary.cpp +++ b/packages/muelu/utils/matrix/ascii2binary.cpp @@ -4,6 +4,7 @@ #include #include #include +#include using namespace std; int main(int argc, char* argv[]) { @@ -44,10 +45,13 @@ int main(int argc, char* argv[]) { double v; vector inds; vector vals; + vector writtenRows(m, false); + size_t writtenEntries = 0; + bool done = false; ifs >> i >> j >> v; i--; j--; - while (row != i && ifs.good()) { + while (row != i && !done) { row = i; inds.resize(0); @@ -57,9 +61,14 @@ int main(int argc, char* argv[]) { inds.push_back(j); vals.push_back(v); - ifs >> i >> j >> v; - i--; j--; - } while (row == i && ifs.good()); + if (ifs.good()) { + ifs >> i >> j >> v; + i--; j--; + } else { + i = -1; + done = true; + } + } while (row == i); int rownnz = inds.size(); @@ -67,8 +76,19 @@ int main(int argc, char* argv[]) { ofs.write(reinterpret_cast(&rownnz), sizeof(rownnz)); for (int k = 0; k < rownnz; k++) ofs.write(reinterpret_cast(&inds[0] + k), sizeof(inds[k])); for (int k = 0; k < rownnz; k++) ofs.write(reinterpret_cast(&vals[0] + k), sizeof(vals[k])); + writtenRows[row] = true; + writtenEntries += rownnz; } + assert (writtenEntries == nnz); + + int rownnz = 0; + for (row = 0; row < m; row++) { + if (!writtenRows[row]) { + ofs.write(reinterpret_cast(&row), sizeof(row)); + ofs.write(reinterpret_cast(&rownnz), sizeof(rownnz)); + } + } return 0; } From ed63829d8c2b72ce6aaa96c03fbb2a1e040cf9f4 Mon Sep 17 00:00:00 2001 From: Kyungjoo Kim Date: Tue, 15 Mar 2022 10:02:41 -0600 Subject: [PATCH 029/147] Intrepid2 - minor comment typo --- packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp b/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp index caf32850a350..dd3149df831e 100644 --- a/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp +++ b/packages/intrepid2/src/Projection/Intrepid2_ProjectionTools.hpp @@ -925,7 +925,7 @@ class ProjectionTools { INTREPID2_TEST_FOR_EXCEPTION (info != 0, std::runtime_error, "GELS return non-zero info code"); - /// scater back to system + /// scatter back to system for (ordinal_type i=0;i Date: Tue, 15 Mar 2022 11:02:04 -0600 Subject: [PATCH 030/147] packages/framework: Redirect grep output --- packages/framework/pr_tools/PullRequestLinuxDriver.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/pr_tools/PullRequestLinuxDriver.sh b/packages/framework/pr_tools/PullRequestLinuxDriver.sh index 20d7c38d3218..181bf5ffcdac 100755 --- a/packages/framework/pr_tools/PullRequestLinuxDriver.sh +++ b/packages/framework/pr_tools/PullRequestLinuxDriver.sh @@ -5,8 +5,8 @@ source ${SCRIPTPATH:?}/common.bash # set -x # echo commands # Fetch arguments -on_weaver=$(echo "$@" | grep '\-\-on_weaver' && echo "1") -on_ats2=$(echo "$@" | grep '\-\-on_ats2' && echo "1") +on_weaver=$(echo "$@" | grep '\-\-on_weaver' &> /dev/null && echo "1") +on_ats2=$(echo "$@" | grep '\-\-on_ats2' &> /dev/null && echo "1") # Load the right version of Git / Python based on a regex From 6ad3a2e891a1ded1019236c51627f24c4866db16 Mon Sep 17 00:00:00 2001 From: Kyungjoo Kim Date: Tue, 15 Mar 2022 13:55:13 -0600 Subject: [PATCH 031/147] Tpetra - remove unscoped using Teuchos --- packages/tpetra/core/src/Tpetra_CrsMatrix_def.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/tpetra/core/src/Tpetra_CrsMatrix_def.hpp b/packages/tpetra/core/src/Tpetra_CrsMatrix_def.hpp index 4037de68294e..481f2a0dd9e2 100644 --- a/packages/tpetra/core/src/Tpetra_CrsMatrix_def.hpp +++ b/packages/tpetra/core/src/Tpetra_CrsMatrix_def.hpp @@ -83,8 +83,6 @@ #include #include -using Teuchos::rcpFromRef; - namespace Tpetra { namespace { // (anonymous) From 69efb2197f223b3778b08de9b42fa116599bd320 Mon Sep 17 00:00:00 2001 From: Jacob Domagala Date: Tue, 15 Mar 2022 21:50:44 +0100 Subject: [PATCH 032/147] Panzer: Make Epetra optional --- packages/panzer/core/CMakeLists.txt | 8 ++++++++ packages/panzer/core/cmake/PanzerCore_config.hpp.in | 1 + packages/panzer/disc-fe/cmake/Dependencies.cmake | 4 ++-- packages/panzer/dof-mgr/CMakeLists.txt | 8 -------- packages/panzer/dof-mgr/cmake/PanzerDofMgr_config.hpp.in | 1 - 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/panzer/core/CMakeLists.txt b/packages/panzer/core/CMakeLists.txt index 779209d72c60..5034323914af 100644 --- a/packages/panzer/core/CMakeLists.txt +++ b/packages/panzer/core/CMakeLists.txt @@ -1,5 +1,13 @@ TRIBITS_SUBPACKAGE(Core) +SET(PANZER_HAVE_EPETRA ${${PACKAGE_NAME}_ENABLE_Epetra} ) + +IF(PANZER_HAVE_EPETRA) + MESSAGE(STATUS "Global Indexer Epetra Utilities On") +ELSE() + MESSAGE(STATUS "Global Indexer Epetra Utilities Off") +ENDIF() + ADD_SUBDIRECTORY(src) TRIBITS_ADD_TEST_DIRECTORIES(test) TRIBITS_SUBPACKAGE_POSTPROCESS() diff --git a/packages/panzer/core/cmake/PanzerCore_config.hpp.in b/packages/panzer/core/cmake/PanzerCore_config.hpp.in index 90f52e65fb9e..92d25b463f40 100644 --- a/packages/panzer/core/cmake/PanzerCore_config.hpp.in +++ b/packages/panzer/core/cmake/PanzerCore_config.hpp.in @@ -6,6 +6,7 @@ #endif #cmakedefine HAVE_MPI +#cmakedefine PANZER_HAVE_EPETRA // What AD Type are you going to use? #define PANZER_FADTYPE @Panzer_FADTYPE@ diff --git a/packages/panzer/disc-fe/cmake/Dependencies.cmake b/packages/panzer/disc-fe/cmake/Dependencies.cmake index 5e34bef761c4..92c8aec34089 100644 --- a/packages/panzer/disc-fe/cmake/Dependencies.cmake +++ b/packages/panzer/disc-fe/cmake/Dependencies.cmake @@ -1,5 +1,5 @@ -SET(LIB_REQUIRED_DEP_PACKAGES TeuchosCore TeuchosParameterList TeuchosComm KokkosCore Sacado Phalanx Intrepid2 ThyraCore ThyraTpetraAdapters ThyraEpetraAdapters ThyraEpetraExtAdapters Tpetra Epetra EpetraExt Zoltan PanzerCore PanzerDofMgr) -SET(LIB_OPTIONAL_DEP_PACKAGES) +SET(LIB_REQUIRED_DEP_PACKAGES TeuchosCore TeuchosParameterList TeuchosComm KokkosCore Sacado Phalanx Intrepid2 ThyraCore ThyraTpetraAdapters Tpetra Zoltan PanzerCore PanzerDofMgr) +SET(LIB_OPTIONAL_DEP_PACKAGES ThyraEpetraAdapters ThyraEpetraExtAdapters Epetra EpetraExt) SET(TEST_REQUIRED_DEP_PACKAGES) SET(TEST_OPTIONAL_DEP_PACKAGES) SET(LIB_REQUIRED_DEP_TPLS MPI) diff --git a/packages/panzer/dof-mgr/CMakeLists.txt b/packages/panzer/dof-mgr/CMakeLists.txt index 5f5354ad919f..7aa4021fc407 100644 --- a/packages/panzer/dof-mgr/CMakeLists.txt +++ b/packages/panzer/dof-mgr/CMakeLists.txt @@ -1,13 +1,5 @@ TRIBITS_SUBPACKAGE(DofMgr) -SET(PANZER_HAVE_EPETRA ${${PACKAGE_NAME}_ENABLE_Epetra} ) - -IF(PANZER_HAVE_EPETRA) - MESSAGE(STATUS "Global Indexer Epetra Utilities On") -ELSE() - MESSAGE(STATUS "Global Indexer Epetra Utilities Off") -ENDIF() - ADD_SUBDIRECTORY(src) TRIBITS_ADD_TEST_DIRECTORIES(test) diff --git a/packages/panzer/dof-mgr/cmake/PanzerDofMgr_config.hpp.in b/packages/panzer/dof-mgr/cmake/PanzerDofMgr_config.hpp.in index cf6c353db7b1..9c4bafc6a844 100644 --- a/packages/panzer/dof-mgr/cmake/PanzerDofMgr_config.hpp.in +++ b/packages/panzer/dof-mgr/cmake/PanzerDofMgr_config.hpp.in @@ -2,6 +2,5 @@ #define PANZER_DOF_MGR_CONFIG_HPP #include "PanzerCore_config.hpp" -#cmakedefine PANZER_HAVE_EPETRA #endif From 14513918b305d4d0bb21730ea10aa8479d044f2c Mon Sep 17 00:00:00 2001 From: Chris Siefert Date: Tue, 15 Mar 2022 20:18:53 -0600 Subject: [PATCH 033/147] Cmake: Updates for lightsaber --- .../ctest_linux_experimental_mpi_release_float_lightsaber.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/ctest/drivers/lightsaber/ctest_linux_experimental_mpi_release_float_lightsaber.cmake b/cmake/ctest/drivers/lightsaber/ctest_linux_experimental_mpi_release_float_lightsaber.cmake index b4846ba86f5a..c18fe1980822 100644 --- a/cmake/ctest/drivers/lightsaber/ctest_linux_experimental_mpi_release_float_lightsaber.cmake +++ b/cmake/ctest/drivers/lightsaber/ctest_linux_experimental_mpi_release_float_lightsaber.cmake @@ -76,6 +76,8 @@ SET(Trilinos_PACKAGES MueLu Tpetra) SET(EXTRA_CONFIGURE_OPTIONS + "-DTrilinos_ENABLE_EPETRA=OFF" + "-DTrilinos_ENABLE_EPETRAEXT=OFF" "-DTrilinos_ENABLE_COMPLEX:BOOL=OFF" "-DTrilinos_ENABLE_EXPLICIT_INSTANTIATION=ON" "-DTrilinos_ENABLE_DEPENDENCY_UNIT_TESTS=OFF" From d95c0befd7a6d4dd8a529f02ca396adf5053aa9e Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Thu, 17 Mar 2022 10:15:31 +0100 Subject: [PATCH 034/147] MueLu: drop composite matrix for region solver --- .../research/regionMG/src/SolveRegionHierarchy_def.hpp | 6 +----- .../test/structured/Driver_Structured_Regions.cpp | 10 ++-------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp index 1ebf12f63bfd..fa5bb4f01f6d 100644 --- a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp +++ b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp @@ -347,13 +347,11 @@ void vCycleAdapter(const int numLevels, ///< Total number of levels RCP regB; compositeToRegional(B, quasiRegB, regB, revisedRowMap, rowImport); - // scaleInterfaceDOFs(regB, regInterfaceScalings, true); RCP quasiRegX; RCP regX; compositeToRegional(X, quasiRegX, regX, revisedRowMap, rowImport); - // scaleInterfaceDOFs(regX, regInterfaceScalings, true); vCycle(0, numLevels, cycleType, regHierarchy, regX, regB, @@ -418,7 +416,7 @@ void solveRegionProblem(const double tol, const bool scaleResidualHist, const in } // Print type of residual norm to the screen - out << "using region solver" << std::endl; + out << "Using region solver" << std::endl; if (scaleResidualHist) out << "Using scaled residual norm." << std::endl; else @@ -625,8 +623,6 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co // check for convergence { normRes = Res->norm2(); - - // if(cycle == 0) { normResIni = normRes; }// out << "NormResIni = " << normResIni << std::endl;} if(scaleResidualHist) { normRes /= normResIni; } // Output current residual norm to screen (on proc 0 only) diff --git a/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp b/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp index 704714ce4a93..6eff560ffedc 100644 --- a/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp +++ b/packages/muelu/research/regionMG/test/structured/Driver_Structured_Regions.cpp @@ -431,8 +431,6 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar procsPerDim[2] = galeriList.get("mz"); } - // const LO numLocalCompositeNodes = lNodesPerDim[0]*lNodesPerDim[1]*lNodesPerDim[2]; - // Rule for boundary duplication // For any two ranks that share an interface: // the lowest rank owns the interface and the highest rank gets extra nodes @@ -473,8 +471,6 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar quasiRegionGIDs, quasiRegionCoordGIDs, compositeToRegionLIDs, interfaceGIDs, interfaceLIDsData); - // const LO numSend = static_cast(sendGIDs.size()); - // std::cout << "p=" << myRank << " | numSend=" << numSend << std::endl; // << ", numReceive=" << numReceive << std::endl; // std::cout << "p=" << myRank << " | receiveGIDs: " << receiveGIDs << std::endl; @@ -598,10 +594,8 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib& lib, int ar revisedRowMap, revisedColMap, rowImport, quasiRegionMats, regionMats); - // Actually for now we are keeping it so we can implement - // iterative solvers using composite operator and vectors. - // // We don't need the composite operator on the fine level anymore. Free it! - // A = Teuchos::null; + // If we don't need the composite operator on the fine level anymore, free it! + if(solverType == "region") A = Teuchos::null; comm->barrier(); tmLocal = Teuchos::null; From c0dbf91eff714c7762f76b337c28c50dc2e11679 Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Thu, 17 Mar 2022 10:16:58 +0100 Subject: [PATCH 035/147] MueLu: add tests for region Richardson & CG solver --- .../regionMG/test/structured/CMakeLists.txt | 36 ++++++++++++++- .../Elasticity3D_CG_linear_4.log.gold | 20 ++++++++ .../Elasticity3D_Richardson_linear_4.log.gold | 46 +++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 packages/muelu/research/regionMG/test/structured/gold_files/Elasticity3D_CG_linear_4.log.gold create mode 100644 packages/muelu/research/regionMG/test/structured/gold_files/Elasticity3D_Richardson_linear_4.log.gold diff --git a/packages/muelu/research/regionMG/test/structured/CMakeLists.txt b/packages/muelu/research/regionMG/test/structured/CMakeLists.txt index e3be641b9526..6ca2b8e7d17a 100644 --- a/packages/muelu/research/regionMG/test/structured/CMakeLists.txt +++ b/packages/muelu/research/regionMG/test/structured/CMakeLists.txt @@ -30,6 +30,8 @@ IF (${PACKAGE_NAME}_ENABLE_Tpetra AND ${PACKAGE_NAME}_ENABLE_Amesos2) gold_files/Star2D_GS_4.log.gold gold_files/Brick3D_linear_4.log.gold gold_files/Elasticity3D_linear_4.log.gold + gold_files/Elasticity3D_CG_linear_4.log.gold + gold_files/Elasticity3D_Richardson_linear_4.log.gold ) ## These are some completion tests @@ -316,10 +318,10 @@ IF (${PACKAGE_NAME}_ENABLE_Tpetra AND ${PACKAGE_NAME}_ENABLE_Amesos2) ) TRIBITS_ADD_ADVANCED_TEST( - Structured_Region_Linear_Elasticity3D_Tpetra_MPI_4_regression + Structured_Region_Linear_Elasticity3D_Region_Tpetra_MPI_4_regression TEST_0 EXEC StructuredRegionDriver - ARGS --linAlgebra=Tpetra --xml=structured_linear_3dof.xml --matrixType=Elasticity3D --nx=10 --ny=10 --nz=10 --smootherIts=2 --convergence-log=Elasticity3D_linear_4.log + ARGS --linAlgebra=Tpetra --xml=structured_linear_3dof.xml --matrixType=Elasticity3D --nx=10 --ny=10 --nz=10 --smootherIts=2 --convergence-log=Elasticity3D_linear_4.log --solverType=region NUM_MPI_PROCS 4 TEST_1 CMND ${PYTHON_EXECUTABLE} @@ -330,6 +332,36 @@ IF (${PACKAGE_NAME}_ENABLE_Tpetra AND ${PACKAGE_NAME}_ENABLE_Amesos2) OVERALL_NUM_MPI_PROCS 4 ) + TRIBITS_ADD_ADVANCED_TEST( + Structured_Region_Linear_Elasticity3D_CG_Tpetra_MPI_4_regression + TEST_0 + EXEC StructuredRegionDriver + ARGS --linAlgebra=Tpetra --xml=structured_linear_3dof.xml --matrixType=Elasticity3D --nx=10 --ny=10 --nz=10 --smootherIts=2 --convergence-log=Elasticity3D_CG_linear_4.log --solverType=CG + NUM_MPI_PROCS 4 + TEST_1 + CMND ${PYTHON_EXECUTABLE} + ARGS compare_residual_history.py gold_files/Elasticity3D_CG_linear_4.log.gold Elasticity3D_CG_linear_4.log 1.0e-12 + STANDARD_PASS_OUTPUT + FAIL_FAST + COMM serial mpi + OVERALL_NUM_MPI_PROCS 4 + ) + + TRIBITS_ADD_ADVANCED_TEST( + Structured_Region_Linear_Elasticity3D_Richardson_Tpetra_MPI_4_regression + TEST_0 + EXEC StructuredRegionDriver + ARGS --linAlgebra=Tpetra --xml=structured_linear_3dof.xml --matrixType=Elasticity3D --nx=10 --ny=10 --nz=10 --smootherIts=2 --convergence-log=Elasticity3D_Richardson_linear_4.log --solverType=Richardson + NUM_MPI_PROCS 4 + TEST_1 + CMND ${PYTHON_EXECUTABLE} + ARGS compare_residual_history.py gold_files/Elasticity3D_Richardson_linear_4.log.gold Elasticity3D_Richardson_linear_4.log 1.0e-12 + STANDARD_PASS_OUTPUT + FAIL_FAST + COMM serial mpi + OVERALL_NUM_MPI_PROCS 4 + ) + TRIBITS_ADD_ADVANCED_TEST( Structured_Region_Linear_R_Tpetra_MPI_4_regression TEST_0 diff --git a/packages/muelu/research/regionMG/test/structured/gold_files/Elasticity3D_CG_linear_4.log.gold b/packages/muelu/research/regionMG/test/structured/gold_files/Elasticity3D_CG_linear_4.log.gold new file mode 100644 index 000000000000..c98f26affceb --- /dev/null +++ b/packages/muelu/research/regionMG/test/structured/gold_files/Elasticity3D_CG_linear_4.log.gold @@ -0,0 +1,20 @@ +# num procs = 4 +# iteration | res-norm (scaled=1) +# +0 7.7562458396230716e-02 +1 1.5042331432848836e-02 +2 3.5429084821274517e-03 +3 7.0319968460572763e-04 +4 1.3614723012499763e-04 +5 2.7351638503936538e-05 +6 5.3881611469716398e-06 +7 1.0520505825833551e-06 +8 2.2035320974240088e-07 +9 5.3938853793851441e-08 +10 1.1824150564972177e-08 +11 2.4149453344927425e-09 +12 5.0940666709936447e-10 +13 9.3435476728453209e-11 +14 1.5823994445414205e-11 +15 3.2602543152475955e-12 +16 7.8934225511277149e-13 diff --git a/packages/muelu/research/regionMG/test/structured/gold_files/Elasticity3D_Richardson_linear_4.log.gold b/packages/muelu/research/regionMG/test/structured/gold_files/Elasticity3D_Richardson_linear_4.log.gold new file mode 100644 index 000000000000..1e51ff1a3453 --- /dev/null +++ b/packages/muelu/research/regionMG/test/structured/gold_files/Elasticity3D_Richardson_linear_4.log.gold @@ -0,0 +1,46 @@ +# num procs = 4 +# iteration | res-norm (scaled=1) +# +0 1.0000000000000000e+00 +1 8.7387372561579940e-02 +2 2.6779339721650273e-02 +3 1.0897915740125575e-02 +4 5.0711766707333197e-03 +5 2.5398006285216853e-03 +6 1.3217706827315517e-03 +7 7.0161218046413453e-04 +8 3.7641863971192661e-04 +9 2.0321883293832925e-04 +10 1.1015747962138637e-04 +11 5.9883501360093953e-05 +12 3.2624739413029711e-05 +13 1.7805250083901582e-05 +14 9.7316084864752302e-06 +15 5.3255619248060550e-06 +16 2.9175636856106329e-06 +17 1.5999008571909777e-06 +18 8.7808617287649501e-07 +19 4.8229573408458779e-07 +20 2.6508710806066269e-07 +21 1.4579216204013829e-07 +22 8.0227944311910053e-08 +23 4.4171496857346630e-08 +24 2.4331319070860709e-08 +25 1.3408528408692167e-08 +26 7.3922349902447991e-09 +27 4.0769841165696690e-09 +28 2.2493769755710373e-09 +29 1.2414766370834466e-09 +30 6.8542923294521965e-10 +31 3.7855638452541837e-10 +32 2.0914130905584290e-10 +33 1.1558166921508074e-10 +34 6.3896589743474208e-11 +35 3.5335127002492129e-11 +36 1.9546882133191326e-11 +37 1.0816646713788990e-11 +38 5.9876354608459683e-12 +39 3.3156569336134692e-12 +40 1.8367075485414091e-12 +41 1.0178221722103886e-12 +42 5.6424945860258692e-13 From 093845011b4184bd4e7cf8e1b8aadb8895bc8f81 Mon Sep 17 00:00:00 2001 From: Sven Baars Date: Thu, 17 Mar 2022 12:43:55 +0100 Subject: [PATCH 036/147] PyTrilinos: Fix Tpetra bindings when compiled with -DTpetra_INST_INT_LONG_LONG:BOOL=OFF. --- packages/PyTrilinos/cmake/PyTrilinos_config.h.in | 5 +++++ packages/PyTrilinos/src/Tpetra.i | 2 ++ 2 files changed, 7 insertions(+) diff --git a/packages/PyTrilinos/cmake/PyTrilinos_config.h.in b/packages/PyTrilinos/cmake/PyTrilinos_config.h.in index 48c7956eb6f9..443d7fd765e0 100644 --- a/packages/PyTrilinos/cmake/PyTrilinos_config.h.in +++ b/packages/PyTrilinos/cmake/PyTrilinos_config.h.in @@ -123,7 +123,12 @@ /* PyTrilinos ordinal types */ +#ifdef HAVE_TPETRA_INST_INT_LONG_LONG #define PYTRILINOS_GLOBAL_ORD long long +#else +#define PYTRILINOS_GLOBAL_ORD int +#endif + #define PYTRILINOS_LOCAL_ORD int /**********************************************************************/ diff --git a/packages/PyTrilinos/src/Tpetra.i b/packages/PyTrilinos/src/Tpetra.i index 9b250e6e780a..ee1e5fb803bb 100644 --- a/packages/PyTrilinos/src/Tpetra.i +++ b/packages/PyTrilinos/src/Tpetra.i @@ -1477,7 +1477,9 @@ public: // Concrete scalar types for Tpetra classes // ////////////////////////////////////////////// %tpetra_scalars(int , int ) +#ifdef HAVE_TPETRA_INST_INT_LONG_LONG %tpetra_scalars(long long , long ) +#endif %tpetra_scalars(double , double) ///////////////////////////////////////////////////// From 9949824d8259ea54e269cff6d55ccbe2f79acb9e Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Thu, 17 Mar 2022 13:37:47 +0100 Subject: [PATCH 037/147] MueLu: avoid allocation of vector in region code --- .../research/regionMG/src/SetupRegionMatrix_def.hpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/muelu/research/regionMG/src/SetupRegionMatrix_def.hpp b/packages/muelu/research/regionMG/src/SetupRegionMatrix_def.hpp index d1ed9d258424..60b14ae6276a 100644 --- a/packages/muelu/research/regionMG/src/SetupRegionMatrix_def.hpp +++ b/packages/muelu/research/regionMG/src/SetupRegionMatrix_def.hpp @@ -524,17 +524,12 @@ computeResidual(RCP >& const ArrayRCP regionInterfaceLIDs = params.get>("Fast MatVec: interface LIDs"); const RCP regionInterfaceImporter = params.get>("Fast MatVec: interface importer"); - // Todo: would it be faster to store this in regRes: - // regRes = A*x - // regRes->update(one, regB, -one); - // and avoid allocating and de-allocating memory for y vector? - - // Step 1: Compute region version of y = Ax - RCP aTimesX = VectorFactory::Build(regionMats->getRangeMap(), true); - regionMats->apply(*regX, *aTimesX, Teuchos::NO_TRANS, TST::one(), TST::zero(), true, regionInterfaceImporter, regionInterfaceLIDs); + // Step 1: Compute region version of y = Ax and store it in regRes + // RCP aTimesX = VectorFactory::Build(regionMats->getRangeMap(), true); + regionMats->apply(*regX, *regRes, Teuchos::NO_TRANS, TST::one(), TST::zero(), true, regionInterfaceImporter, regionInterfaceLIDs); // Step 2: Compute region version of r = b - y - regRes->update(TST::one(), *regB, -TST::one(), *aTimesX, TST::zero()); + regRes->update(TST::one(), *regB, -TST::one(), *regRes, TST::zero()); tm = Teuchos::null; } // computeResidual From 1b9f50742d336201934854fa056b67dcccaa8412 Mon Sep 17 00:00:00 2001 From: Christian Glusa Date: Wed, 16 Mar 2022 16:44:40 -0600 Subject: [PATCH 038/147] Tpetra: ETI LocalCrsMatrixOperator for mixed scalar types --- packages/tpetra/core/src/CMakeLists.txt | 22 +++++++++++++++++++ .../src/Tpetra_LocalCrsMatrixOperator_def.hpp | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/packages/tpetra/core/src/CMakeLists.txt b/packages/tpetra/core/src/CMakeLists.txt index b41cef7bf9d2..205bbb4c715d 100644 --- a/packages/tpetra/core/src/CMakeLists.txt +++ b/packages/tpetra/core/src/CMakeLists.txt @@ -829,6 +829,28 @@ IF (${PACKAGE_NAME}_ENABLE_EXPLICIT_INSTANTIATION) "${TpetraCore_ETI_GORDS}" "${TpetraCore_ETI_NODES}" TRUE TRUE) LIST(APPEND SOURCES ${LOCALCRSMATRIXOPERATOR_OUTPUT_FILES}) + # Generate ETI .cpp files for Tpetra::LocalCrsMatrixOperator with mixed Scalars. + ASSERT_DEFINED (Tpetra_INST_DOUBLE) + ASSERT_DEFINED (Tpetra_INST_FLOAT) + IF (Tpetra_INST_DOUBLE AND Tpetra_INST_FLOAT) + TPETRA_PROCESS_ALL_CONVERT_TEMPLATES(LOCALCRSMATRIXOPERATOR_MIXED_OUTPUT_FILES + "Tpetra_ETI_SOUT_SIN_LO_GO_NT.tmpl" "LocalCrsMatrixOperator" + "LOCALCRSMATRIXOPERATOR_MIXED" + "double" "float" + "${TpetraCore_ETI_LORDS}" "${TpetraCore_ETI_GORDS}" "${TpetraCore_ETI_NODES}" True True) + LIST(APPEND SOURCES ${LOCALCRSMATRIXOPERATOR_MIXED_OUTPUT_FILES}) + ENDIF() + ASSERT_DEFINED (Tpetra_INST_COMPLEX_DOUBLE) + ASSERT_DEFINED (Tpetra_INST_COMPLEX_FLOAT) + IF (Tpetra_INST_COMPLEX_DOUBLE AND Tpetra_INST_COMPLEX_FLOAT) + TPETRA_PROCESS_ALL_CONVERT_TEMPLATES(LOCALCRSMATRIXOPERATOR_MIXED_OUTPUT_FILES + "Tpetra_ETI_SOUT_SIN_LO_GO_NT.tmpl" "LocalCrsMatrixOperator" + "LOCALCRSMATRIXOPERATOR_MIXED" + "std::complex" "std::complex" + "${TpetraCore_ETI_LORDS}" "${TpetraCore_ETI_GORDS}" "${TpetraCore_ETI_NODES}" True True) + LIST(APPEND SOURCES ${LOCALCRSMATRIXOPERATOR_MIXED_OUTPUT_FILES}) + ENDIF() + # Generate ETI .cpp files for Tpetra::CrsGraph. TPETRA_PROCESS_ALL_LGN_TEMPLATES(CRSGRAPH_OUTPUT_FILES "Tpetra_ETI_LO_GO_NT.tmpl" diff --git a/packages/tpetra/core/src/Tpetra_LocalCrsMatrixOperator_def.hpp b/packages/tpetra/core/src/Tpetra_LocalCrsMatrixOperator_def.hpp index 9ad516eb4657..15a68f7a7092 100644 --- a/packages/tpetra/core/src/Tpetra_LocalCrsMatrixOperator_def.hpp +++ b/packages/tpetra/core/src/Tpetra_LocalCrsMatrixOperator_def.hpp @@ -204,4 +204,9 @@ getLocalMatrixDevice () const #define TPETRA_LOCALCRSMATRIXOPERATOR_INSTANT(SC,NT) \ template class LocalCrsMatrixOperator< SC, SC, NT::device_type >; +// If we want mixed versions, we use this macro. + +#define TPETRA_LOCALCRSMATRIXOPERATOR_MIXED_INSTANT(SC,MATSC,LO,GO,NT) \ + template class LocalCrsMatrixOperator< SC, MATSC, NT::device_type >; + #endif // TPETRA_LOCALCRSMATRIXOPERATOR_DEF_HPP From 67c66a7b6b2dcddde7e6bb5d32cc6ab4f5c541c2 Mon Sep 17 00:00:00 2001 From: Christian Glusa Date: Wed, 16 Mar 2022 16:43:14 -0600 Subject: [PATCH 039/147] MueLu: Add option "transfers: half precision" Converts transfers P and R to half precision --- packages/muelu/doc/UsersGuide/masterList.xml | 8 + .../muelu/doc/UsersGuide/options_misc.tex | 2 + packages/muelu/doc/UsersGuide/paramlist.tex | 2 + .../muelu/doc/UsersGuide/paramlist_hidden.tex | 2 + packages/muelu/src/CMakeLists.txt | 1 + .../src/Headers/MueLu_UseShortNamesScalar.hpp | 3 + .../MueLu_ParameterListInterpreter_decl.hpp | 3 + .../MueLu_ParameterListInterpreter_def.hpp | 35 ++++ .../Misc/MueLu_LowPrecisionFactory_decl.hpp | 108 +++++++++++ .../Misc/MueLu_LowPrecisionFactory_def.hpp | 125 ++++++++++++ .../muelu/src/MueCentral/MueLu_MasterList.cpp | 3 + .../src/Utils/ClassList/SC-LO-GO-NO.classList | 1 + .../ETI_SC_LO_GO_NO_classes.cmake | 1 + .../MueLu_LowPrecisionFactory_fwd.hpp | 63 ++++++ packages/muelu/test/scaling/scaling.xml | 1 + packages/muelu/test/unit_tests/CMakeLists.txt | 1 + .../muelu/test/unit_tests/LowPrecision.cpp | 182 ++++++++++++++++++ 17 files changed, 541 insertions(+) create mode 100644 packages/muelu/src/Misc/MueLu_LowPrecisionFactory_decl.hpp create mode 100644 packages/muelu/src/Misc/MueLu_LowPrecisionFactory_def.hpp create mode 100644 packages/muelu/src/Utils/ForwardDeclaration/MueLu_LowPrecisionFactory_fwd.hpp create mode 100644 packages/muelu/test/unit_tests/LowPrecision.cpp diff --git a/packages/muelu/doc/UsersGuide/masterList.xml b/packages/muelu/doc/UsersGuide/masterList.xml index ec3ca3c925b4..c876eab4db2a 100644 --- a/packages/muelu/doc/UsersGuide/masterList.xml +++ b/packages/muelu/doc/UsersGuide/masterList.xml @@ -1041,6 +1041,14 @@ not supported by ML + + transfers: half precision + bool + false + Replace transfer operators P and R (if explicitely constructed) with half precision versions for the solve phase.. + not supported by ML + + nullspace: calculate rotations bool diff --git a/packages/muelu/doc/UsersGuide/options_misc.tex b/packages/muelu/doc/UsersGuide/options_misc.tex index 46578ee8b5fd..1c126cd53cdf 100644 --- a/packages/muelu/doc/UsersGuide/options_misc.tex +++ b/packages/muelu/doc/UsersGuide/options_misc.tex @@ -15,6 +15,8 @@ \cbb{transpose: use implicit}{bool}{false}{Use implicit transpose for the restriction operator.} +\cbb{transfers: half precision}{bool}{false}{Replace transfer operators P and R (if explicitely constructed) with half precision versions for the solve phase..} + \cbb{nullspace: calculate rotations}{bool}{false}{When nullspace internally generated by muelu, calculate null space rotations in addition to translations.} \cbb{nullspace: suppress dimension check}{bool}{false}{Suppress safety check to ensure that nullspace dimension is at least equal or greater than the number of PDEs per mesh node.} diff --git a/packages/muelu/doc/UsersGuide/paramlist.tex b/packages/muelu/doc/UsersGuide/paramlist.tex index e26b7e3f12bc..e6b83710158d 100644 --- a/packages/muelu/doc/UsersGuide/paramlist.tex +++ b/packages/muelu/doc/UsersGuide/paramlist.tex @@ -158,6 +158,8 @@ \cbb{transpose: use implicit}{bool}{false}{Use implicit transpose for the restriction operator.} +\cbb{transfers: half precision}{bool}{false}{Replace transfer operators P and R (if explicitely constructed) with half precision versions for the solve phase..} + \cbb{nullspace: calculate rotations}{bool}{false}{When nullspace internally generated by muelu, calculate null space rotations in addition to translations.} \cbb{nullspace: suppress dimension check}{bool}{false}{Suppress safety check to ensure that nullspace dimension is at least equal or greater than the number of PDEs per mesh node.} diff --git a/packages/muelu/doc/UsersGuide/paramlist_hidden.tex b/packages/muelu/doc/UsersGuide/paramlist_hidden.tex index 84712befb30a..e291ad94f297 100644 --- a/packages/muelu/doc/UsersGuide/paramlist_hidden.tex +++ b/packages/muelu/doc/UsersGuide/paramlist_hidden.tex @@ -233,6 +233,8 @@ \cbb{transpose: use implicit}{bool}{false}{Use implicit transpose for the restriction operator.} +\cbb{transfers: half precision}{bool}{false}{Replace transfer operators P and R (if explicitely constructed) with half precision versions for the solve phase..} + \cbb{nullspace: calculate rotations}{bool}{false}{When nullspace internally generated by muelu, calculate null space rotations in addition to translations.} \cbb{nullspace: suppress dimension check}{bool}{false}{Suppress safety check to ensure that nullspace dimension is at least equal or greater than the number of PDEs per mesh node.} diff --git a/packages/muelu/src/CMakeLists.txt b/packages/muelu/src/CMakeLists.txt index c87939a9ea05..ea04922a4df1 100644 --- a/packages/muelu/src/CMakeLists.txt +++ b/packages/muelu/src/CMakeLists.txt @@ -467,3 +467,4 @@ TRIBITS_ADD_LIBRARY( # touch CMakeLists.txt because a new file was created in Utils/ExplicitInstantiation of Utils/ForwardDeclaration # touch CMakeLists.txt because a new file was created in Utils/ExplicitInstantiation of Utils/ForwardDeclaration # touch CMakeLists.txt because a new file was created in Utils/ExplicitInstantiation of Utils/ForwardDeclaration +# touch CMakeLists.txt because a new file was created in Utils/ExplicitInstantiation of Utils/ForwardDeclaration diff --git a/packages/muelu/src/Headers/MueLu_UseShortNamesScalar.hpp b/packages/muelu/src/Headers/MueLu_UseShortNamesScalar.hpp index 937da226b4a5..c9c6c0815e8b 100644 --- a/packages/muelu/src/Headers/MueLu_UseShortNamesScalar.hpp +++ b/packages/muelu/src/Headers/MueLu_UseShortNamesScalar.hpp @@ -173,6 +173,9 @@ typedef MueLu::LineDetectionFactory Line #ifdef MUELU_LOCALPERMUTATIONSTRATEGY_SHORT typedef MueLu::LocalPermutationStrategy LocalPermutationStrategy; #endif +#ifdef MUELU_LOWPRECISIONFACTORY_SHORT +typedef MueLu::LowPrecisionFactory LowPrecisionFactory; +#endif #ifdef MUELU_MAPTRANSFERFACTORY_SHORT typedef MueLu::MapTransferFactory MapTransferFactory; #endif diff --git a/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_decl.hpp b/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_decl.hpp index 560f1f21b5d6..f071315da0a4 100644 --- a/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_decl.hpp +++ b/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_decl.hpp @@ -73,6 +73,7 @@ #include "MueLu_InitialBlockNumberFactory_fwd.hpp" #include "MueLu_LineDetectionFactory_fwd.hpp" #include "MueLu_LocalOrdinalTransferFactory_fwd.hpp" +#include "MueLu_LowPrecisionFactory_fwd.hpp" #include "MueLu_NotayAggregationFactory_fwd.hpp" #include "MueLu_NullspaceFactory_fwd.hpp" #include "MueLu_PatternFactory_fwd.hpp" @@ -231,6 +232,8 @@ namespace MueLu { int levelID, std::vector& keeps) const; void UpdateFactoryManager_Repartition(Teuchos::ParameterList& paramList, const Teuchos::ParameterList& defaultList, FactoryManager& manager, int levelID, std::vector& keeps, RCP & nullSpaceFactory) const; + void UpdateFactoryManager_LowPrecision(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager, + int levelID, std::vector& keeps) const; void UpdateFactoryManager_Nullspace(Teuchos::ParameterList& paramList, const Teuchos::ParameterList& defaultList, FactoryManager& manager, int levelID, std::vector& keeps, RCP & nullSpaceFactory) const; void UpdateFactoryManager_BlockNumber(Teuchos::ParameterList& paramList, const Teuchos::ParameterList& defaultList, diff --git a/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_def.hpp b/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_def.hpp index f58fdfef29ae..6d8586cf953d 100644 --- a/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_def.hpp +++ b/packages/muelu/src/Interface/MueLu_ParameterListInterpreter_def.hpp @@ -106,6 +106,7 @@ #include "MueLu_ZoltanInterface.hpp" #include "MueLu_Zoltan2Interface.hpp" #include "MueLu_NodePartitionInterface.hpp" +#include "MueLu_LowPrecisionFactory.hpp" #ifdef HAVE_MUELU_KOKKOS_REFACTOR #include "MueLu_CoalesceDropFactory_kokkos.hpp" @@ -700,6 +701,9 @@ namespace MueLu { // === Repartitioning === UpdateFactoryManager_Repartition(paramList, defaultList, manager, levelID, keeps, nullSpaceFactory); + // === Lower precision transfers === + UpdateFactoryManager_LowPrecision(paramList, defaultList, manager, levelID, keeps); + // === Final Keeps for Reuse === if ((reuseType == "RAP" || reuseType == "full") && levelID) { keeps.push_back(keep_pair("P", manager.GetFactory("P").get())); @@ -1769,6 +1773,37 @@ namespace MueLu { } } + // ===================================================================================================== + // ========================================= Low precision transfers =================================== + // ===================================================================================================== + template + void ParameterListInterpreter:: + UpdateFactoryManager_LowPrecision(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager, + int levelID, std::vector& keeps) const + { + MUELU_SET_VAR_2LIST(paramList, defaultList, "transfers: half precision", bool, enableLowPrecision); + + if (enableLowPrecision) { + // Low precision P + auto newP = rcp(new LowPrecisionFactory()); + ParameterList newPparams; + newPparams.set("matrix key", "P"); + newP-> SetParameterList(newPparams); + newP-> SetFactory("P", manager.GetFactory("P")); + manager.SetFactory("P", newP); + + if (!this->implicitTranspose_) { + // Low precision R + auto newR = rcp(new LowPrecisionFactory()); + ParameterList newRparams; + newRparams.set("matrix key", "R"); + newR-> SetParameterList(newRparams); + newR-> SetFactory("R", manager.GetFactory("R")); + manager.SetFactory("R", newR); + } + } + } + // ===================================================================================================== // =========================================== Nullspace =============================================== // ===================================================================================================== diff --git a/packages/muelu/src/Misc/MueLu_LowPrecisionFactory_decl.hpp b/packages/muelu/src/Misc/MueLu_LowPrecisionFactory_decl.hpp new file mode 100644 index 000000000000..d6c8a7429ccd --- /dev/null +++ b/packages/muelu/src/Misc/MueLu_LowPrecisionFactory_decl.hpp @@ -0,0 +1,108 @@ +// @HEADER +// +// *********************************************************************** +// +// MueLu: A package for multigrid based preconditioning +// Copyright 2012 Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact +// Jonathan Hu (jhu@sandia.gov) +// Andrey Prokopenko (aprokop@sandia.gov) +// Ray Tuminaro (rstumin@sandia.gov) +// +// *********************************************************************** +// +// @HEADER +#ifndef MUELU_LOWPRECISIONFACTORY_DECL_HPP +#define MUELU_LOWPRECISIONFACTORY_DECL_HPP + +#include + +#include "MueLu_ConfigDefs.hpp" +#include "MueLu_LowPrecisionFactory_fwd.hpp" + +#include "MueLu_GraphBase.hpp" +#include "MueLu_Level_fwd.hpp" +#include "MueLu_SingleLevelFactoryBase.hpp" + +namespace MueLu { + + /*! + @class LowPrecisionFactory class. + @brief Factory for converting matrices to half precision operators + */ + + template + class LowPrecisionFactory : public SingleLevelFactoryBase { +#undef MUELU_LOWPRECISIONFACTORY_SHORT +#include "MueLu_UseShortNames.hpp" + + public: + + //! @name Constructors/Destructors. + //@{ + + LowPrecisionFactory() { } + + //! Destructor. + virtual ~LowPrecisionFactory() { } + + RCP GetValidParameterList() const; + + //@} + + //! Input + //@{ + + void DeclareInput(Level& currentLevel) const; + + //@} + + //! @name Build methods. + //@{ + + /*! + @brief Build method. + + Converts a matrix to half precision operators and returns it in currentLevel. + */ + void Build(Level& currentLevel) const; + + //@} + + }; //class LowPrecisionFactory + +} //namespace MueLu + +#define MUELU_LOWPRECISIONFACTORY_SHORT +#endif // MUELU_LOWPRECISIONFACTORY_DECL_HPP diff --git a/packages/muelu/src/Misc/MueLu_LowPrecisionFactory_def.hpp b/packages/muelu/src/Misc/MueLu_LowPrecisionFactory_def.hpp new file mode 100644 index 000000000000..35cc8c393612 --- /dev/null +++ b/packages/muelu/src/Misc/MueLu_LowPrecisionFactory_def.hpp @@ -0,0 +1,125 @@ +// @HEADER +// +// *********************************************************************** +// +// MueLu: A package for multigrid based preconditioning +// Copyright 2012 Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact +// Jonathan Hu (jhu@sandia.gov) +// Andrey Prokopenko (aprokop@sandia.gov) +// Ray Tuminaro (rstumin@sandia.gov) +// +// *********************************************************************** +// +// @HEADER +#ifndef MUELU_LOWPRECISIONFACTORY_DEF_HPP +#define MUELU_LOWPRECISIONFACTORY_DEF_HPP + +#include +#include +#include +#include + +#include "MueLu_LowPrecisionFactory_decl.hpp" + +#include "MueLu_FactoryManager.hpp" +#include "MueLu_Level.hpp" +#include "MueLu_MasterList.hpp" +#include "MueLu_Monitor.hpp" + + +namespace MueLu { + + template + RCP LowPrecisionFactory::GetValidParameterList() const { + RCP validParamList = rcp(new ParameterList()); + + validParamList->set("matrix key", "A", ""); + validParamList->set< RCP >("R", Teuchos::null, "Generating factory of the matrix A to be converted to lower precision"); + validParamList->set< RCP >("A", Teuchos::null, "Generating factory of the matrix A to be converted to lower precision"); + validParamList->set< RCP >("P", Teuchos::null, "Generating factory of the matrix A to be converted to lower precision"); + + return validParamList; + } + + template + void LowPrecisionFactory::DeclareInput(Level& currentLevel) const { + + const ParameterList& pL = GetParameterList(); + std::string matrixKey = pL.get("matrix key"); + Input(currentLevel, matrixKey); + } + + template + void LowPrecisionFactory::Build(Level& currentLevel) const { + using Teuchos::ParameterList; + using HalfScalar = typename Teuchos::ScalarTraits::halfPrecision; + + const ParameterList& pL = GetParameterList(); + std::string matrixKey = pL.get("matrix key"); + + FactoryMonitor m(*this, "Converting " + matrixKey + " to half precision", currentLevel); + + RCP A = Get< RCP >(currentLevel, matrixKey); + +#if defined(HAVE_TPETRA_INST_DOUBLE) && defined(HAVE_TPETRA_INST_FLOAT) + if ((A->getRowMap()->lib() == Xpetra::UseTpetra) && std::is_same::value) { + auto tpA = rcp_dynamic_cast(rcp_dynamic_cast(A)->getCrsMatrix(), true)->getTpetra_CrsMatrix(); + auto tpLowA = tpA->template convert(); + auto tpLowOpA = rcp(new Tpetra::CrsMatrixMultiplyOp(tpLowA)); + auto xpTpLowOpA = rcp(new TpetraOperator(tpLowOpA)); + auto xpLowOpA = rcp_dynamic_cast(xpTpLowOpA); + Set(currentLevel, matrixKey, xpLowOpA); + return; + } +#endif +#if defined(HAVE_TPETRA_INST_DOUBLE) && defined(HAVE_TPETRA_INST_FLOAT) + if ((A->getRowMap()->lib() == Xpetra::UseTpetra) && std::is_same>::value) { + auto tpA = rcp_dynamic_cast(rcp_dynamic_cast(A)->getCrsMatrix(), true)->getTpetra_CrsMatrix(); + auto tpLowA = tpA->template convert(); + auto tpLowOpA = rcp(new Tpetra::CrsMatrixMultiplyOp(tpLowA)); + auto xpTpLowOpA = rcp(new TpetraOperator(tpLowOpA)); + auto xpLowOpA = rcp_dynamic_cast(xpTpLowOpA); + Set(currentLevel, matrixKey, xpLowOpA); + return; + } +#endif + + GetOStream(Warnings) << "Matrix not converted to half precision. This only works for Tpetra and when both Scalar and HalfScalar have been instantiated." << std::endl; + Set(currentLevel, matrixKey, A); + } + +} //namespace MueLu + +#endif // MUELU_LOWPRECISIONFACTORY_DEF_HPP diff --git a/packages/muelu/src/MueCentral/MueLu_MasterList.cpp b/packages/muelu/src/MueCentral/MueLu_MasterList.cpp index 259b508dd7b1..81da25908322 100644 --- a/packages/muelu/src/MueCentral/MueLu_MasterList.cpp +++ b/packages/muelu/src/MueCentral/MueLu_MasterList.cpp @@ -275,6 +275,7 @@ namespace MueLu { "" "" "" + "" "" "" "" @@ -762,6 +763,8 @@ namespace MueLu { ("transpose: use implicit","transpose: use implicit") + ("transfers: half precision","transfers: half precision") + ("nullspace: calculate rotations","nullspace: calculate rotations") ("nullspace: suppress dimension check","nullspace: suppress dimension check") diff --git a/packages/muelu/src/Utils/ClassList/SC-LO-GO-NO.classList b/packages/muelu/src/Utils/ClassList/SC-LO-GO-NO.classList index 16e50e8dffe5..7f02c8afa8af 100644 --- a/packages/muelu/src/Utils/ClassList/SC-LO-GO-NO.classList +++ b/packages/muelu/src/Utils/ClassList/SC-LO-GO-NO.classList @@ -55,6 +55,7 @@ InitialBlockNumberFactory IntrepidPCoarsenFactory - #ifdef HAVE_MUELU_INTREPID2 LineDetectionFactory LocalPermutationStrategy +LowPrecisionFactory MapTransferFactory MatrixAnalysisFactory MergedBlockedMatrixFactory diff --git a/packages/muelu/src/Utils/ExplicitInstantiation/ETI_SC_LO_GO_NO_classes.cmake b/packages/muelu/src/Utils/ExplicitInstantiation/ETI_SC_LO_GO_NO_classes.cmake index acfe810bc55a..86304681ea42 100644 --- a/packages/muelu/src/Utils/ExplicitInstantiation/ETI_SC_LO_GO_NO_classes.cmake +++ b/packages/muelu/src/Utils/ExplicitInstantiation/ETI_SC_LO_GO_NO_classes.cmake @@ -53,6 +53,7 @@ APPEND_SET(MUELU_SC_LO_GO_NO_ETI_CLASSES MueLu::InitialBlockNumberFactory ) APPEND_SET(MUELU_SC_LO_GO_NO_ETI_CLASSES MueLu::IntrepidPCoarsenFactory-.?ifdef.HAVE_MUELU_INTREPID2 ) APPEND_SET(MUELU_SC_LO_GO_NO_ETI_CLASSES MueLu::LineDetectionFactory ) APPEND_SET(MUELU_SC_LO_GO_NO_ETI_CLASSES MueLu::LocalPermutationStrategy ) +APPEND_SET(MUELU_SC_LO_GO_NO_ETI_CLASSES MueLu::LowPrecisionFactory ) APPEND_SET(MUELU_SC_LO_GO_NO_ETI_CLASSES MueLu::MapTransferFactory ) APPEND_SET(MUELU_SC_LO_GO_NO_ETI_CLASSES MueLu::MatrixAnalysisFactory ) APPEND_SET(MUELU_SC_LO_GO_NO_ETI_CLASSES MueLu::MergedBlockedMatrixFactory ) diff --git a/packages/muelu/src/Utils/ForwardDeclaration/MueLu_LowPrecisionFactory_fwd.hpp b/packages/muelu/src/Utils/ForwardDeclaration/MueLu_LowPrecisionFactory_fwd.hpp new file mode 100644 index 000000000000..8d9feecd64e5 --- /dev/null +++ b/packages/muelu/src/Utils/ForwardDeclaration/MueLu_LowPrecisionFactory_fwd.hpp @@ -0,0 +1,63 @@ +// @HEADER +// +// *********************************************************************** +// +// MueLu: A package for multigrid based preconditioning +// Copyright 2012 Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact +// Jonathan Hu (jhu@sandia.gov) +// Andrey Prokopenko (aprokop@sandia.gov) +// Ray Tuminaro (rstumin@sandia.gov) +// +// *********************************************************************** +// +// @HEADER +#ifndef MUELU_LOWPRECISIONFACTORY_FWD_HPP +#define MUELU_LOWPRECISIONFACTORY_FWD_HPP + + + + +namespace MueLu { + template + class LowPrecisionFactory; +} + +#ifndef MUELU_LOWPRECISIONFACTORY_SHORT +#define MUELU_LOWPRECISIONFACTORY_SHORT +#endif + + + +#endif // MUELU_LOWPRECISIONFACTORY_FWD_HPP diff --git a/packages/muelu/test/scaling/scaling.xml b/packages/muelu/test/scaling/scaling.xml index b8787d19322f..b2db6d6434b5 100644 --- a/packages/muelu/test/scaling/scaling.xml +++ b/packages/muelu/test/scaling/scaling.xml @@ -13,6 +13,7 @@ + diff --git a/packages/muelu/test/unit_tests/CMakeLists.txt b/packages/muelu/test/unit_tests/CMakeLists.txt index f7d883cebb24..ceb127b78c0e 100644 --- a/packages/muelu/test/unit_tests/CMakeLists.txt +++ b/packages/muelu/test/unit_tests/CMakeLists.txt @@ -38,6 +38,7 @@ APPEND_SET(SOURCES Hierarchy.cpp IndexManager.cpp Level.cpp + LowPrecision.cpp LWGraph.cpp MapTransferFactory.cpp Memory.cpp diff --git a/packages/muelu/test/unit_tests/LowPrecision.cpp b/packages/muelu/test/unit_tests/LowPrecision.cpp new file mode 100644 index 000000000000..fd72a8b492f7 --- /dev/null +++ b/packages/muelu/test/unit_tests/LowPrecision.cpp @@ -0,0 +1,182 @@ +// @HEADER +// +// *********************************************************************** +// +// MueLu: A package for multigrid based preconditioning +// Copyright 2012 Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact +// Jonathan Hu (jhu@sandia.gov) +// Andrey Prokopenko (aprokop@sandia.gov) +// Ray Tuminaro (rstumin@sandia.gov) +// +// *********************************************************************** +// +// @HEADER + +#include +#include +#include +#include +#include +#include +#include +// #include + +#include +#include +#include + +#ifdef HAVE_MUELU_TPETRA +# include +#endif + +namespace MueLuTests { + + TEUCHOS_UNIT_TEST_TEMPLATE_4_DECL(LowPrecisionFactory, Basic, Scalar, LocalOrdinal, GlobalOrdinal, Node) + { +# include + MUELU_TESTING_SET_OSTREAM; + MUELU_TESTING_LIMIT_SCOPE(Scalar,GlobalOrdinal,Node); + out << "version: " << MueLu::Version() << std::endl; + + using Teuchos::TimeMonitor; + using TST = Teuchos::ScalarTraits; + using HalfScalar = typename TST::halfPrecision; + using HalfTST = Teuchos::ScalarTraits; + + // Modify to read in matrix + std::string matrix_file = ""; + + // for timing + int numMatvecs = 100; + + RCP A; + if (matrix_file == "") { + int nx = 1000; + A = TestHelpers::TestFactory::Build2DPoisson(nx); + } else { + RCP > comm = TestHelpers::Parameters::getDefaultComm(); + A = Xpetra::IO::Read(matrix_file, Xpetra::UseTpetra, comm); + } + + RCP lowA; + const bool isTpetra = A->getDomainMap()->lib() == Xpetra::UseTpetra; + std::list matrixKeys = {"A", "P", "R"}; + for (auto it = matrixKeys.begin(); it != matrixKeys.end(); ++it) { + Level aLevel; + TestHelpers::TestFactory::createSingleLevelHierarchy(aLevel); + aLevel.Set(*it,A); + + // Set up LowPrecisionFactory + RCP LP = rcp(new LowPrecisionFactory()); + Teuchos::ParameterList params; + params.set("matrix key", *it); + LP->SetParameterList(params); + + // Build + aLevel.Request(*it,LP.get()); + LP->Build(aLevel); + TEST_EQUALITY(aLevel.IsAvailable(*it,LP.get()), true); + lowA = aLevel.Get< RCP >(*it,LP.get()); + aLevel.Release(*it,LP.get()); + + // Check that the resulting Op is as expected. + if (isTpetra && (false +#if defined(HAVE_TPETRA_INST_DOUBLE) && defined(HAVE_TPETRA_INST_FLOAT) + || std::is_same::value +#endif +#if defined(HAVE_TPETRA_INST_COMPLEX_DOUBLE) && defined(HAVE_TPETRA_INST_COMPLEX_FLOAT) + || std::is_same >::value +#endif + )) { +#ifdef HAVE_MUELU_TPETRA + auto tpCrsMultOp = rcp_dynamic_cast >(rcp_dynamic_cast(lowA)->getOperator()); + TEST_ASSERT(!tpCrsMultOp.is_null()); // Actually converted +#else + TEST_ASSERT(false); // We should never get here. +#endif + } else { + TEST_ASSERT(!rcp_dynamic_cast(lowA).is_null()); // Just a regular old matrix + TEST_EQUALITY(A, lowA); + } + } + + // Check apply + if (isTpetra && std::is_same::value) { + RCP X = MultiVectorFactory::Build(A->getDomainMap(),1); + X->randomize(); + + RCP B = MultiVectorFactory::Build(A->getRangeMap(),1); + RCP B0 = MultiVectorFactory::Build(lowA->getRangeMap(),1); + + // warm up + for (int i = 0; i < 5; i++) { + A->apply(*X, *B); + } + { + RCP tm = rcp(new TimeMonitor(*TimeMonitor::getNewTimer("MatVec original"))); + for (int i = 0; i < numMatvecs; i++) { + A->apply(*X, *B); + } + } + + // warm up low precision + for (int i = 0; i < 5; i++) { + lowA->apply(*X, *B0); + } + { + RCP tm = rcp(new TimeMonitor(*TimeMonitor::getNewTimer("MatVec low precision"))); + for (int i = 0; i < numMatvecs; i++) { + lowA->apply(*X, *B0); + } + } + + TimeMonitor::summarize(A->getRowMap()->getComm().ptr(), std::cout, false, true, false, Teuchos::Union, "", true); + TimeMonitor::zeroOutTimers(); + + B->update(-1, *B0, 1); + + Teuchos::Array::magnitudeType> norm(1); + B->norm2(norm); + TEST_FLOATING_EQUALITY(norm[0], TST::zero(), HalfTST::eps()); + } + + } + +#define MUELU_ETI_GROUP(Scalar, LocalOrdinal, GlobalOrdinal, Node) \ + TEUCHOS_UNIT_TEST_TEMPLATE_4_INSTANT(LowPrecisionFactory, Basic, Scalar, LocalOrdinal, GlobalOrdinal, Node) + +#include + +} // end MueLuTests namespace From ad18b9dd6fb30c6b701461f11e76f4af8d75e45b Mon Sep 17 00:00:00 2001 From: Christian Glusa Date: Wed, 16 Mar 2022 18:10:57 -0600 Subject: [PATCH 040/147] MueLu: Fix more float tests --- .../MueLu_SaPFactory_def.hpp | 16 +- packages/muelu/test/toggletransfer/main.cpp | 28 ++- packages/muelu/test/unit_tests/Aggregates.cpp | 4 +- .../unit_tests/Smoothers/BlockedSmoother.cpp | 161 +++++++++++------- .../unit_tests_kokkos/Aggregates_kokkos.cpp | 4 +- 5 files changed, 129 insertions(+), 84 deletions(-) diff --git a/packages/muelu/src/Transfers/Smoothed-Aggregation/MueLu_SaPFactory_def.hpp b/packages/muelu/src/Transfers/Smoothed-Aggregation/MueLu_SaPFactory_def.hpp index 5ea16148eaad..d519aa879fd7 100644 --- a/packages/muelu/src/Transfers/Smoothed-Aggregation/MueLu_SaPFactory_def.hpp +++ b/packages/muelu/src/Transfers/Smoothed-Aggregation/MueLu_SaPFactory_def.hpp @@ -689,17 +689,19 @@ namespace MueLu { bool lowerViolation = false; bool upperViolation = false; bool sumViolation = false; - temp = Teuchos::ScalarTraits::zero(); + using TST = Teuchos::ScalarTraits; + temp = TST::zero(); for (LocalOrdinal i = 0; i < nEntries; i++) { - if (Teuchos::ScalarTraits::real(fixedUnsorted[i]) < Teuchos::ScalarTraits::real(notFlippedLeftBound)) lowerViolation = true; - if (Teuchos::ScalarTraits::real(fixedUnsorted[i]) > Teuchos::ScalarTraits::real(notFlippedRghtBound)) upperViolation = true; + if (TST::real(fixedUnsorted[i]) < TST::real(notFlippedLeftBound)) lowerViolation = true; + if (TST::real(fixedUnsorted[i]) > TST::real(notFlippedRghtBound)) upperViolation = true; temp += fixedUnsorted[i]; } - if (Teuchos::ScalarTraits::magnitude(temp - rsumTarget) > Teuchos::ScalarTraits::magnitude(as(1.0e-8)*rsumTarget)) sumViolation = true; + SC tol = as(std::max(1.0e-8, as(100*TST::eps()))); + if (TST::magnitude(temp - rsumTarget) > TST::magnitude(tol*rsumTarget)) sumViolation = true; - TEUCHOS_TEST_FOR_EXCEPTION(lowerViolation, Exceptions::RuntimeError, "MueLu::SaPFactory::constrainRow: feasible solution but computation resulted in a lower bound violation??? "); - TEUCHOS_TEST_FOR_EXCEPTION(upperViolation, Exceptions::RuntimeError, "MueLu::SaPFactory::constrainRow: feasible solution but computation resulted in an upper bound violation??? "); - TEUCHOS_TEST_FOR_EXCEPTION(sumViolation, Exceptions::RuntimeError, "MueLu::SaPFactory::constrainRow: feasible solution but computation resulted in a row sum violation??? "); + TEUCHOS_TEST_FOR_EXCEPTION(lowerViolation, Exceptions::RuntimeError, "MueLu::SaPFactory::constrainRow: feasible solution but computation resulted in a lower bound violation??? "); + TEUCHOS_TEST_FOR_EXCEPTION(upperViolation, Exceptions::RuntimeError, "MueLu::SaPFactory::constrainRow: feasible solution but computation resulted in an upper bound violation??? "); + TEUCHOS_TEST_FOR_EXCEPTION(sumViolation, Exceptions::RuntimeError, "MueLu::SaPFactory::constrainRow: feasible solution but computation resulted in a row sum violation??? "); return hasFeasibleSol; } diff --git a/packages/muelu/test/toggletransfer/main.cpp b/packages/muelu/test/toggletransfer/main.cpp index 9b1f6387277d..3c15c428f423 100644 --- a/packages/muelu/test/toggletransfer/main.cpp +++ b/packages/muelu/test/toggletransfer/main.cpp @@ -150,21 +150,19 @@ int main_(Teuchos::CommandLineProcessor &clp, Xpetra::UnderlyingLib lib, int arg Teuchos::ParameterList paramList; Teuchos::updateParametersFromXmlFileAndBroadcast(xmlFile, Teuchos::Ptr(¶mList), *comm); - if (TYPE_EQUAL(Scalar, std::complex)) { - if (paramList.isSublist("Factories")) { - Teuchos::ParameterList smootherParams = paramList.sublist("Factories").sublist("myJacobi").sublist("ParameterList"); - double damping = smootherParams.get("relaxation: damping factor"); - smootherParams.remove("relaxation: damping factor"); - smootherParams.set("relaxation: damping factor",damping); - paramList.sublist("Factories").sublist("myJacobi").set("ParameterList",smootherParams); - } - if (paramList.isSublist("smoother: params")) { - Teuchos::ParameterList smootherParams = paramList.sublist("smoother: params"); - double damping = smootherParams.get("relaxation: damping factor"); - smootherParams.remove("relaxation: damping factor"); - smootherParams.set("relaxation: damping factor",damping); - paramList.set("smoother: params",smootherParams); - } + if (paramList.isSublist("Factories")) { + Teuchos::ParameterList smootherParams = paramList.sublist("Factories").sublist("myJacobi").sublist("ParameterList"); + double damping = smootherParams.get("relaxation: damping factor"); + smootherParams.remove("relaxation: damping factor"); + smootherParams.set("relaxation: damping factor",damping); + paramList.sublist("Factories").sublist("myJacobi").set("ParameterList",smootherParams); + } + if (paramList.isSublist("smoother: params")) { + Teuchos::ParameterList smootherParams = paramList.sublist("smoother: params"); + double damping = smootherParams.get("relaxation: damping factor"); + smootherParams.remove("relaxation: damping factor"); + smootherParams.set("relaxation: damping factor",damping); + paramList.set("smoother: params",smootherParams); } // create parameter list interpreter diff --git a/packages/muelu/test/unit_tests/Aggregates.cpp b/packages/muelu/test/unit_tests/Aggregates.cpp index fa0e8e734696..055b76448e7e 100644 --- a/packages/muelu/test/unit_tests/Aggregates.cpp +++ b/packages/muelu/test/unit_tests/Aggregates.cpp @@ -1368,7 +1368,7 @@ class AggregateGenerator { RCP dropFact = rcp(new CoalesceDropFactory()); dropFact->SetParameter("aggregation: dropping may create Dirichlet",Teuchos::ParameterEntry(false)); - dropFact->SetParameter("aggregation: drop tol",Teuchos::ParameterEntry(-100*TST::eps())); + dropFact->SetParameter("aggregation: drop tol",Teuchos::ParameterEntry(Teuchos::as(-100*TST::eps()))); RCP amalgFact = rcp(new AmalgamationFactory()); dropFact->SetFactory("UnAmalgamationInfo", amalgFact); level.Request("Graph",dropFact.get()); @@ -1402,7 +1402,7 @@ class AggregateGenerator { amalgFact = rcp(new AmalgamationFactory()); dropFact = rcp(new CoalesceDropFactory()); dropFact->SetParameter("aggregation: dropping may create Dirichlet",Teuchos::ParameterEntry(true)); - dropFact->SetParameter("aggregation: drop tol",Teuchos::ParameterEntry(-100*TST::eps())); + dropFact->SetParameter("aggregation: drop tol",Teuchos::ParameterEntry(Teuchos::as(-100*TST::eps()))); dropFact->SetFactory("UnAmalgamationInfo", amalgFact); level.Request("Graph",dropFact.get()); diff --git a/packages/muelu/test/unit_tests/Smoothers/BlockedSmoother.cpp b/packages/muelu/test/unit_tests/Smoothers/BlockedSmoother.cpp index fe51dd787486..a0d4789e8dfe 100644 --- a/packages/muelu/test/unit_tests/Smoothers/BlockedSmoother.cpp +++ b/packages/muelu/test/unit_tests/Smoothers/BlockedSmoother.cpp @@ -375,8 +375,9 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); out << "solve with zero initial guess, and unreliable nonzeroed vector X" << std::endl; X->randomize(); @@ -390,8 +391,8 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm2[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm2[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + TEUCHOS_TEST_COMPARE(residualNorm2[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); out << "solve with random initial guess" << std::endl; X->randomize(); @@ -405,8 +406,8 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm3[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm3[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + TEUCHOS_TEST_COMPARE(residualNorm3[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); if (comm->getSize() == 1) { TEST_EQUALITY(residualNorm1[0] == residualNorm2[0], true); @@ -517,8 +518,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); out << "solve with zero initial guess, and unreliable nonzeroed vector X" << std::endl; X->randomize(); @@ -532,8 +535,8 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm2[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm2[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + TEUCHOS_TEST_COMPARE(residualNorm2[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); out << "solve with random initial guess" << std::endl; X->randomize(); @@ -547,8 +550,8 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm3[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm3[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + TEUCHOS_TEST_COMPARE(residualNorm3[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); if (comm->getSize() == 1) { TEST_EQUALITY(residualNorm1[0] == residualNorm2[0], true); @@ -654,7 +657,9 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); Teuchos::RCP doMapExtractor = reorderedbA->getDomainMapExtractor(); @@ -810,7 +815,9 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); Teuchos::RCP doMapExtractor = reorderedbA->getDomainMapExtractor(); @@ -1233,7 +1240,9 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 1e-7, out, success); + magnitude_type tol = 10*std::sqrt(Teuchos::ScalarTraits::eps()); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); } // end Tpetra } @@ -1344,7 +1353,9 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); Teuchos::RCP doMapExtractor = reorderedbA->getDomainMapExtractor(); @@ -1580,8 +1591,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); out << "solve with random initial guess" << std::endl; X->randomize(); @@ -1595,8 +1608,8 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm2[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm2[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + TEUCHOS_TEST_COMPARE(residualNorm2[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); if (comm->getSize() == 1) { TEST_EQUALITY(residualNorm1[0] != residualNorm2[0], true); @@ -1787,8 +1800,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -1971,8 +1986,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -2157,8 +2174,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -2341,8 +2360,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -2779,8 +2800,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); out << "solve with random initial guess" << std::endl; X->randomize(); @@ -2794,8 +2817,8 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm2[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm2[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + TEUCHOS_TEST_COMPARE(residualNorm2[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); if (comm->getSize() == 1) { TEST_EQUALITY(residualNorm1[0] != residualNorm2[0], true); @@ -2940,8 +2963,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -3097,8 +3122,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -3238,8 +3265,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -3398,8 +3427,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -3555,8 +3586,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -3922,8 +3955,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); out << "solve with random initial guess" << std::endl; X->randomize(); @@ -3937,8 +3972,8 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm2[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm2[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + TEUCHOS_TEST_COMPARE(residualNorm2[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); if (comm->getSize() == 1) { TEST_EQUALITY(residualNorm1[0] != residualNorm2[0], true); @@ -4124,8 +4159,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -4305,8 +4342,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -4734,8 +4773,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); out << "solve with random initial guess" << std::endl; X->randomize(); @@ -4749,8 +4790,8 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm2[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm2[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + TEUCHOS_TEST_COMPARE(residualNorm2[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); if (comm->getSize() == 1) { TEST_EQUALITY(residualNorm1[0] != residualNorm2[0], true); @@ -4936,8 +4977,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } @@ -5117,8 +5160,10 @@ namespace MueLuTests { out << " ||Residual_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(20) << residualNorm1[0] << std::endl; out << " ||X_final|| = " << std::setiosflags(std::ios::fixed) << std::setprecision(10) << finalNorms[0] << std::endl; - TEUCHOS_TEST_COMPARE(residualNorm1[0], <, 5e-15, out, success); - TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, 5e-15, out, success); + magnitude_type tol = 50.*Teuchos::ScalarTraits::eps(); + + TEUCHOS_TEST_COMPARE(residualNorm1[0], <, tol, out, success); + TEUCHOS_TEST_COMPARE(finalNorms[0] - Teuchos::ScalarTraits::magnitude(Teuchos::ScalarTraits::one()), <, tol, out, success); }// end useTpetra } diff --git a/packages/muelu/test/unit_tests_kokkos/Aggregates_kokkos.cpp b/packages/muelu/test/unit_tests_kokkos/Aggregates_kokkos.cpp index d190902d5428..b76d62e6d019 100644 --- a/packages/muelu/test/unit_tests_kokkos/Aggregates_kokkos.cpp +++ b/packages/muelu/test/unit_tests_kokkos/Aggregates_kokkos.cpp @@ -651,7 +651,7 @@ namespace MueLuTests { RCP dropFact = rcp(new CoalesceDropFactory_kokkos()); dropFact->SetParameter("aggregation: dropping may create Dirichlet",Teuchos::ParameterEntry(false)); - dropFact->SetParameter("aggregation: drop tol",Teuchos::ParameterEntry(-100*TST::eps())); + dropFact->SetParameter("aggregation: drop tol",Teuchos::ParameterEntry(Teuchos::as(-100*TST::eps()))); RCP amalgFact = rcp(new AmalgamationFactory_kokkos()); dropFact->SetFactory("UnAmalgamationInfo", amalgFact); level.Request("Graph",dropFact.get()); @@ -690,7 +690,7 @@ namespace MueLuTests { amalgFact = rcp(new AmalgamationFactory_kokkos()); dropFact = rcp(new CoalesceDropFactory_kokkos()); dropFact->SetParameter("aggregation: dropping may create Dirichlet",Teuchos::ParameterEntry(true)); - dropFact->SetParameter("aggregation: drop tol",Teuchos::ParameterEntry(-100*TST::eps())); + dropFact->SetParameter("aggregation: drop tol",Teuchos::ParameterEntry(Teuchos::as(-100*TST::eps()))); dropFact->SetFactory("UnAmalgamationInfo", amalgFact); level.Request("Graph",dropFact.get()); From 2acb7241bc0d7fbb7eaec1519662495bce472355 Mon Sep 17 00:00:00 2001 From: Jacob Domagala Date: Thu, 17 Mar 2022 19:23:40 +0100 Subject: [PATCH 041/147] Panzer: Fix issue with newly added Panzer_ENABLE_Epetra flag --- packages/panzer/core/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/panzer/core/CMakeLists.txt b/packages/panzer/core/CMakeLists.txt index 5034323914af..c3b4daf45b39 100644 --- a/packages/panzer/core/CMakeLists.txt +++ b/packages/panzer/core/CMakeLists.txt @@ -1,6 +1,11 @@ TRIBITS_SUBPACKAGE(Core) -SET(PANZER_HAVE_EPETRA ${${PACKAGE_NAME}_ENABLE_Epetra} ) +# Consider 'Panzer_ENABLE_Epetra' only if 'Trilinos_ENABLE_Epetra=ON' +IF(Trilinos_ENABLE_Epetra AND DEFINED Panzer_ENABLE_Epetra) + SET(PANZER_HAVE_EPETRA ${Panzer_ENABLE_Epetra}) +ELSE() + SET(PANZER_HAVE_EPETRA ${Trilinos_ENABLE_Epetra}) +ENDIF() IF(PANZER_HAVE_EPETRA) MESSAGE(STATUS "Global Indexer Epetra Utilities On") From 13e11e01f19b6e4687cd67350edf22324642d3c9 Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Fri, 18 Mar 2022 11:55:28 +0100 Subject: [PATCH 042/147] MueLu: fix indentation in region tests --- .../regionMG/test/structured/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/muelu/research/regionMG/test/structured/CMakeLists.txt b/packages/muelu/research/regionMG/test/structured/CMakeLists.txt index 6ca2b8e7d17a..48b728ccb8ec 100644 --- a/packages/muelu/research/regionMG/test/structured/CMakeLists.txt +++ b/packages/muelu/research/regionMG/test/structured/CMakeLists.txt @@ -292,7 +292,7 @@ IF (${PACKAGE_NAME}_ENABLE_Tpetra AND ${PACKAGE_NAME}_ENABLE_Amesos2) TEST_0 EXEC StructuredRegionDriver ARGS --linAlgebra=Tpetra --xml=structured_1dof.xml --matrixType=Star2D --nx=10 --ny=10 --smootherIts=2 --convergence-log=Star2D_GS_4.log --smootherType=Gauss - NUM_MPI_PROCS 4 + NUM_MPI_PROCS 4 TEST_1 CMND ${PYTHON_EXECUTABLE} ARGS compare_residual_history.py gold_files/Star2D_GS_4.log.gold Star2D_GS_4.log 1.0e-12 @@ -307,7 +307,7 @@ IF (${PACKAGE_NAME}_ENABLE_Tpetra AND ${PACKAGE_NAME}_ENABLE_Amesos2) TEST_0 EXEC StructuredRegionDriver ARGS --linAlgebra=Tpetra --xml=structured_linear_1dof.xml --matrixType=Brick3D --nx=10 --ny=10 --nz=10 --smootherIts=2 --convergence-log=Brick3D_linear_4.log - NUM_MPI_PROCS 4 + NUM_MPI_PROCS 4 TEST_1 CMND ${PYTHON_EXECUTABLE} ARGS compare_residual_history.py gold_files/Brick3D_linear_4.log.gold Brick3D_linear_4.log 1.0e-12 @@ -322,7 +322,7 @@ IF (${PACKAGE_NAME}_ENABLE_Tpetra AND ${PACKAGE_NAME}_ENABLE_Amesos2) TEST_0 EXEC StructuredRegionDriver ARGS --linAlgebra=Tpetra --xml=structured_linear_3dof.xml --matrixType=Elasticity3D --nx=10 --ny=10 --nz=10 --smootherIts=2 --convergence-log=Elasticity3D_linear_4.log --solverType=region - NUM_MPI_PROCS 4 + NUM_MPI_PROCS 4 TEST_1 CMND ${PYTHON_EXECUTABLE} ARGS compare_residual_history.py gold_files/Elasticity3D_linear_4.log.gold Elasticity3D_linear_4.log 1.0e-12 @@ -337,7 +337,7 @@ IF (${PACKAGE_NAME}_ENABLE_Tpetra AND ${PACKAGE_NAME}_ENABLE_Amesos2) TEST_0 EXEC StructuredRegionDriver ARGS --linAlgebra=Tpetra --xml=structured_linear_3dof.xml --matrixType=Elasticity3D --nx=10 --ny=10 --nz=10 --smootherIts=2 --convergence-log=Elasticity3D_CG_linear_4.log --solverType=CG - NUM_MPI_PROCS 4 + NUM_MPI_PROCS 4 TEST_1 CMND ${PYTHON_EXECUTABLE} ARGS compare_residual_history.py gold_files/Elasticity3D_CG_linear_4.log.gold Elasticity3D_CG_linear_4.log 1.0e-12 @@ -352,7 +352,7 @@ IF (${PACKAGE_NAME}_ENABLE_Tpetra AND ${PACKAGE_NAME}_ENABLE_Amesos2) TEST_0 EXEC StructuredRegionDriver ARGS --linAlgebra=Tpetra --xml=structured_linear_3dof.xml --matrixType=Elasticity3D --nx=10 --ny=10 --nz=10 --smootherIts=2 --convergence-log=Elasticity3D_Richardson_linear_4.log --solverType=Richardson - NUM_MPI_PROCS 4 + NUM_MPI_PROCS 4 TEST_1 CMND ${PYTHON_EXECUTABLE} ARGS compare_residual_history.py gold_files/Elasticity3D_Richardson_linear_4.log.gold Elasticity3D_Richardson_linear_4.log 1.0e-12 @@ -367,11 +367,11 @@ IF (${PACKAGE_NAME}_ENABLE_Tpetra AND ${PACKAGE_NAME}_ENABLE_Amesos2) TEST_0 EXEC StructuredRegionDriver ARGS --linAlgebra=Tpetra --xml=structured_linear_1dof_comp.xml --matrixType=Brick3D --nx=19 --ny=19 --nz=10 --smootherIts=2 --convergence-log=Brick3D_linear_4_comp.log - NUM_MPI_PROCS 4 + NUM_MPI_PROCS 4 TEST_1 EXEC StructuredRegionDriver ARGS --linAlgebra=Tpetra --xml=structured_linear_R_1dof.xml --matrixType=Brick3D --nx=19 --ny=19 --nz=10 --smootherIts=2 --convergence-log=Brick3D_linear_R_4_comp.log - NUM_MPI_PROCS 4 + NUM_MPI_PROCS 4 TEST_2 CMND ${PYTHON_EXECUTABLE} ARGS compare_residual_history.py Brick3D_linear_4_comp.log Brick3D_linear_R_4_comp.log 1.0e-12 From 8db9a2da6e7d3e6359ddaf08df2c904c3f02c320 Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Fri, 18 Mar 2022 11:56:01 +0100 Subject: [PATCH 043/147] MueLu: test comparison of region & Richardson Both approaches, i.e. running the V-cycle in region format vs. running a Richardson iteration in composite format while calling the region hierarhcy, should deliver the same convergence history. Thist test now compares both residual histories. --- .../regionMG/test/structured/CMakeLists.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/muelu/research/regionMG/test/structured/CMakeLists.txt b/packages/muelu/research/regionMG/test/structured/CMakeLists.txt index 48b728ccb8ec..d70056c450aa 100644 --- a/packages/muelu/research/regionMG/test/structured/CMakeLists.txt +++ b/packages/muelu/research/regionMG/test/structured/CMakeLists.txt @@ -381,6 +381,25 @@ IF (${PACKAGE_NAME}_ENABLE_Tpetra AND ${PACKAGE_NAME}_ENABLE_Amesos2) OVERALL_NUM_MPI_PROCS 4 ) + TRIBITS_ADD_ADVANCED_TEST( + Structured_Region_Linear_Elasticity3D_Region_vs_Richardson_Tpetra_MPI_4_regression + TEST_0 + EXEC StructuredRegionDriver + ARGS --linAlgebra=Tpetra --xml=structured_linear_3dof.xml --matrixType=Elasticity3D --nx=10 --ny=10 --nz=10 --smootherIts=2 --convergence-log=Elasticity3D_Region_linear_4.log --solverType=region + NUM_MPI_PROCS 4 + TEST_1 + EXEC StructuredRegionDriver + ARGS --linAlgebra=Tpetra --xml=structured_linear_3dof.xml --matrixType=Elasticity3D --nx=10 --ny=10 --nz=10 --smootherIts=2 --convergence-log=Elasticity3D_Richardson_linear_4.log --solverType=Richardson + NUM_MPI_PROCS 4 + TEST_2 + CMND ${PYTHON_EXECUTABLE} + ARGS compare_residual_history.py Elasticity3D_Region_linear_4.log Elasticity3D_Richardson_linear_4.log 1.0e-12 + STANDARD_PASS_OUTPUT + FAIL_FAST + COMM serial mpi + OVERALL_NUM_MPI_PROCS 4 + ) + ENDIF() ENDIF() From 218339457e0d066afac1054204f1528c0f4b2836 Mon Sep 17 00:00:00 2001 From: Jacob Domagala Date: Fri, 18 Mar 2022 15:20:21 +0100 Subject: [PATCH 044/147] Panzer: Make Epetra optional (partially) for adapter-stk --- .../adapters-stk/example/CMakeLists.txt | 9 +- .../example/CurlLaplacianExample/main.cpp | 19 ++- .../example/MixedPoissonExample/main.cpp | 23 ++- .../src/Panzer_STK_ModelEvaluatorFactory.cpp | 4 + .../src/Panzer_STK_SetupLOWSFactory.cpp | 5 + .../adapters-stk/src/Panzer_STK_Utilities.cpp | 4 + .../adapters-stk/src/Panzer_STK_Utilities.hpp | 20 ++- .../Panzer_STK_PeriodicBC_Matcher_impl.hpp | 53 +++---- .../panzer/adapters-stk/test/CMakeLists.txt | 9 +- .../test/bcstrategy/CMakeLists.txt | 5 +- .../gather_scatter_evaluators/CMakeLists.txt | 14 +- .../scatter_field_evaluator.cpp | 58 +++---- .../initial_condition_builder/CMakeLists.txt | 28 ++-- .../test/model_evaluator/CMakeLists.txt | 2 +- .../model_evaluator/thyra_model_evaluator.cpp | 2 +- .../test/periodic_bcs/CMakeLists.txt | 81 +++++----- .../test/stk_connmngr/CMakeLists.txt | 16 +- .../stk_connmngr/tCubeHexMeshDOFManager.cpp | 6 - .../stk_connmngr/tDOFManager2_Orientation.cpp | 18 +-- .../stk_connmngr/tDOFManager2_SimpleTests.cpp | 79 +++++----- .../test/stk_connmngr/tSTKConnManager.cpp | 148 +++++++++--------- .../tSquareQuadMeshDOFManager.cpp | 134 ++++++++-------- .../tSquareQuadMeshDOFManager_edgetests.cpp | 12 +- .../stk_connmngr/tSquareTriMeshDOFManager.cpp | 106 ++++++------- .../test/stk_interface_test/CMakeLists.txt | 15 +- .../tCubeHexMeshFactory.cpp | 6 - .../tCubeTetMeshFactory.cpp | 6 - .../stk_interface_test/tExodusEdgeBlock.cpp | 6 - .../stk_interface_test/tExodusFaceBlock.cpp | 6 - .../tExodusReaderFactory.cpp | 8 +- .../test/stk_interface_test/tGhosting.cpp | 12 +- .../stk_interface_test/tLineMeshFactory.cpp | 30 ++-- .../stk_interface_test/tPamgenMeshFactory.cpp | 8 +- .../test/stk_interface_test/tSTKInterface.cpp | 123 +++++++-------- .../tSingleBlockCubeHexMeshFactory.cpp | 30 ++-- .../tSquareQuadMeshFactory.cpp | 6 - 36 files changed, 531 insertions(+), 580 deletions(-) diff --git a/packages/panzer/adapters-stk/example/CMakeLists.txt b/packages/panzer/adapters-stk/example/CMakeLists.txt index b65844a9822f..1ea02b3c6668 100644 --- a/packages/panzer/adapters-stk/example/CMakeLists.txt +++ b/packages/panzer/adapters-stk/example/CMakeLists.txt @@ -1,10 +1,13 @@ +IF(PANZER_HAVE_EPETRA) + ADD_SUBDIRECTORY(PoissonExample) + ADD_SUBDIRECTORY(assembly_engine) + ADD_SUBDIRECTORY(PoissonInterfaceExample) +ENDIF(PANZER_HAVE_EPETRA) + ADD_SUBDIRECTORY(square_mesh) -ADD_SUBDIRECTORY(PoissonExample) ADD_SUBDIRECTORY(CurlLaplacianExample) ADD_SUBDIRECTORY(MixedCurlLaplacianExample) ADD_SUBDIRECTORY(MixedPoissonExample) -ADD_SUBDIRECTORY(PoissonInterfaceExample) ADD_SUBDIRECTORY(PoissonInterfaceTpetra) -ADD_SUBDIRECTORY(assembly_engine) ADD_SUBDIRECTORY(main_driver) ADD_SUBDIRECTORY(ModelEvaluator) diff --git a/packages/panzer/adapters-stk/example/CurlLaplacianExample/main.cpp b/packages/panzer/adapters-stk/example/CurlLaplacianExample/main.cpp index 5a4cb115a24d..ba5d628b62c1 100644 --- a/packages/panzer/adapters-stk/example/CurlLaplacianExample/main.cpp +++ b/packages/panzer/adapters-stk/example/CurlLaplacianExample/main.cpp @@ -59,7 +59,7 @@ #include "Panzer_AssemblyEngine_TemplateManager.hpp" #include "Panzer_AssemblyEngine_TemplateBuilder.hpp" #include "Panzer_LinearObjFactory.hpp" -#include "Panzer_BlockedEpetraLinearObjFactory.hpp" + #include "Panzer_TpetraLinearObjFactory.hpp" #include "Panzer_DOFManagerFactory.hpp" #include "Panzer_FieldManagerBuilder.hpp" @@ -82,10 +82,11 @@ #include "Panzer_STK_Utilities.hpp" #include "Panzer_STK_ResponseEvaluatorFactory_SolutionWriter.hpp" -#include "Epetra_MpiComm.h" - +#ifdef PANZER_HAVE_EPETRA +#include "Panzer_BlockedEpetraLinearObjFactory.hpp" #include "EpetraExt_RowMatrixOut.h" #include "EpetraExt_VectorOut.h" +#endif #include "BelosPseudoBlockGmresSolMgr.hpp" #include "BelosTpetraAdapter.hpp" @@ -161,7 +162,7 @@ int main(int argc,char * argv[]) Teuchos::GlobalMPISession mpiSession(&argc,&argv); Kokkos::initialize(argc,argv); - RCP Comm = Teuchos::rcp(new Epetra_MpiComm(MPI_COMM_WORLD)); + Teuchos::RCP > comm = Teuchos::rcp(new Teuchos::MpiComm(MPI_COMM_WORLD)); Teuchos::FancyOStream out(Teuchos::rcpFromRef(std::cout)); out.setOutputToRootOnly(0); @@ -200,6 +201,12 @@ int main(int argc,char * argv[]) clp.setOption("basis-order",&basis_order); clp.setOption("output-filename",&output_filename); +#ifndef PANZER_HAVE_EPETRA + if(!useTpetra) { + throw std::runtime_error("Panzer is built without Epetra! Either use Panzer_ENABLE_Epetra=ON or run this example with `use-tpetra` flag"); + } +#endif + // parse commandline argument Teuchos::CommandLineProcessor::EParseCommandLineReturn r_parse= clp.parse( argc, argv ); if (r_parse == Teuchos::CommandLineProcessor::PARSE_HELP_PRINTED) return 0; @@ -338,6 +345,7 @@ int main(int argc,char * argv[]) // build the connection manager if(!useTpetra) { +#ifdef PANZER_HAVE_EPETRA const Teuchos::RCP conn_manager = Teuchos::rcp(new panzer_stk::STKConnManager(mesh)); panzer::DOFManagerFactory globalIndexerFactory; @@ -347,6 +355,7 @@ int main(int argc,char * argv[]) // construct some linear algebra object, build object to pass to evaluators linObjFactory = Teuchos::rcp(new panzer::BlockedEpetraLinearObjFactory(comm.getConst(),dofManager_int)); +#endif // PANZER_HAVE_EPETRA } else { const Teuchos::RCP conn_manager @@ -603,6 +612,7 @@ int main(int argc,char * argv[]) void solveEpetraSystem(panzer::LinearObjContainer & container) { +#ifdef PANZER_HAVE_EPETRA // convert generic linear object container to epetra container panzer::EpetraLinearObjContainer & ep_container = Teuchos::dyn_cast(container); @@ -629,6 +639,7 @@ void solveEpetraSystem(panzer::LinearObjContainer & container) // Therefore we have J*e=-J*u which implies e = -u // thus we will scale the solution vector ep_container.get_x()->Scale(-1.0); +#endif // PANZER_HAVE_EPETRA } void solveTpetraSystem(panzer::LinearObjContainer & container) diff --git a/packages/panzer/adapters-stk/example/MixedPoissonExample/main.cpp b/packages/panzer/adapters-stk/example/MixedPoissonExample/main.cpp index e4876b16e120..a6ee108322a4 100644 --- a/packages/panzer/adapters-stk/example/MixedPoissonExample/main.cpp +++ b/packages/panzer/adapters-stk/example/MixedPoissonExample/main.cpp @@ -59,7 +59,6 @@ #include "Panzer_AssemblyEngine_TemplateManager.hpp" #include "Panzer_AssemblyEngine_TemplateBuilder.hpp" #include "Panzer_LinearObjFactory.hpp" -#include "Panzer_BlockedEpetraLinearObjFactory.hpp" #include "Panzer_TpetraLinearObjFactory.hpp" #include "Panzer_DOFManagerFactory.hpp" #include "Panzer_FieldManagerBuilder.hpp" @@ -77,14 +76,18 @@ #include "Panzer_STK_CubeHexMeshFactory.hpp" #include "Panzer_STK_CubeTetMeshFactory.hpp" #include "Panzer_STK_SetupUtilities.hpp" -#include "Panzer_STK_Utilities.hpp" + #include "Panzer_STK_ResponseEvaluatorFactory_SolutionWriter.hpp" #include "Panzer_HierarchicParallelism.hpp" +#ifdef PANZER_HAVE_EPETRA +#include "Panzer_BlockedEpetraLinearObjFactory.hpp" #include "Epetra_MpiComm.h" - #include "EpetraExt_RowMatrixOut.h" #include "EpetraExt_VectorOut.h" +#include "Panzer_STK_Utilities.hpp" +#include "AztecOO.h" +#endif #include "BelosPseudoBlockGmresSolMgr.hpp" #include "BelosTpetraAdapter.hpp" @@ -94,7 +97,7 @@ #include "Example_ClosureModel_Factory_TemplateBuilder.hpp" #include "Example_EquationSetFactory.hpp" -#include "AztecOO.h" + #include @@ -129,7 +132,7 @@ int main(int argc,char * argv[]) Teuchos::GlobalMPISession mpiSession(&argc,&argv); Kokkos::initialize(argc,argv); - RCP Comm = Teuchos::rcp(new Epetra_MpiComm(MPI_COMM_WORLD)); + // RCP Comm = Teuchos::rcp(new Epetra_MpiComm(MPI_COMM_WORLD)); Teuchos::RCP > comm = Teuchos::rcp(new Teuchos::MpiComm(MPI_COMM_WORLD)); Teuchos::FancyOStream out(Teuchos::rcpFromRef(std::cout)); out.setOutputToRootOnly(0); @@ -171,6 +174,12 @@ int main(int argc,char * argv[]) if (r_parse == Teuchos::CommandLineProcessor::PARSE_HELP_PRINTED) return 0; if (r_parse != Teuchos::CommandLineProcessor::PARSE_SUCCESSFUL ) return -1; + if(!useTpetra){ +#ifndef PANZER_HAVE_EPETRA + throw std::runtime_error("Trying to run Panzer MixedPoisson Test with Epetra, but Epetra is disabled!"); +#endif + } + // cuda optimizations //////////////////////////////////////////////////// // Always use shared memory optimization for residual @@ -295,6 +304,7 @@ int main(int argc,char * argv[]) // build the connection manager if(!useTpetra) { +#ifdef PANZER_HAVE_EPETRA const Teuchos::RCP conn_manager = Teuchos::rcp(new panzer_stk::STKConnManager(mesh)); panzer::DOFManagerFactory globalIndexerFactory; @@ -304,6 +314,7 @@ int main(int argc,char * argv[]) // construct some linear algebra object, build object to pass to evaluators linObjFactory = Teuchos::rcp(new panzer::BlockedEpetraLinearObjFactory(comm.getConst(),dofManager_int)); +#endif } else { const Teuchos::RCP conn_manager = Teuchos::rcp(new panzer_stk::STKConnManager(mesh)); @@ -540,6 +551,7 @@ int main(int argc,char * argv[]) void solveEpetraSystem(panzer::LinearObjContainer & container) { +#ifdef PANZER_HAVE_EPETRA // convert generic linear object container to epetra container panzer::EpetraLinearObjContainer & ep_container = Teuchos::dyn_cast(container); @@ -570,6 +582,7 @@ void solveEpetraSystem(panzer::LinearObjContainer & container) // Therefore we have J*e=-J*u which implies e = -u // thus we will scale the solution vector ep_container.get_x()->Scale(-1.0); +#endif } void solveTpetraSystem(panzer::LinearObjContainer & container) diff --git a/packages/panzer/adapters-stk/src/Panzer_STK_ModelEvaluatorFactory.cpp b/packages/panzer/adapters-stk/src/Panzer_STK_ModelEvaluatorFactory.cpp index 70f6d62e8968..a9f1895e34a0 100644 --- a/packages/panzer/adapters-stk/src/Panzer_STK_ModelEvaluatorFactory.cpp +++ b/packages/panzer/adapters-stk/src/Panzer_STK_ModelEvaluatorFactory.cpp @@ -42,6 +42,8 @@ #include "PanzerAdaptersSTK_config.hpp" +#ifdef PANZER_HAVE_EPETRA + #include "Panzer_STK_ModelEvaluatorFactory.hpp" #include "Panzer_STK_ModelEvaluatorFactory_impl.hpp" @@ -50,3 +52,5 @@ namespace panzer_stk { template class ModelEvaluatorFactory; } + +#endif // PANZER_HAVE_EPETRA \ No newline at end of file diff --git a/packages/panzer/adapters-stk/src/Panzer_STK_SetupLOWSFactory.cpp b/packages/panzer/adapters-stk/src/Panzer_STK_SetupLOWSFactory.cpp index a407939574fa..ee205503cfca 100644 --- a/packages/panzer/adapters-stk/src/Panzer_STK_SetupLOWSFactory.cpp +++ b/packages/panzer/adapters-stk/src/Panzer_STK_SetupLOWSFactory.cpp @@ -41,6 +41,9 @@ // @HEADER #include "PanzerAdaptersSTK_config.hpp" + +#ifdef PANZER_HAVE_EPETRA + #include "Panzer_STK_SetupLOWSFactory.hpp" #include "Panzer_STK_ParameterListCallback.hpp" #include "Panzer_STK_ParameterListCallbackBlocked.hpp" @@ -526,3 +529,5 @@ namespace { return Teuchos::null; } } + +#endif // PANZER_HAVE_EPETRA \ No newline at end of file diff --git a/packages/panzer/adapters-stk/src/Panzer_STK_Utilities.cpp b/packages/panzer/adapters-stk/src/Panzer_STK_Utilities.cpp index 87915fbaf47f..e0046bad2523 100644 --- a/packages/panzer/adapters-stk/src/Panzer_STK_Utilities.cpp +++ b/packages/panzer/adapters-stk/src/Panzer_STK_Utilities.cpp @@ -42,6 +42,8 @@ #include "PanzerAdaptersSTK_config.hpp" +#ifdef PANZER_HAVE_EPETRA + #include "Panzer_STK_Utilities.hpp" #include "Panzer_GlobalIndexer.hpp" @@ -177,3 +179,5 @@ void build_local_ids(const panzer_stk::STK_Interface & mesh, } } + +#endif // PANZER_HAVE_EPETRA \ No newline at end of file diff --git a/packages/panzer/adapters-stk/src/Panzer_STK_Utilities.hpp b/packages/panzer/adapters-stk/src/Panzer_STK_Utilities.hpp index 72dff87490c0..46632c5f7fba 100644 --- a/packages/panzer/adapters-stk/src/Panzer_STK_Utilities.hpp +++ b/packages/panzer/adapters-stk/src/Panzer_STK_Utilities.hpp @@ -40,6 +40,8 @@ // *********************************************************************** // @HEADER +#ifdef PANZER_HAVE_EPETRA + #ifndef __Panzer_STK_Utilities_hpp__ #define __Panzer_STK_Utilities_hpp__ @@ -52,7 +54,7 @@ namespace panzer { class GlobalIndexer; } -namespace panzer_stk { +namespace panzer_stk { /** Write a vector to the cell data of a STK mesh. This will look up * the cell field prefix+fieldName+postfix, which is assumed @@ -70,18 +72,18 @@ void write_solution_data(const panzer::GlobalIndexer& dofMngr,panzer_stk::STK_In /** Using a container, compute the sorted permutation vector * do not modifiy the original container. * - * Motivated by this board on StackOverflow: + * Motivated by this board on StackOverflow: * http://stackoverflow.com/questions/4523220/sorting-a-vector-of-double-precision-reals-and-obtain-their-order - */ + */ template void sorted_permutation(const RAContainer & cont,std::vector & permutation,const Compare & comp); /** Using a container, compute the sorted permutation vector * do not modifiy the original container. * - * Motivated by this board on StackOverflow: + * Motivated by this board on StackOverflow: * http://stackoverflow.com/questions/4523220/sorting-a-vector-of-double-precision-reals-and-obtain-their-order - */ + */ template void sorted_permutation(const RAContainer & cont,std::vector & permutation); @@ -91,7 +93,7 @@ namespace panzer_stk { // utility class used by the sorted permutation objects template struct PermFunctor { - PermFunctor(const RAContainer & cont,const Compare & comp) + PermFunctor(const RAContainer & cont,const Compare & comp) : compare(comp), values(cont) {} PermFunctor(const PermFunctor & p) : compare(p.compare), values(p.values) {} @@ -108,9 +110,9 @@ struct PermFunctor { template void sorted_permutation(const RAContainer & cont,std::vector & permutation) -{ +{ std::less comp; - sorted_permutation(cont,permutation,comp); + sorted_permutation(cont,permutation,comp); } template @@ -128,3 +130,5 @@ void sorted_permutation(const RAContainer & cont,std::vector & perm } #endif + +#endif // PANZER_HAVE_EPETRA \ No newline at end of file diff --git a/packages/panzer/adapters-stk/src/stk_interface/Panzer_STK_PeriodicBC_Matcher_impl.hpp b/packages/panzer/adapters-stk/src/stk_interface/Panzer_STK_PeriodicBC_Matcher_impl.hpp index 4a6b07950a58..be1775f5899c 100644 --- a/packages/panzer/adapters-stk/src/stk_interface/Panzer_STK_PeriodicBC_Matcher_impl.hpp +++ b/packages/panzer/adapters-stk/src/stk_interface/Panzer_STK_PeriodicBC_Matcher_impl.hpp @@ -46,7 +46,6 @@ #include "Panzer_STK_Version.hpp" #include "PanzerAdaptersSTK_config.hpp" #include "Panzer_STK_Interface.hpp" -#include "Panzer_STK_Utilities.hpp" #include "Teuchos_FancyOStream.hpp" @@ -70,7 +69,7 @@ matchPeriodicSides(const std::string & left,const std::string & right, // 2. Match the global nodes on the "left" to locally owned nodes on the "right" // - only local work required // 3. If a processor requires a node on the left (if it is owned or ghosted) - // communicate matching conditions from the right boundary + // communicate matching conditions from the right boundary // // Note: The matching check could definitely be sped up with a sorting operation // Note: The communication could be done in a way that requires less global communication @@ -106,9 +105,9 @@ matchPeriodicSides(const std::string & left,const std::string & right, out.setOutputToRootOnly(-1); out << "Not all sides matched expect failure: \n" << e.what() << std::endl; - } + } - // Get the ids on the left required by this processor (they maybe ghosted), + // Get the ids on the left required by this processor (they maybe ghosted), // and using the matched ids computed above over all processors, find the // corrsponding node on the right boundary. ///////////////////////////////////////////////////////////////////////// @@ -117,11 +116,11 @@ matchPeriodicSides(const std::string & left,const std::string & right, // THE REQUEST LIST. THERE ALSO IS A REQUIREMENT OF PER PROC UNIQUENESS IN THE EPETRA // IMPORT. SO THERE IS SOME ADDITIONAL WORK DONE TO REMOVE REPEATED ENTRIES - // build reverse map + // build reverse map std::map > reverseMap; for(std::size_t i=0;i > locallyRequiredIds = getLocalSideIds(mesh,left,type_); std::vector saved_locallyRequiredIds = *locallyRequiredIds; // will be required // to check owner/ghostship @@ -133,12 +132,12 @@ matchPeriodicSides(const std::string & left,const std::string & right, std::size_t owned = ownedToMapped[i].first; std::size_t mapped = ownedToMapped[i].second; - std::vector::iterator itr + std::vector::iterator itr = std::find(locallyRequiredIds->begin(),locallyRequiredIds->end(),owned); if(itr!=locallyRequiredIds->end()) *itr = mapped; - else + else unusedOwnedToMapped.push_back(ownedToMapped[i]); } @@ -146,7 +145,7 @@ matchPeriodicSides(const std::string & left,const std::string & right, std::vector unique_locallyRequiredIds; { std::set s; - s.insert(locallyRequiredIds->begin(),locallyRequiredIds->end()); + s.insert(locallyRequiredIds->begin(),locallyRequiredIds->end()); unique_locallyRequiredIds.insert(unique_locallyRequiredIds.begin(),s.begin(),s.end()); } @@ -162,19 +161,19 @@ matchPeriodicSides(const std::string & left,const std::string & right, { // fill up set with current globally matched ids (not neccessarily owned/ghosted) std::set > gmi_set; - gmi_set.insert(globallyMatchedIds->begin(),globallyMatchedIds->end()); - - // for each globally matched ID, update IDs from the previous + gmi_set.insert(globallyMatchedIds->begin(),globallyMatchedIds->end()); + + // for each globally matched ID, update IDs from the previous // run (i.e. from ownedToMapped) using the reverseMap for(std::size_t i=0;isize();i++) { std::pair pair = (*globallyMatchedIds)[i]; const std::vector & others = reverseMap[pair.first]; - + // add in reverse map (note other[j] is guranteed to be local to this processor // if it was when ownedToMapped was passed in) - for(std::size_t j=0;jinsert(globallyMatchedIds->begin(),gmi_set.begin(),gmi_set.end()); } - // now you have a pair of ids that maps ids on the left required by this processor + // now you have a pair of ids that maps ids on the left required by this processor // to ids on the right globallyMatchedIds->insert(globallyMatchedIds->end(),unusedOwnedToMapped.begin(),unusedOwnedToMapped.end()); @@ -209,7 +208,7 @@ matchPeriodicSides(const std::string & left,const std::string & right, // 2. Match the global nodes on the "left" to locally owned nodes on the "right" // - only local work required // 3. If a processor requires a node on the left (if it is owned or ghosted) - // communicate matching conditions from the right boundary + // communicate matching conditions from the right boundary // // Note: The matching check could definitely be spead up with a sorting operation // Note: The communication could be done in a way that requires less global communication @@ -245,9 +244,9 @@ matchPeriodicSides(const std::string & left,const std::string & right, out.setOutputToRootOnly(-1); out << "Not all sides matched expect failure: \n" << e.what() << std::endl; - } + } - // Get the ids on the left required by this processor (they maybe ghosted), + // Get the ids on the left required by this processor (they maybe ghosted), // and using the matched ids computed above over all processors, find the // corrsponding node on the right boundary. ///////////////////////////////////////////////////////////////////////// @@ -257,9 +256,9 @@ matchPeriodicSides(const std::string & left,const std::string & right, Teuchos::RCP > > globallyMatchedIds = getGlobalPairing(*locallyRequiredIds,*locallyMatchedIds,mesh,failure); - // now you have a pair of ids that maps ids on the left required by this processor + // now you have a pair of ids that maps ids on the left required by this processor // to ids on the right - + return globallyMatchedIds; } @@ -274,7 +273,7 @@ getLocallyMatchedSideIds(const std::vector & side_ids, using Teuchos::Tuple; RCP > > result - = Teuchos::rcp(new std::vector >); + = Teuchos::rcp(new std::vector >); // grab local IDs and coordinates on this side ////////////////////////////////////////////////////////////////// @@ -292,12 +291,12 @@ getLocallyMatchedSideIds(const std::vector & side_ids, // do a slow search for the coordinates: this _can_ be sped // up! (considered searches in sorted ranges using the sorted_permutation function) //////////////////////////////////////////////////////// - for(std::size_t localNode=0;localNode & local_coord = local_side_coords[localNode]; // loop over globally distributed coordinates and find a match - for(std::size_t globalNode=0;globalNode & global_coord = side_coords[globalNode]; @@ -306,13 +305,13 @@ getLocallyMatchedSideIds(const std::vector & side_ids, checkProb = true; // processor? result->push_back(std::make_pair(global_gid,local_gid)); - side_flags[globalNode] = true; + side_flags[globalNode] = true; continue; } } } - // make sure you matched everything you can: If this throws...it can + // make sure you matched everything you can: If this throws...it can // cause the process to hang! TEUCHOS_TEST_FOR_EXCEPTION(checkProb,std::logic_error, "getLocallyMatchedSideIds: checkProb failed"); diff --git a/packages/panzer/adapters-stk/test/CMakeLists.txt b/packages/panzer/adapters-stk/test/CMakeLists.txt index 43769017db80..7a9fbdaf94a3 100644 --- a/packages/panzer/adapters-stk/test/CMakeLists.txt +++ b/packages/panzer/adapters-stk/test/CMakeLists.txt @@ -1,10 +1,13 @@ +IF (PANZER_HAVE_EPETRA) + ADD_SUBDIRECTORY(assembly_engine) + ADD_SUBDIRECTORY(field_manager_builder) + ADD_SUBDIRECTORY(model_evaluator) +ENDIF (PANZER_HAVE_EPETRA) + ADD_SUBDIRECTORY(stk_interface_test) ADD_SUBDIRECTORY(stk_connmngr) ADD_SUBDIRECTORY(panzer_workset_builder) -ADD_SUBDIRECTORY(field_manager_builder) ADD_SUBDIRECTORY(initial_condition_builder) -ADD_SUBDIRECTORY(assembly_engine) -ADD_SUBDIRECTORY(model_evaluator) ADD_SUBDIRECTORY(solver) ADD_SUBDIRECTORY(gather_scatter_evaluators) ADD_SUBDIRECTORY(periodic_bcs) diff --git a/packages/panzer/adapters-stk/test/bcstrategy/CMakeLists.txt b/packages/panzer/adapters-stk/test/bcstrategy/CMakeLists.txt index 18419aafbbb0..e423114e3bec 100644 --- a/packages/panzer/adapters-stk/test/bcstrategy/CMakeLists.txt +++ b/packages/panzer/adapters-stk/test/bcstrategy/CMakeLists.txt @@ -1,4 +1,5 @@ +IF(PANZER_HAVE_EPETRA) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) INCLUDE_DIRECTORIES(${PARENT_PACKAGE_SOURCE_DIR}/disc-fe/test/equation_set) @@ -14,7 +15,7 @@ SET(SOURCES user_app_BCStrategy_Neumann_Constant.hpp user_app_BCStrategy_Neumann_Constant_impl.hpp user_app_BCStrategy_Factory.hpp - ) + ) TRIBITS_ADD_EXECUTABLE_AND_TEST( bcstrategy @@ -27,3 +28,5 @@ TRIBITS_ADD_EXECUTABLE_AND_TEST( SOURCES bcstrategy_composite_factory.cpp ${UNIT_TEST_DRIVER} user_app_BCStrategy_Dirichlet_Constant.hpp user_app_BCStrategy_Dirichlet_Constant_impl.hpp user_app_BCStrategy_Factory_Physics1.hpp user_app_BCStrategy_Factory_Physics2.hpp NUM_MPI_PROCS 1 ) + +ENDIF(PANZER_HAVE_EPETRA) \ No newline at end of file diff --git a/packages/panzer/adapters-stk/test/gather_scatter_evaluators/CMakeLists.txt b/packages/panzer/adapters-stk/test/gather_scatter_evaluators/CMakeLists.txt index 558878272455..02651c69200d 100644 --- a/packages/panzer/adapters-stk/test/gather_scatter_evaluators/CMakeLists.txt +++ b/packages/panzer/adapters-stk/test/gather_scatter_evaluators/CMakeLists.txt @@ -9,15 +9,17 @@ INCLUDE_DIRECTORIES(${PACKAGE_SOURCE_DIR}/test/bcstrategy) SET(UNIT_TEST_DRIVER ${PANZER_UNIT_TEST_MAIN}) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - gs_evaluators - SOURCES gs_evaluators.cpp ${UNIT_TEST_DRIVER} - COMM serial mpi - NUM_MPI_PROCS 1 +IF (PANZER_HAVE_EPETRA) + TRIBITS_ADD_EXECUTABLE_AND_TEST( + gs_evaluators + SOURCES gs_evaluators.cpp ${UNIT_TEST_DRIVER} + COMM serial mpi + NUM_MPI_PROCS 1 ) +ENDIF(PANZER_HAVE_EPETRA) TRIBITS_ADD_EXECUTABLE_AND_TEST( - scatter_field_evaluator + scatter_field_evaluator SOURCES scatter_field_evaluator.cpp ${UNIT_TEST_DRIVER} COMM serial mpi NUM_MPI_PROCS 1 diff --git a/packages/panzer/adapters-stk/test/gather_scatter_evaluators/scatter_field_evaluator.cpp b/packages/panzer/adapters-stk/test/gather_scatter_evaluators/scatter_field_evaluator.cpp index 10c2354348c6..7250cadf177e 100644 --- a/packages/panzer/adapters-stk/test/gather_scatter_evaluators/scatter_field_evaluator.cpp +++ b/packages/panzer/adapters-stk/test/gather_scatter_evaluators/scatter_field_evaluator.cpp @@ -77,8 +77,6 @@ using Teuchos::rcp; #include "Phalanx_Evaluator_Macros.hpp" #include "Phalanx_MDField.hpp" -#include "Epetra_MpiComm.h" - #include // for get char #include #include @@ -130,7 +128,7 @@ namespace panzer { XCoordinate:: evaluateFields( typename Traits::EvalData workset) - { + { std::size_t numcells = workset.num_cells; int l_nodes = nodes; auto xcoord_v = PHX::as_view(xcoord); @@ -154,13 +152,14 @@ namespace panzer { const std::size_t workset_size = 20; linBasis = buildLinearBasis(workset_size); - Kokkos::push_finalize_hook( [=] { - linBasis = Teuchos::RCP(); + Kokkos::push_finalize_hook( [=] { + linBasis = Teuchos::RCP(); }); Teuchos::RCP mesh = buildMesh(20,20,true); - RCP Comm = Teuchos::rcp(new Epetra_MpiComm(MPI_COMM_WORLD)); + Teuchos::RCP > comm + = Teuchos::rcp_dynamic_cast >(Teuchos::DefaultComm::getComm()); Teuchos::RCP ipb = Teuchos::parameterList("Physics Blocks"); std::vector bcs; @@ -168,7 +167,7 @@ namespace panzer { Teuchos::ParameterList pl; pl.set("Data Layout",linBasis->functional); - Teuchos::RCP > fm = + Teuchos::RCP > fm = Teuchos::rcp(new PHX::FieldManager); fm->registerEvaluator(Teuchos::rcp(new XCoordinate(pl))); @@ -193,7 +192,7 @@ namespace panzer { std::map > block_ids_to_cell_topo; block_ids_to_cell_topo["eblock-0_0"] = mesh->getCellTopology("eblock-0_0"); - + Teuchos::RCP gd = panzer::createGlobalData(); panzer::buildPhysicsBlocks(block_ids_to_physics_ids, @@ -217,7 +216,7 @@ namespace panzer { Teuchos::RCP physics_block_one = panzer::findPhysicsBlock("eblock-0_0",physicsBlocks); Teuchos::RCP > volume_worksets = panzer_stk::buildWorksets(*mesh,physics_block_one->elementBlockID(), - physics_block_one->getWorksetNeeds()); + physics_block_one->getWorksetNeeds()); panzer::Traits::SD sd; sd.worksets_ = volume_worksets; @@ -232,7 +231,7 @@ namespace panzer { } fm->postEvaluate(0); - if(mesh->isWritable()) + if(mesh->isWritable()) mesh->writeToExodus("x-coord.exo"); } @@ -241,15 +240,16 @@ namespace panzer { const std::size_t workset_size = 5; linBasis = buildLinearBasis(workset_size); - Kokkos::push_finalize_hook( [=] { - linBasis = Teuchos::RCP(); + Kokkos::push_finalize_hook( [=] { + linBasis = Teuchos::RCP(); }); Teuchos::RCP mesh = buildMesh(5,5,false); - RCP Comm = Teuchos::rcp(new Epetra_MpiComm(MPI_COMM_WORLD)); + Teuchos::RCP > comm + = Teuchos::rcp_dynamic_cast >(Teuchos::DefaultComm::getComm()); - Teuchos::RCP topo = + Teuchos::RCP topo = Teuchos::rcp(new shards::CellTopology(shards::getCellTopologyData< shards::Quadrilateral<4> >())); panzer::CellData cellData(workset_size,topo); Teuchos::RCP intRule = Teuchos::rcp(new panzer::IntegrationRule(1,cellData)); @@ -258,7 +258,7 @@ namespace panzer { std::vector bcs; testInitialzation(ipb, bcs); - Teuchos::RCP > fm = + Teuchos::RCP > fm = Teuchos::rcp(new PHX::FieldManager); { Teuchos::ParameterList pl; @@ -277,7 +277,7 @@ namespace panzer { Teuchos::RCP > fieldNames = Teuchos::rcp(new std::vector); fieldNames->push_back("x-coord"); - + Teuchos::ParameterList pl; pl.set("Mesh",mesh); pl.set("IR",intRule); @@ -314,7 +314,7 @@ namespace panzer { std::map > block_ids_to_cell_topo; block_ids_to_cell_topo["eblock-0_0"] = mesh->getCellTopology("eblock-0_0"); - + Teuchos::RCP gd = panzer::createGlobalData(); panzer::buildPhysicsBlocks(block_ids_to_physics_ids, @@ -339,7 +339,7 @@ namespace panzer { Teuchos::RCP physics_block_one = panzer::findPhysicsBlock("eblock-0_0",physicsBlocks); Teuchos::RCP > volume_worksets = panzer_stk::buildWorksets(*mesh,physics_block_one->elementBlockID(), - physics_block_one->getWorksetNeeds()); + physics_block_one->getWorksetNeeds()); panzer::Traits::SD sd; @@ -355,18 +355,18 @@ namespace panzer { } fm->postEvaluate(0); - if(mesh->isWritable()) + if(mesh->isWritable()) mesh->writeToExodus("x-coord-cell.exo"); } Teuchos::RCP buildLinearBasis(std::size_t worksetSize) { - Teuchos::RCP topo = + Teuchos::RCP topo = Teuchos::rcp(new shards::CellTopology(shards::getCellTopologyData< shards::Quadrilateral<4> >())); panzer::CellData cellData(worksetSize,topo); - return Teuchos::rcp(new panzer::PureBasis("HGrad",1,cellData)); + return Teuchos::rcp(new panzer::PureBasis("HGrad",1,cellData)); } Teuchos::RCP buildMesh(int elemX,int elemY,bool solution) @@ -376,17 +376,17 @@ namespace panzer { pl->set("Y Blocks",1); pl->set("X Elements",elemX); pl->set("Y Elements",elemY); - + panzer_stk::SquareQuadMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildUncommitedMesh(MPI_COMM_WORLD); - + // add in some fields mesh->addSolutionField("x-coord","eblock-0_0"); if(!solution) mesh->addCellField("x-coord","eblock-0_0"); - factory.completeMeshConstruction(*mesh,MPI_COMM_WORLD); + factory.completeMeshConstruction(*mesh,MPI_COMM_WORLD); return mesh; } @@ -423,10 +423,10 @@ namespace panzer { double value = 5.0; Teuchos::ParameterList p; p.set("Value",value); - panzer::BC bc(bc_id, neumann, sideset_id, element_block_id, dof_name, + panzer::BC bc(bc_id, neumann, sideset_id, element_block_id, dof_name, strategy, p); bcs.push_back(bc); - } + } { std::size_t bc_id = 1; panzer::BCType neumann = BCT_Dirichlet; @@ -437,10 +437,10 @@ namespace panzer { double value = 5.0; Teuchos::ParameterList p; p.set("Value",value); - panzer::BC bc(bc_id, neumann, sideset_id, element_block_id, dof_name, + panzer::BC bc(bc_id, neumann, sideset_id, element_block_id, dof_name, strategy, p); bcs.push_back(bc); - } + } { std::size_t bc_id = 2; panzer::BCType neumann = BCT_Dirichlet; @@ -451,7 +451,7 @@ namespace panzer { double value = 5.0; Teuchos::ParameterList p; p.set("Value",value); - panzer::BC bc(bc_id, neumann, sideset_id, element_block_id, dof_name, + panzer::BC bc(bc_id, neumann, sideset_id, element_block_id, dof_name, strategy, p); bcs.push_back(bc); } diff --git a/packages/panzer/adapters-stk/test/initial_condition_builder/CMakeLists.txt b/packages/panzer/adapters-stk/test/initial_condition_builder/CMakeLists.txt index cfe1a9db3004..918113e4ec0f 100644 --- a/packages/panzer/adapters-stk/test/initial_condition_builder/CMakeLists.txt +++ b/packages/panzer/adapters-stk/test/initial_condition_builder/CMakeLists.txt @@ -14,20 +14,22 @@ TRIBITS_ADD_EXECUTABLE_AND_TEST( COMM serial mpi NUM_MPI_PROCS 1 ) - -TRIBITS_ADD_EXECUTABLE_AND_TEST( - initial_condition_builder2 - SOURCES initial_condition_builder2.cpp user_app_STKClosureModel_Factory.hpp user_app_STKClosureModel_Factory_impl.hpp user_app_STKClosureModel_Factory_TemplateBuilder.hpp ${UNIT_TEST_DRIVER} - COMM serial mpi - NUM_MPI_PROCS 2 - ) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - initial_condition_control - SOURCES initial_condition_control.cpp user_app_STKClosureModel_Factory.hpp user_app_STKClosureModel_Factory_impl.hpp user_app_STKClosureModel_Factory_TemplateBuilder.hpp ${UNIT_TEST_DRIVER} - COMM serial mpi - NUM_MPI_PROCS 2 - ) +IF (PANZER_HAVE_EPETRA) + TRIBITS_ADD_EXECUTABLE_AND_TEST( + initial_condition_builder2 + SOURCES initial_condition_builder2.cpp user_app_STKClosureModel_Factory.hpp user_app_STKClosureModel_Factory_impl.hpp user_app_STKClosureModel_Factory_TemplateBuilder.hpp ${UNIT_TEST_DRIVER} + COMM serial mpi + NUM_MPI_PROCS 2 + ) + + TRIBITS_ADD_EXECUTABLE_AND_TEST( + initial_condition_control + SOURCES initial_condition_control.cpp user_app_STKClosureModel_Factory.hpp user_app_STKClosureModel_Factory_impl.hpp user_app_STKClosureModel_Factory_TemplateBuilder.hpp ${UNIT_TEST_DRIVER} + COMM serial mpi + NUM_MPI_PROCS 2 + ) +ENDIF(PANZER_HAVE_EPETRA) TRIBITS_COPY_FILES_TO_BINARY_DIR(ic_builder2_files SOURCE_FILES block-decomp.exo block-decomp.exo.2.0 block-decomp.exo.2.1 diff --git a/packages/panzer/adapters-stk/test/model_evaluator/CMakeLists.txt b/packages/panzer/adapters-stk/test/model_evaluator/CMakeLists.txt index 0865f2d448a4..f188d5060e21 100644 --- a/packages/panzer/adapters-stk/test/model_evaluator/CMakeLists.txt +++ b/packages/panzer/adapters-stk/test/model_evaluator/CMakeLists.txt @@ -37,7 +37,7 @@ TRIBITS_ADD_EXECUTABLE_AND_TEST( ) TRIBITS_ADD_EXECUTABLE_AND_TEST( - response_residual + response_residual SOURCES response_residual.cpp ${UNIT_TEST_DRIVER} COMM serial mpi NUM_MPI_PROCS 2 diff --git a/packages/panzer/adapters-stk/test/model_evaluator/thyra_model_evaluator.cpp b/packages/panzer/adapters-stk/test/model_evaluator/thyra_model_evaluator.cpp index d2d9f4f3fd85..223673cfc999 100644 --- a/packages/panzer/adapters-stk/test/model_evaluator/thyra_model_evaluator.cpp +++ b/packages/panzer/adapters-stk/test/model_evaluator/thyra_model_evaluator.cpp @@ -87,7 +87,7 @@ using Teuchos::rcp; #include "user_app_ClosureModel_Factory_TemplateBuilder.hpp" #include "user_app_BCStrategy_Factory.hpp" -#include "Epetra_MpiComm.h" +// #include "Epetra_MpiComm.h" #include "Teuchos_DefaultMpiComm.hpp" #include "Teuchos_OpaqueWrapper.hpp" diff --git a/packages/panzer/adapters-stk/test/periodic_bcs/CMakeLists.txt b/packages/panzer/adapters-stk/test/periodic_bcs/CMakeLists.txt index e4ff79bd8eb9..fbec63aaae9d 100644 --- a/packages/panzer/adapters-stk/test/periodic_bcs/CMakeLists.txt +++ b/packages/panzer/adapters-stk/test/periodic_bcs/CMakeLists.txt @@ -1,41 +1,44 @@ +IF(PANZER_HAVE_EPETRA) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -SET(UNIT_TEST_DRIVER - ${PANZER_UNIT_TEST_MAIN}) - -TRIBITS_ADD_EXECUTABLE_AND_TEST( - periodic_bcs - SOURCES periodic_bcs.cpp ${UNIT_TEST_DRIVER} - COMM serial mpi - NUM_MPI_PROCS 4 - ) - -TRIBITS_ADD_EXECUTABLE_AND_TEST( - periodic_mesh - SOURCES periodic_mesh.cpp ${UNIT_TEST_DRIVER} - COMM serial mpi - NUM_MPI_PROCS 2 - ) - -# TRIBITS_ADD_EXECUTABLE_AND_TEST( -# periodic_mesh_nosubcells -# SOURCES periodic_mesh_nosubcells.cpp ${UNIT_TEST_DRIVER} -# COMM serial mpi -# NUM_MPI_PROCS 1 -# ) - -TRIBITS_ADD_EXECUTABLE_AND_TEST( - periodic_32bit_int_limit - SOURCES periodic_32bit_int_limit.cpp ${UNIT_TEST_DRIVER} - COMM serial mpi - NUM_MPI_PROCS 2 - ) - -TRIBITS_COPY_FILES_TO_BINARY_DIR(periodic_32bit_int_limit_files - SOURCE_FILES periodic_32bit_int_limit.jou periodic_32bit_int_limit.exo README.txt - SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/" - DEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/" - EXEDEPS periodic_32bit_int_limit - ) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + + SET(UNIT_TEST_DRIVER + ${PANZER_UNIT_TEST_MAIN}) + + TRIBITS_ADD_EXECUTABLE_AND_TEST( + periodic_bcs + SOURCES periodic_bcs.cpp ${UNIT_TEST_DRIVER} + COMM serial mpi + NUM_MPI_PROCS 4 + ) + + TRIBITS_ADD_EXECUTABLE_AND_TEST( + periodic_mesh + SOURCES periodic_mesh.cpp ${UNIT_TEST_DRIVER} + COMM serial mpi + NUM_MPI_PROCS 2 + ) + + # TRIBITS_ADD_EXECUTABLE_AND_TEST( + # periodic_mesh_nosubcells + # SOURCES periodic_mesh_nosubcells.cpp ${UNIT_TEST_DRIVER} + # COMM serial mpi + # NUM_MPI_PROCS 1 + # ) + + TRIBITS_ADD_EXECUTABLE_AND_TEST( + periodic_32bit_int_limit + SOURCES periodic_32bit_int_limit.cpp ${UNIT_TEST_DRIVER} + COMM serial mpi + NUM_MPI_PROCS 2 + ) + + TRIBITS_COPY_FILES_TO_BINARY_DIR(periodic_32bit_int_limit_files + SOURCE_FILES periodic_32bit_int_limit.jou periodic_32bit_int_limit.exo README.txt + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/" + DEST_DIR "${CMAKE_CURRENT_BINARY_DIR}/" + EXEDEPS periodic_32bit_int_limit + ) + +ENDIF(PANZER_HAVE_EPETRA) diff --git a/packages/panzer/adapters-stk/test/stk_connmngr/CMakeLists.txt b/packages/panzer/adapters-stk/test/stk_connmngr/CMakeLists.txt index 70b7a47b1a13..1215434e650c 100644 --- a/packages/panzer/adapters-stk/test/stk_connmngr/CMakeLists.txt +++ b/packages/panzer/adapters-stk/test/stk_connmngr/CMakeLists.txt @@ -25,7 +25,7 @@ TRIBITS_ADD_EXECUTABLE_AND_TEST( NUM_MPI_PROCS 2 COMM serial mpi ) - + TRIBITS_ADD_EXECUTABLE_AND_TEST( tSquareTriMeshDOFManager SOURCES tSquareTriMeshDOFManager.cpp ${UNIT_TEST_DRIVER} @@ -33,12 +33,14 @@ TRIBITS_ADD_EXECUTABLE_AND_TEST( COMM serial mpi ) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - tEpetraLinObjFactory - SOURCES tEpetraLinearObjFactory.cpp ${UNIT_TEST_DRIVER} - NUM_MPI_PROCS 2 - COMM serial mpi - ) +IF (PANZER_HAVE_EPETRA) + TRIBITS_ADD_EXECUTABLE_AND_TEST( + tEpetraLinObjFactory + SOURCES tEpetraLinearObjFactory.cpp ${UNIT_TEST_DRIVER} + NUM_MPI_PROCS 2 + COMM serial mpi + ) +ENDIF (PANZER_HAVE_EPETRA) TRIBITS_ADD_EXECUTABLE_AND_TEST( tCubeHexMeshDOFManager diff --git a/packages/panzer/adapters-stk/test/stk_connmngr/tCubeHexMeshDOFManager.cpp b/packages/panzer/adapters-stk/test/stk_connmngr/tCubeHexMeshDOFManager.cpp index 8610e9a2ffc6..178e057da1cc 100644 --- a/packages/panzer/adapters-stk/test/stk_connmngr/tCubeHexMeshDOFManager.cpp +++ b/packages/panzer/adapters-stk/test/stk_connmngr/tCubeHexMeshDOFManager.cpp @@ -57,12 +57,6 @@ #include "Intrepid2_HGRAD_HEX_C1_FEM.hpp" #include "Intrepid2_HGRAD_HEX_C2_FEM.hpp" -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - typedef Kokkos::DynRankView FieldContainer; using Teuchos::RCP; diff --git a/packages/panzer/adapters-stk/test/stk_connmngr/tDOFManager2_Orientation.cpp b/packages/panzer/adapters-stk/test/stk_connmngr/tDOFManager2_Orientation.cpp index 5c6dd073f808..d1a3da77e86e 100644 --- a/packages/panzer/adapters-stk/test/stk_connmngr/tDOFManager2_Orientation.cpp +++ b/packages/panzer/adapters-stk/test/stk_connmngr/tDOFManager2_Orientation.cpp @@ -59,12 +59,6 @@ #include "Intrepid2_HCURL_QUAD_I1_FEM.hpp" #include "Intrepid2_HDIV_QUAD_I1_FEM.hpp" -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - typedef Kokkos::DynRankView FieldContainer; using Teuchos::RCP; @@ -84,7 +78,7 @@ Teuchos::RCP buildQuadMesh(stk::ParallelMachine comm,int xe panzer_stk::SquareQuadMeshFactory meshFact; meshFact.setParameterList(Teuchos::rcpFromRef(pl)); - + Teuchos::RCP mesh = meshFact.buildMesh(comm); return Teuchos::rcp(new panzer_stk::STKConnManager(mesh)); } @@ -115,9 +109,9 @@ TEUCHOS_UNIT_TEST(tDOFManager_Orientation, buildTest_quad_edge_orientations) TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternC1 + RCP patternC1 = buildFieldPattern >(); - RCP patternI1 + RCP patternI1 = buildFieldPattern >(); RCP patternDIV = buildFieldPattern >(); @@ -137,7 +131,7 @@ TEUCHOS_UNIT_TEST(tDOFManager_Orientation, buildTest_quad_edge_orientations) dofManager->addField("e",patternDIV); dofManager->buildGlobalUnknowns(); - + const std::vector & u_offsets = dofManager->getGIDFieldOffsets("eblock-0_0",dofManager->getFieldNum("u")); const std::vector & b_offsets = dofManager->getGIDFieldOffsets("eblock-0_0",dofManager->getFieldNum("b")); const std::vector & e_offsets = dofManager->getGIDFieldOffsets("eblock-0_0",dofManager->getFieldNum("e")); @@ -262,7 +256,7 @@ TEUCHOS_UNIT_TEST(tDOFManager_Orientation, buildTest_quad_edge_orientations2) TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternI1 + RCP patternI1 = buildFieldPattern >(); RCP connManager = buildQuadMesh(Comm,2,2,1,1); @@ -335,7 +329,7 @@ TEUCHOS_UNIT_TEST(tDOFManager_Orientation, buildTest_quad_edge_orientations_fail TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternI1 + RCP patternI1 = buildFieldPattern >(); RCP connManager = buildQuadMesh(Comm,2,2,1,1); diff --git a/packages/panzer/adapters-stk/test/stk_connmngr/tDOFManager2_SimpleTests.cpp b/packages/panzer/adapters-stk/test/stk_connmngr/tDOFManager2_SimpleTests.cpp index f67fea7a6ce7..6339053f79e3 100644 --- a/packages/panzer/adapters-stk/test/stk_connmngr/tDOFManager2_SimpleTests.cpp +++ b/packages/panzer/adapters-stk/test/stk_connmngr/tDOFManager2_SimpleTests.cpp @@ -84,11 +84,6 @@ #include "Panzer_DOFManager.hpp" -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" - #include "mpi.h" -#endif - #include using Teuchos::RCP; @@ -105,8 +100,8 @@ namespace { pl->set("Y Blocks",2); pl->set("X Elements",4); pl->set("Y Elements",4); - - panzer_stk::SquareQuadMeshFactory factory; + + panzer_stk::SquareQuadMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); RCP conn = rcp(new panzer_stk::STKConnManager(mesh)); @@ -116,7 +111,7 @@ namespace { my_DOFManager->setConnManager(conn,MPI_COMM_WORLD); RCP> basis = Teuchos::rcp(new Intrepid2::Basis_HGRAD_QUAD_C1_FEM); - + RCP< const panzer::FieldPattern> pattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis)); std::vector names; @@ -144,9 +139,9 @@ namespace { TEST_EQUALITY(my_DOFManager->getNumFields(), 3); - const std::vector & vel_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",0); - const std::vector & tem_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",1); - const std::vector & rad_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",2); + const std::vector & vel_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",0); + const std::vector & tem_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",1); + const std::vector & rad_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",2); TEST_EQUALITY(vel_offests.size(),tem_offests.size()); TEST_EQUALITY(tem_offests.size(),rad_offests.size()); @@ -159,8 +154,8 @@ namespace { pl->set("Y Blocks",2); pl->set("X Elements",4); pl->set("Y Elements",4); - - panzer_stk::SquareQuadMeshFactory factory; + + panzer_stk::SquareQuadMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); RCP conn = rcp(new panzer_stk::STKConnManager(mesh)); @@ -170,7 +165,7 @@ namespace { my_DOFManager->setConnManager(conn,MPI_COMM_WORLD); RCP > basis = Teuchos::rcp(new Intrepid2::Basis_HGRAD_QUAD_C1_FEM); - + RCP< const panzer::FieldPattern> pattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis)); my_DOFManager->setConnManager(conn, MPI_COMM_WORLD); @@ -312,8 +307,8 @@ namespace { pl->set("Y Blocks",2); pl->set("X Elements",4); pl->set("Y Elements",4); - - panzer_stk::SquareQuadMeshFactory factory; + + panzer_stk::SquareQuadMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); RCP conn = rcp(new panzer_stk::STKConnManager(mesh)); @@ -323,7 +318,7 @@ namespace { my_DOFManager->setConnManager(conn,MPI_COMM_WORLD); RCP > basis = Teuchos::rcp(new Intrepid2::Basis_HGRAD_QUAD_C1_FEM); - + RCP< const panzer::FieldPattern> pattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis)); my_DOFManager->setConnManager(conn, MPI_COMM_WORLD); @@ -354,15 +349,15 @@ namespace { } } - TEUCHOS_UNIT_TEST( DOFManager_tests, gidsAreSet) + TEUCHOS_UNIT_TEST( DOFManager_tests, gidsAreSet) { RCP pl = rcp(new Teuchos::ParameterList); pl->set("X Blocks",2); pl->set("Y Blocks",2); pl->set("X Elements",4); pl->set("Y Elements",4); - - panzer_stk::SquareQuadMeshFactory factory; + + panzer_stk::SquareQuadMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); RCP conn = rcp(new panzer_stk::STKConnManager(mesh)); @@ -372,7 +367,7 @@ namespace { my_DOFManager->setConnManager(conn,MPI_COMM_WORLD); RCP > basis = Teuchos::rcp(new Intrepid2::Basis_HGRAD_QUAD_C1_FEM); - + RCP< const panzer::FieldPattern> pattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis)); std::vector names; @@ -413,8 +408,8 @@ namespace { pl->set("Y Blocks",1); pl->set("X Elements",4); pl->set("Y Elements",2); - - panzer_stk::SquareQuadMeshFactory factory; + + panzer_stk::SquareQuadMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); RCP conn = rcp(new panzer_stk::STKConnManager(mesh)); @@ -424,7 +419,7 @@ namespace { my_DOFManager->setConnManager(conn, MPI_COMM_WORLD); RCP > basis = Teuchos::rcp(new Intrepid2::Basis_HGRAD_QUAD_C1_FEM); - + RCP< const panzer::FieldPattern> pattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis)); std::vector names; @@ -490,8 +485,8 @@ namespace { pl->set("X Elements",4); pl->set("Y Elements",2); pl->set("Z Elements",2); - - panzer_stk::CubeTetMeshFactory factory; + + panzer_stk::CubeTetMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); RCP conn = rcp(new panzer_stk::STKConnManager(mesh)); @@ -502,7 +497,7 @@ namespace { RCP > basis = Teuchos::rcp(new Intrepid2::Basis_HGRAD_TET_C1_FEM); RCP > secbasis = Teuchos::rcp(new Intrepid2::Basis_HCURL_TET_I1_FEM); - + RCP< const panzer::FieldPattern> pattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis)); RCP< const panzer::FieldPattern> secpattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(secbasis)); @@ -540,8 +535,8 @@ namespace { pl->set("X Elements",4); pl->set("Y Elements",2); pl->set("Z Elements",2); - - panzer_stk::CubeTetMeshFactory factory; + + panzer_stk::CubeTetMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); RCP conn = rcp(new panzer_stk::STKConnManager(mesh)); @@ -552,7 +547,7 @@ namespace { RCP > basis = Teuchos::rcp(new Intrepid2::Basis_HGRAD_TET_C1_FEM); RCP > secbasis = Teuchos::rcp(new Intrepid2::Basis_HCURL_TET_I1_FEM); - + RCP< const panzer::FieldPattern> pattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis)); RCP< const panzer::FieldPattern> secpattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(secbasis)); @@ -595,8 +590,8 @@ namespace { pl->set("X Elements",4); pl->set("Y Elements",2); pl->set("Z Elements",2); - - panzer_stk::CubeTetMeshFactory factory; + + panzer_stk::CubeTetMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); RCP conn = rcp(new panzer_stk::STKConnManager(mesh)); @@ -607,7 +602,7 @@ namespace { RCP > basis = Teuchos::rcp(new Intrepid2::Basis_HGRAD_TET_C1_FEM); RCP > secbasis = Teuchos::rcp(new Intrepid2::Basis_HCURL_TET_I1_FEM); - + RCP< const panzer::FieldPattern> pattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis)); RCP< const panzer::FieldPattern> secpattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(secbasis)); @@ -662,16 +657,16 @@ namespace { } - - TEUCHOS_UNIT_TEST( DOFManager_tests, multiBloc) + + TEUCHOS_UNIT_TEST( DOFManager_tests, multiBloc) { RCP pl = rcp(new Teuchos::ParameterList); pl->set("X Blocks",1); pl->set("Y Blocks",2); pl->set("X Elements",5); pl->set("Y Elements",5); - - panzer_stk::SquareQuadMeshFactory factory; + + panzer_stk::SquareQuadMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); RCP conn = rcp(new panzer_stk::STKConnManager(mesh)); @@ -681,7 +676,7 @@ namespace { my_DOFManager->setConnManager(conn, MPI_COMM_WORLD); RCP > basis = Teuchos::rcp(new Intrepid2::Basis_HGRAD_QUAD_C1_FEM); - + RCP< const panzer::FieldPattern> pattern = Teuchos::rcp(new panzer::Intrepid2FieldPattern(basis)); std::vector names; @@ -705,9 +700,9 @@ namespace { TEST_EQUALITY(my_DOFManager->getNumFields(), 3); - //const std::vector & vel_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",0); - //const std::vector & tem_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",1); - //const std::vector & rad_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",2); + //const std::vector & vel_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",0); + //const std::vector & tem_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",1); + //const std::vector & rad_offests = my_DOFManager->getGIDFieldOffsets("eblock-0_0",2); TEST_ASSERT(my_DOFManager->fieldInBlock("Velocity","eblock-0_0")); TEST_ASSERT(!my_DOFManager->fieldInBlock("Velocity","eblock-0_1")); TEST_ASSERT(my_DOFManager->fieldInBlock("Temperature","eblock-0_1")); @@ -720,4 +715,4 @@ namespace { } -} /*generic namespace*/ +} /*generic namespace*/ diff --git a/packages/panzer/adapters-stk/test/stk_connmngr/tSTKConnManager.cpp b/packages/panzer/adapters-stk/test/stk_connmngr/tSTKConnManager.cpp index 5c7e2813408e..d5190a024d12 100644 --- a/packages/panzer/adapters-stk/test/stk_connmngr/tSTKConnManager.cpp +++ b/packages/panzer/adapters-stk/test/stk_connmngr/tSTKConnManager.cpp @@ -58,12 +58,6 @@ #include "Intrepid2_HGRAD_QUAD_C1_FEM.hpp" #include "Intrepid2_HGRAD_QUAD_C2_FEM.hpp" -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - using Teuchos::RCP; using Teuchos::rcp; @@ -83,7 +77,7 @@ Teuchos::RCP build2DMesh(int xElements,int yElements,int xBlocks, SquareQuadMeshFactory factory; factory.setParameterList(pl); - + Teuchos::RCP meshPtr = factory.buildMesh(MPI_COMM_WORLD); return meshPtr; @@ -121,7 +115,7 @@ TEUCHOS_UNIT_TEST(tSTKConnManager, 2_blocks) RCP mesh = build2DMesh(2,1,2,1); TEST_ASSERT(mesh!=Teuchos::null); - RCP fp + RCP fp = buildFieldPattern >(); STKConnManager connMngr(mesh); @@ -140,7 +134,7 @@ TEUCHOS_UNIT_TEST(tSTKConnManager, 2_blocks) std::string blockId = elementBlockIds[blk]; const std::vector & elementBlock = connMngr.getElementBlock(blockId); for(std::size_t elmt=0;elmt & elementBlock = connMngr.getNeighborElementBlock(elementBlockIds[blk]); for(std::size_t elmt=0;elmt mesh = build2DMesh(5,5,1,1); TEST_ASSERT(mesh!=Teuchos::null); - RCP fp + RCP fp = buildFieldPattern >(); STKConnManager connMngr(mesh); @@ -259,18 +253,18 @@ TEUCHOS_UNIT_TEST(tSTKConnManager, single_block_2d) // test connectivities ///////////////////////////////////////////////////////////// - TEST_EQUALITY(connMngr.getConnectivitySize(9),4); - TEST_EQUALITY(connMngr.getConnectivitySize(8),4); + TEST_EQUALITY(connMngr.getConnectivitySize(9),4); + TEST_EQUALITY(connMngr.getConnectivitySize(8),4); + - std::size_t localId; if(myRank==0) localId = mesh->elementLocalId(17); else localId = mesh->elementLocalId(20); - + { - int conn_true[4]; + int conn_true[4]; if(numProcs==1) { conn_true[0] = 20; conn_true[1] = 21; @@ -290,7 +284,7 @@ TEUCHOS_UNIT_TEST(tSTKConnManager, single_block_2d) conn_true[3] = 29; } else { - TEST_ASSERT(false); + TEST_ASSERT(false); } const auto * conn = connMngr.getConnectivity(localId); @@ -317,7 +311,7 @@ TEUCHOS_UNIT_TEST(tSTKConnManager, noConnectivityClone) RCP fp_hgrad = buildFieldPattern >(); - RCP fp_const + RCP fp_const = buildConstantFieldPattern(*ct); STKConnManager connMngr_const(mesh); @@ -331,39 +325,39 @@ TEUCHOS_UNIT_TEST(tSTKConnManager, noConnectivityClone) { // did we get the element block correct? ///////////////////////////////////////////////////////////// - + TEST_EQUALITY(connMngr_const.numElementBlocks(),1); - + const std::vector & elementBlock = connMngr_const.getElementBlock("eblock-0_0"); std::vector nc_elementBlock = elementBlock; if(numProcs==1) { TEST_EQUALITY(elementBlock.size(),25); } else if(numProcs==2 && myRank==0) { TEST_EQUALITY(elementBlock.size(),15); } else if(numProcs==2 && myRank==1) { TEST_EQUALITY(elementBlock.size(),10); } else { TEST_ASSERT(false); } - + // check that the local elements are correctly numbered std::sort(nc_elementBlock.begin(),nc_elementBlock.end()); bool check_local_blocks_passed = true; for(std::size_t i=0;ielementLocalId(17); else localId = mesh->elementLocalId(20); - + { - int conn_true[1]; + int conn_true[1]; if(numProcs==1) { conn_true[0] = 16; } @@ -374,52 +368,52 @@ TEUCHOS_UNIT_TEST(tSTKConnManager, noConnectivityClone) conn_true[0] = 19; } else { - TEST_ASSERT(false); + TEST_ASSERT(false); } - + const auto * conn = connMngr_const.getConnectivity(localId); for(std::size_t i=0;(int) inumElementBlocks(),1); - + const std::vector & elementBlock = connMngr_hgrad->getElementBlock("eblock-0_0"); std::vector nc_elementBlock = elementBlock; if(numProcs==1) { TEST_EQUALITY(elementBlock.size(),25); } else if(numProcs==2 && myRank==0) { TEST_EQUALITY(elementBlock.size(),15); } else if(numProcs==2 && myRank==1) { TEST_EQUALITY(elementBlock.size(),10); } else { TEST_ASSERT(false); } - + // check that the local elements are correctly numbered std::sort(nc_elementBlock.begin(),nc_elementBlock.end()); bool check_local_blocks_passed = true; for(std::size_t i=0;igetBlockId(9),"eblock-0_0"); - + // test connectivities ///////////////////////////////////////////////////////////// - TEST_EQUALITY(connMngr_hgrad->getConnectivitySize(9),4); - TEST_EQUALITY(connMngr_hgrad->getConnectivitySize(8),4); - - + TEST_EQUALITY(connMngr_hgrad->getConnectivitySize(9),4); + TEST_EQUALITY(connMngr_hgrad->getConnectivitySize(8),4); + + std::size_t localId; if(myRank==0) localId = mesh->elementLocalId(17); else localId = mesh->elementLocalId(20); - + { - int conn_true[4]; + int conn_true[4]; if(numProcs==1) { conn_true[0] = 20; conn_true[1] = 21; @@ -439,9 +433,9 @@ TEUCHOS_UNIT_TEST(tSTKConnManager, noConnectivityClone) conn_true[3] = 29; } else { - TEST_ASSERT(false); + TEST_ASSERT(false); } - + const auto * conn = connMngr_hgrad->getConnectivity(localId); for(std::size_t i=0;(int) igetConnectivitySize(localId);i++) TEST_EQUALITY(conn[i],conn_true[i]-1); @@ -460,7 +454,7 @@ TEUCHOS_UNIT_TEST(tSTKConnManager, four_block_2d) RCP mesh = build2DMesh(2,2,2,2); // 4x4 elements TEST_ASSERT(mesh!=Teuchos::null); - RCP fp + RCP fp = buildFieldPattern >(); STKConnManager connMngr(mesh); @@ -481,14 +475,14 @@ TEUCHOS_UNIT_TEST(tSTKConnManager, four_block_2d) std::vector nc_elementBlock = elementBlock; if(numProcs==1) { TEST_EQUALITY(elementBlock.size(),4); } else if(numProcs==2) { TEST_EQUALITY(elementBlock.size(),2); } - + bool check_blockid_lookup = true; for(std::size_t i=0;i FieldContainer; using Teuchos::RCP; @@ -83,7 +77,7 @@ Teuchos::RCP buildQuadMesh(stk::ParallelMachine comm,int xe panzer_stk::SquareQuadMeshFactory meshFact; meshFact.setParameterList(Teuchos::rcpFromRef(pl)); - + Teuchos::RCP mesh = meshFact.buildMesh(comm); return Teuchos::rcp(new panzer_stk::STKConnManager(mesh)); } @@ -113,7 +107,7 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, buildTest_quad) TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternC1 + RCP patternC1 = buildFieldPattern >(); RCP connManager = buildQuadMesh(Comm,2,2,1,1); @@ -160,11 +154,11 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, buildTest_quad) TEST_EQUALITY(gids[9],6); TEST_EQUALITY(gids[10],7); TEST_EQUALITY(gids[11],8); for(std::size_t i=0;igetElementGIDs(1,gids); TEST_EQUALITY(gids.size(),12); TEST_EQUALITY(gids[0],6); TEST_EQUALITY(gids[1],7); TEST_EQUALITY(gids[2],8); @@ -173,9 +167,9 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, buildTest_quad) TEST_EQUALITY(gids[9],12); TEST_EQUALITY(gids[10],13); TEST_EQUALITY(gids[11],14); for(std::size_t i=0;igetElementGIDs(1,gids); TEST_EQUALITY(gids.size(),12); TEST_EQUALITY(gids[0],9); TEST_EQUALITY(gids[1],10); TEST_EQUALITY(gids[2],11); @@ -202,9 +196,9 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, buildTest_quad) TEST_EQUALITY(gids[9],15); TEST_EQUALITY(gids[10],16); TEST_EQUALITY(gids[11],17); for(std::size_t i=0;i patternC1 + RCP patternC1 = buildFieldPattern >(); RCP connManager = buildQuadMesh(Comm,2,2,1,1); @@ -265,17 +259,17 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, field_order) dofManager->getElementGIDs(0,gids); TEST_EQUALITY(gids.size(),12); for(std::size_t i=0;igetElementGIDs(1,gids); TEST_EQUALITY(gids.size(),12); for(std::size_t i=0;igetElementGIDs(0,gids); TEST_EQUALITY(gids.size(),12); for(std::size_t i=0;igetElementGIDs(1,gids); TEST_EQUALITY(gids.size(),12); for(std::size_t i=0;i patternC1 + RCP patternC1 = buildFieldPattern >(); // build DOF manager @@ -377,7 +371,7 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, ghosted_owned_indices) ownedAndGhostedCorrect &= (ownedAndGhosted[5] == (int) 8); TEST_ASSERT(ownedAndGhostedCorrect); } - else + else TEUCHOS_ASSERT(false); } @@ -397,9 +391,9 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, multiple_dof_managers) TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternC1 + RCP patternC1 = buildFieldPattern >(); - RCP patternC2 + RCP patternC2 = buildFieldPattern >(); // build DOF manager @@ -421,15 +415,15 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, multiple_dof_managers) dofManager_temp->getElementGIDs(0,gids); TEST_EQUALITY(gids.size(),4); - TEST_EQUALITY(gids[0],0); - TEST_EQUALITY(gids[1],1); + TEST_EQUALITY(gids[0],0); + TEST_EQUALITY(gids[1],1); TEST_EQUALITY(gids[2],3); - TEST_EQUALITY(gids[3],2); - + TEST_EQUALITY(gids[3],2); + dofManager_temp->getElementGIDs(1,gids); TEST_EQUALITY(gids.size(),4); - TEST_EQUALITY(gids[0],2); - TEST_EQUALITY(gids[1],3); + TEST_EQUALITY(gids[0],2); + TEST_EQUALITY(gids[1],3); TEST_EQUALITY(gids[2],5); TEST_EQUALITY(gids[3],4); } @@ -438,15 +432,15 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, multiple_dof_managers) dofManager_temp->getElementGIDs(0,gids); TEST_EQUALITY(gids.size(),4); - TEST_EQUALITY(gids[0],1); - TEST_EQUALITY(gids[1],6); + TEST_EQUALITY(gids[0],1); + TEST_EQUALITY(gids[1],6); TEST_EQUALITY(gids[2],7); - TEST_EQUALITY(gids[3],3); - + TEST_EQUALITY(gids[3],3); + dofManager_temp->getElementGIDs(1,gids); TEST_EQUALITY(gids.size(),4); - TEST_EQUALITY(gids[0],3); - TEST_EQUALITY(gids[1],7); + TEST_EQUALITY(gids[0],3); + TEST_EQUALITY(gids[1],7); TEST_EQUALITY(gids[2],8); TEST_EQUALITY(gids[3],5); } @@ -476,7 +470,7 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager,getDofCoords) std::vector block00, block01; meshDB->getMyElements("eblock-0_0",block00); meshDB->getMyElements("eblock-1_0",block01); - + std::vector localIds_00, localIds_01; FieldContainer coords00, coords01; RCP patternC1_00 @@ -485,8 +479,8 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager,getDofCoords) = buildFieldPattern >(); // get coordinates - stkManager->getDofCoords("eblock-0_0",*patternC1_00,localIds_00,coords00); - stkManager->getDofCoords("eblock-1_0",*patternC1_01,localIds_01,coords01); + stkManager->getDofCoords("eblock-0_0",*patternC1_00,localIds_00,coords00); + stkManager->getDofCoords("eblock-1_0",*patternC1_01,localIds_01,coords01); TEST_EQUALITY(localIds_00.size(),block00.size()); TEST_EQUALITY(localIds_01.size(),block01.size()); @@ -499,9 +493,9 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager,getDofCoords) TEST_EQUALITY(coords00.extent(1),4); TEST_EQUALITY(coords00.extent(2),2); TEST_EQUALITY(coords01.extent(1),9); TEST_EQUALITY(coords01.extent(2),2); - for(std::size_t i=0;ielementLocalId(block00[i])); - for(std::size_t i=0;ielementLocalId(block01[i])); // for(std::size_t c=0;c patternC1 + RCP patternC1 = buildFieldPattern >(); - RCP patternI1 + RCP patternI1 = buildFieldPattern >(); RCP connManager = buildQuadMesh(Comm,2,2,1,1); @@ -654,7 +648,7 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, buildTest_quad_edge_orientations2) TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternI1 + RCP patternI1 = buildFieldPattern >(); RCP connManager = buildQuadMesh(Comm,2,2,1,1); @@ -734,7 +728,7 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, buildTest_quad_edge_orientations_fa TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternI1 + RCP patternI1 = buildFieldPattern >(); RCP connManager = buildQuadMesh(Comm,2,2,1,1); @@ -767,9 +761,9 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, buildTest_q2q1) TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternC1 + RCP patternC1 = buildFieldPattern >(); - RCP patternC2 + RCP patternC2 = buildFieldPattern >(); RCP connManager = buildQuadMesh(Comm,2,2,1,1); @@ -910,7 +904,7 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, buildTest_q2q1) TEST_EQUALITY(owned.size(),59-36); TEST_EQUALITY(ownedAndGhosted.size(),36); } - else + else TEUCHOS_ASSERT(false); } @@ -929,7 +923,7 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, buildTest_nabors) TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternC1 + RCP patternC1 = buildFieldPattern >(); RCP connManager = buildQuadMesh(Comm,4,2,1,1); @@ -1014,9 +1008,9 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager, buildTest_nabors) dofManager->getOwnedIndices(owned); dofManager_noNeighbors->getOwnedIndices(owned_noNeighbors); TEST_EQUALITY(owned.size(),owned_noNeighbors.size()); - + bool owned_result = true; - for(std::size_t j=0;jgetElementGIDs(e,gids); bool allFound = true; - for(std::size_t i=0;i FieldContainer; using Teuchos::RCP; @@ -83,7 +77,7 @@ Teuchos::RCP buildQuadMesh(stk::ParallelMachine comm,int xe panzer_stk::SquareQuadMeshFactory meshFact; meshFact.setParameterList(Teuchos::rcpFromRef(pl)); - + Teuchos::RCP mesh = meshFact.buildMesh(comm); return Teuchos::rcp(new panzer_stk::STKConnManager(mesh)); } @@ -112,7 +106,7 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager_edgetests, buildTest_quad_edge_orien TEUCHOS_ASSERT(numProcs==1); // build a geometric pattern from a single basis - RCP patternI1 + RCP patternI1 = buildFieldPattern >(); out << *patternI1 << std::endl; @@ -139,7 +133,7 @@ TEUCHOS_UNIT_TEST(tSquareQuadMeshDOFManager_edgetests, buildTest_quad_edge_orien out << indices[j+4] << " "; out << std::endl; } - + out << "GIDS" << std::endl; for(int i=0;i<4;i++) { diff --git a/packages/panzer/adapters-stk/test/stk_connmngr/tSquareTriMeshDOFManager.cpp b/packages/panzer/adapters-stk/test/stk_connmngr/tSquareTriMeshDOFManager.cpp index 780d6224bb23..df1463f646c0 100644 --- a/packages/panzer/adapters-stk/test/stk_connmngr/tSquareTriMeshDOFManager.cpp +++ b/packages/panzer/adapters-stk/test/stk_connmngr/tSquareTriMeshDOFManager.cpp @@ -57,12 +57,6 @@ #include "Intrepid2_HGRAD_TRI_C1_FEM.hpp" #include "Intrepid2_HGRAD_TRI_C2_FEM.hpp" -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - typedef Kokkos::DynRankView FieldContainer; using Teuchos::RCP; @@ -82,7 +76,7 @@ Teuchos::RCP buildTriMesh(stk::ParallelMachine comm,int xel panzer_stk::SquareTriMeshFactory meshFact; meshFact.setParameterList(Teuchos::rcpFromRef(pl)); - + Teuchos::RCP mesh = meshFact.buildMesh(comm); return Teuchos::rcp(new panzer_stk::STKConnManager(mesh)); } @@ -112,7 +106,7 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, buildTest_tri) TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternC1 + RCP patternC1 = buildFieldPattern >(); RCP connManager = buildTriMesh(Comm,2,2,1,1); @@ -158,11 +152,11 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, buildTest_tri) TEST_EQUALITY(gids[6],9); TEST_EQUALITY(gids[7],10); TEST_EQUALITY(gids[8],11); for(std::size_t i=0;igetElementGIDs(1,gids); TEST_EQUALITY(gids.size(),9); TEST_EQUALITY(gids[0],0); TEST_EQUALITY(gids[1],1); TEST_EQUALITY(gids[2],2); @@ -170,9 +164,9 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, buildTest_tri) TEST_EQUALITY(gids[6],6); TEST_EQUALITY(gids[7],7); TEST_EQUALITY(gids[8],8); for(std::size_t i=0;igetElementGIDs(3,gids); @@ -182,9 +176,9 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, buildTest_tri) TEST_EQUALITY(gids[6],12); TEST_EQUALITY(gids[7],13); TEST_EQUALITY(gids[8],14); for(std::size_t i=0;igetElementGIDs(1,gids); TEST_EQUALITY(gids.size(),9); TEST_EQUALITY(gids[0],3); TEST_EQUALITY(gids[1],4); TEST_EQUALITY(gids[2],5); @@ -209,9 +203,9 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, buildTest_tri) TEST_EQUALITY(gids[6],9); TEST_EQUALITY(gids[7],10); TEST_EQUALITY(gids[8],11); for(std::size_t i=0;igetElementGIDs(3,gids); @@ -221,9 +215,9 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, buildTest_tri) TEST_EQUALITY(gids[6],15); TEST_EQUALITY(gids[7],16); TEST_EQUALITY(gids[8],17); for(std::size_t i=0;i patternC1 + RCP patternC1 = buildFieldPattern >(); RCP connManager = buildTriMesh(Comm,2,2,1,1); @@ -285,17 +279,17 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, field_order) dofManager->getElementGIDs(0,gids); TEST_EQUALITY(gids.size(),12); for(std::size_t i=0;igetElementGIDs(1,gids); TEST_EQUALITY(gids.size(),12); for(std::size_t i=0;igetElementGIDs(0,gids); TEST_EQUALITY(gids.size(),12); for(std::size_t i=0;igetElementGIDs(1,gids); TEST_EQUALITY(gids.size(),12); for(std::size_t i=0;i patternC1 + RCP patternC1 = buildFieldPattern >(); // build DOF manager @@ -391,7 +385,7 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, ghosted_owned_indices) } TEST_ASSERT(ownedAndGhostedCorrect); } - else + else TEUCHOS_ASSERT(false); } @@ -411,9 +405,9 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, multiple_dof_managers) TEUCHOS_ASSERT(numProcs==2); // build a geometric pattern from a single basis - RCP patternC1 + RCP patternC1 = buildFieldPattern >(); - RCP patternC2 + RCP patternC2 = buildFieldPattern >(); // build DOF manager @@ -436,8 +430,8 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, multiple_dof_managers) dofManager_temp->getElementGIDs(0,gids); TEST_EQUALITY(gids.size(),4); TEST_EQUALITY(gids[0],0); TEST_EQUALITY(gids[1],1); TEST_EQUALITY(gids[2],3); - TEST_EQUALITY(gids[3],2); - + TEST_EQUALITY(gids[3],2); + dofManager_temp->getElementGIDs(1,gids); TEST_EQUALITY(gids.size(),4); TEST_EQUALITY(gids[0],2); TEST_EQUALITY(gids[1],3); TEST_EQUALITY(gids[2],5); @@ -449,8 +443,8 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager, multiple_dof_managers) dofManager_temp->getElementGIDs(0,gids); TEST_EQUALITY(gids.size(),4); TEST_EQUALITY(gids[0],1); TEST_EQUALITY(gids[1],6); TEST_EQUALITY(gids[2],7); - TEST_EQUALITY(gids[3],3); - + TEST_EQUALITY(gids[3],3); + dofManager_temp->getElementGIDs(1,gids); TEST_EQUALITY(gids.size(),4); TEST_EQUALITY(gids[0],3); TEST_EQUALITY(gids[1],7); TEST_EQUALITY(gids[2],8); @@ -485,7 +479,7 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager,getDofCoords) std::vector block00, block01; meshDB->getMyElements("eblock-0_0",block00); meshDB->getMyElements("eblock-1_0",block01); - + std::vector localIds_00, localIds_01; FieldContainer coords00, coords01; RCP patternC1_00 @@ -494,8 +488,8 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager,getDofCoords) = buildFieldPattern >(); // get coordinates - stkManager->getDofCoords("eblock-0_0",*patternC1_00,localIds_00,coords00); - stkManager->getDofCoords("eblock-1_0",*patternC1_01,localIds_01,coords01); + stkManager->getDofCoords("eblock-0_0",*patternC1_00,localIds_00,coords00); + stkManager->getDofCoords("eblock-1_0",*patternC1_01,localIds_01,coords01); TEST_EQUALITY(localIds_00.size(),block00.size()); TEST_EQUALITY(localIds_01.size(),block01.size()); @@ -506,9 +500,9 @@ TEUCHOS_UNIT_TEST(tSquareTriMeshDOFManager,getDofCoords) TEST_EQUALITY(coords00.extent(1),4); TEST_EQUALITY(coords00.extent(2),2); TEST_EQUALITY(coords01.extent(1),9); TEST_EQUALITY(coords01.extent(2),2); - for(std::size_t i=0;ielementLocalId(block00[i])); - for(std::size_t i=0;ielementLocalId(block01[i])); // for(std::size_t c=0;c -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - #include "Ioss_DatabaseIO.h" #include "Ioss_IOFactory.h" #include "Ioss_Region.h" @@ -757,7 +751,7 @@ TEUCHOS_UNIT_TEST(tExodusReaderFactory, umr_refine_once_with_geometry) TEST_EQUALITY((int) nodesets.size(),3); std::map sidesets_counts = {{"top",4}, {"interface",2}, {"surface_3",2}, {"surface_4",4}, {"inner",2}}; - + for (auto const& x : sidesets_counts) { std::vector globalCounts; stk::mesh::Part * ss_part = mesh->getSideset(x.first); diff --git a/packages/panzer/adapters-stk/test/stk_interface_test/tGhosting.cpp b/packages/panzer/adapters-stk/test/stk_interface_test/tGhosting.cpp index def432b10977..ae2f8c4fbd41 100644 --- a/packages/panzer/adapters-stk/test/stk_interface_test/tGhosting.cpp +++ b/packages/panzer/adapters-stk/test/stk_interface_test/tGhosting.cpp @@ -54,12 +54,6 @@ #include "Shards_BasicTopologies.hpp" -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - #include "stk_mesh/base/GetEntities.hpp" #include "stk_mesh/base/Selector.hpp" //#include @@ -72,14 +66,14 @@ inline bool XOR(bool A,bool B) class LocalIdCompare { public: LocalIdCompare(const Teuchos::RCP & mesh) : mesh_(mesh) {} - bool operator()(stk::mesh::Entity a,stk::mesh::Entity b) const + bool operator()(stk::mesh::Entity a,stk::mesh::Entity b) const { return mesh_->elementLocalId(a) < mesh_->elementLocalId(b); } private: Teuchos::RCP mesh_; }; -// This test was modified to its current lame state when the +// This test was modified to its current lame state when the // construction of the local element IDs was automated in the // STK_Interface. (Independent of order of addition in the mesh @@ -103,7 +97,7 @@ TEUCHOS_UNIT_TEST(tGhosting, get_neighbor_elements) TEUCHOS_ASSERT(numprocs==4); - SquareQuadMeshFactory factory; + SquareQuadMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); mesh->writeToExodus("TEST.exo"); diff --git a/packages/panzer/adapters-stk/test/stk_interface_test/tLineMeshFactory.cpp b/packages/panzer/adapters-stk/test/stk_interface_test/tLineMeshFactory.cpp index c733299ec37f..9c3146a9a436 100644 --- a/packages/panzer/adapters-stk/test/stk_interface_test/tLineMeshFactory.cpp +++ b/packages/panzer/adapters-stk/test/stk_interface_test/tLineMeshFactory.cpp @@ -53,12 +53,6 @@ #include "Shards_BasicTopologies.hpp" -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - namespace panzer_stk { TEUCHOS_UNIT_TEST(tLineMeshFactory, defaults) @@ -66,13 +60,13 @@ TEUCHOS_UNIT_TEST(tLineMeshFactory, defaults) using Teuchos::RCP; using Teuchos::rcp; using Teuchos::rcpFromRef; - - LineMeshFactory factory; + + LineMeshFactory factory; RCP mesh = factory.buildMesh(MPI_COMM_WORLD); TEST_ASSERT(mesh!=Teuchos::null); TEST_EQUALITY(mesh->getPeriodicBCVector().size(),0); - + if(mesh->isWritable()) mesh->writeToExodus("Line.exo"); @@ -96,12 +90,12 @@ TEUCHOS_UNIT_TEST(tLineMeshFactory, element_counts) RCP pl = rcp(new Teuchos::ParameterList); pl->set("X Blocks",1); pl->set("X Elements",2); - - LineMeshFactory factory; + + LineMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); TEST_ASSERT(mesh!=Teuchos::null); - + if(mesh->isWritable()) mesh->writeToExodus("Line_oddelmt.exo"); @@ -130,12 +124,12 @@ TEUCHOS_UNIT_TEST(tLineMeshFactory, allblock) pl->set("X Elements",xe); xe *= bx; - - LineMeshFactory factory; + + LineMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); TEST_ASSERT(mesh!=Teuchos::null); - + if(mesh->isWritable()) mesh->writeToExodus("Line_allblock.exo"); @@ -159,12 +153,12 @@ TEUCHOS_UNIT_TEST(tLineMeshFactory, two_block) RCP pl = rcp(new Teuchos::ParameterList); pl->set("X Blocks",2); pl->set("X Elements",5); - - LineMeshFactory factory; + + LineMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(MPI_COMM_WORLD); TEST_ASSERT(mesh!=Teuchos::null); - + if(mesh->isWritable()) mesh->writeToExodus("Line_2block.exo"); diff --git a/packages/panzer/adapters-stk/test/stk_interface_test/tPamgenMeshFactory.cpp b/packages/panzer/adapters-stk/test/stk_interface_test/tPamgenMeshFactory.cpp index 617da8c36e5f..0b060a08e7f1 100644 --- a/packages/panzer/adapters-stk/test/stk_interface_test/tPamgenMeshFactory.cpp +++ b/packages/panzer/adapters-stk/test/stk_interface_test/tPamgenMeshFactory.cpp @@ -58,12 +58,6 @@ #include "percept/PerceptMesh.hpp" #endif -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - #include "stk_mesh/base/GetEntities.hpp" #include "stk_mesh/base/Selector.hpp" #include "stk_mesh/base/CreateAdjacentEntities.hpp" @@ -411,7 +405,7 @@ TEUCHOS_UNIT_TEST(tPamgenFactory, keepPerceptData) TEST_ASSERT(nonnull(refinedMesh)); TEST_ASSERT(refinedMesh->get_number_elements()>0); - // check if the parent information is stored + // check if the parent information is stored std::vector ranks_to_be_deleted; ranks_to_be_deleted.push_back(stk::topology::ELEMENT_RANK); ranks_to_be_deleted.push_back(refinedMesh->side_rank()); diff --git a/packages/panzer/adapters-stk/test/stk_interface_test/tSTKInterface.cpp b/packages/panzer/adapters-stk/test/stk_interface_test/tSTKInterface.cpp index 00218daea565..12052a41a784 100644 --- a/packages/panzer/adapters-stk/test/stk_interface_test/tSTKInterface.cpp +++ b/packages/panzer/adapters-stk/test/stk_interface_test/tSTKInterface.cpp @@ -52,12 +52,6 @@ #include "Shards_BasicTopologies.hpp" -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - namespace panzer_stk { typedef shards::Quadrilateral<4> QuadTopo; @@ -80,26 +74,26 @@ Teuchos::RCP build2DMesh() mesh.beginModification(); std::vector coord(2); stk::mesh::Part * block = mesh.getElementBlockPart("quad_elements"); - { + { // Add four coordinates // // 4 ---- 3 // | | // | | - // 1 ---- 2 + // 1 ---- 2 // - + coord[0] = 0.0; coord[1] = 0.0; - mesh.addNode(1,coord); + mesh.addNode(1,coord); coord[0] = 1.0; coord[1] = 0.0; - mesh.addNode(2,coord); + mesh.addNode(2,coord); coord[0] = 1.0; coord[1] = 1.0; - mesh.addNode(3,coord); + mesh.addNode(3,coord); coord[0] = 0.0; coord[1] = 1.0; - mesh.addNode(4,coord); + mesh.addNode(4,coord); // add an element std::vector nodes; @@ -110,20 +104,20 @@ Teuchos::RCP build2DMesh() mesh.addElement(ed,block); } - { + { // Add four coordinates // // 3 ---- 6 // | | // | | - // 2 ---- 5 + // 2 ---- 5 // - + coord[0] = 2.0; coord[1] = 0.5; - mesh.addNode(5,coord); + mesh.addNode(5,coord); coord[0] = 2.1; coord[1] = 1.5; - mesh.addNode(6,coord); + mesh.addNode(6,coord); // add an element std::vector nodes(4); @@ -136,20 +130,20 @@ Teuchos::RCP build2DMesh() mesh.addElement(ed,block); } - { + { // Add four coordinates // // 8 ---- 7 // | | // | | - // 4 ---- 3 + // 4 ---- 3 // - + coord[0] = 1.0; coord[1] = 2.5; - mesh.addNode(7,coord); + mesh.addNode(7,coord); coord[0] = 0.1; coord[1] = 2.0; - mesh.addNode(8,coord); + mesh.addNode(8,coord); // add an element std::vector nodes(4); @@ -179,12 +173,11 @@ TEUCHOS_UNIT_TEST(tSTKInterface, interface_test) const CellTopologyData * side_ctd = shards::CellTopology(ctd).getBaseCellTopologyData(1,0); // build global (or serial communicator) - #ifdef HAVE_MPI - Epetra_MpiComm Comm(MPI_COMM_WORLD); - #else - Epetra_SerialComm Comm; - #endif - RCP comm = rcpFromRef(Comm); + #ifdef HAVE_MPI + Teuchos::RCP > comm = Teuchos::rcp(new Teuchos::MpiComm(MPI_COMM_WORLD)); + #else + auto comm = Teuchos::rcp(Teuchos::DefaultComm::getComm()); + #endif STK_Interface mesh(2); @@ -209,26 +202,26 @@ TEUCHOS_UNIT_TEST(tSTKInterface, interface_test) std::vector coord(2); stk::mesh::Part * block = mesh.getElementBlockPart("0"); - { + { // Add four coordinates // // 4 ---- 3 // | | // | | - // 1 ---- 2 + // 1 ---- 2 // - + coord[0] = 0.0; coord[1] = 0.0; - mesh.addNode(1,coord); + mesh.addNode(1,coord); coord[0] = 1.0; coord[1] = 0.0; - mesh.addNode(2,coord); + mesh.addNode(2,coord); coord[0] = 1.0; coord[1] = 1.0; - mesh.addNode(3,coord); + mesh.addNode(3,coord); coord[0] = 0.0; coord[1] = 1.0; - mesh.addNode(4,coord); + mesh.addNode(4,coord); // add an element std::vector nodes; @@ -239,20 +232,20 @@ TEUCHOS_UNIT_TEST(tSTKInterface, interface_test) mesh.addElement(ed,block); } - { + { // Add four coordinates // // 3 ---- 6 // | | // | | - // 2 ---- 5 + // 2 ---- 5 // - + coord[0] = 2.0; coord[1] = 0.5; - mesh.addNode(5,coord); + mesh.addNode(5,coord); coord[0] = 2.1; coord[1] = 1.5; - mesh.addNode(6,coord); + mesh.addNode(6,coord); // add an element std::vector nodes(4); @@ -282,7 +275,7 @@ TEUCHOS_UNIT_TEST(tSTKInterface, interface_test) #else TEST_ASSERT(not mesh.isWritable()); TEST_THROW(mesh.writeToExodus("simplemesh.exo"),std::logic_error); - #endif + #endif const double * coords = 0; @@ -318,38 +311,38 @@ TEUCHOS_UNIT_TEST(tSTKInterface, node_sharing_test) using Teuchos::RCP; using Teuchos::rcp; using Teuchos::rcpFromRef; - + RCP mesh = build2DMesh(); - + if(mesh->isWritable()) mesh->writeToExodus("simplemesh.exo"); - + { std::vector elements; mesh->getElementsSharingNode(2,elements); - - TEST_EQUALITY(elements.size(),2); - TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 1))!=elements.end()); - TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 2))!=elements.end()); + + TEST_EQUALITY(elements.size(),2); + TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 1))!=elements.end()); + TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 2))!=elements.end()); } - + { std::vector elements; mesh->getElementsSharingNode(4,elements); - - TEST_EQUALITY(elements.size(),2); - TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 1))!=elements.end()); - TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 3))!=elements.end()); + + TEST_EQUALITY(elements.size(),2); + TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 1))!=elements.end()); + TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 3))!=elements.end()); } - + { std::vector elements; mesh->getElementsSharingNode(3,elements); - - TEST_EQUALITY(elements.size(),3); - TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 1))!=elements.end()); - TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 2))!=elements.end()); - TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 3))!=elements.end()); + + TEST_EQUALITY(elements.size(),3); + TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 1))!=elements.end()); + TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 2))!=elements.end()); + TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 3))!=elements.end()); } { @@ -360,11 +353,11 @@ TEUCHOS_UNIT_TEST(tSTKInterface, node_sharing_test) std::vector elements; mesh->getElementsSharingNodes(nodes,elements); - TEST_EQUALITY(elements.size(),2); - TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 1))!=elements.end()); - TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 3))!=elements.end()); + TEST_EQUALITY(elements.size(),2); + TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 1))!=elements.end()); + TEST_ASSERT(std::find_if(elements.begin(),elements.end(),CompareID(mesh, 3))!=elements.end()); } - + { std::vector nodes; nodes.push_back(1); @@ -373,7 +366,7 @@ TEUCHOS_UNIT_TEST(tSTKInterface, node_sharing_test) std::vector elements; mesh->getElementsSharingNodes(nodes,elements); - TEST_EQUALITY(elements.size(),0); + TEST_EQUALITY(elements.size(),0); } } diff --git a/packages/panzer/adapters-stk/test/stk_interface_test/tSingleBlockCubeHexMeshFactory.cpp b/packages/panzer/adapters-stk/test/stk_interface_test/tSingleBlockCubeHexMeshFactory.cpp index 80f08cce6323..d528d14655b5 100644 --- a/packages/panzer/adapters-stk/test/stk_interface_test/tSingleBlockCubeHexMeshFactory.cpp +++ b/packages/panzer/adapters-stk/test/stk_interface_test/tSingleBlockCubeHexMeshFactory.cpp @@ -53,12 +53,6 @@ #include "Shards_BasicTopologies.hpp" -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - using Teuchos::RCP; using Teuchos::rcp; using Teuchos::rcpFromRef; @@ -91,7 +85,7 @@ TEUCHOS_UNIT_TEST(tCubeHexMeshFactory, test_four) TEUCHOS_UNIT_TEST(tCubeHexMeshFactory, element_counts) { - int colors[] = + int colors[] = { 1, 2,2, 4,4,4,4, @@ -141,8 +135,8 @@ void test1(Teuchos::FancyOStream &out, bool &success, MPI_Comm & comm) pl->set("X Elements",2); pl->set("Y Elements",4); pl->set("Z Elements",5); - - CubeHexMeshFactory factory; + + CubeHexMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(comm); TEST_ASSERT(mesh!=Teuchos::null); @@ -162,7 +156,7 @@ void test1(Teuchos::FancyOStream &out, bool &success, MPI_Comm & comm) void test2(Teuchos::FancyOStream &out, bool &success,MPI_Comm & comm) { int size; MPI_Comm_size(comm, &size); TEST_EQUALITY(size,2); - int rank; MPI_Comm_rank(comm, &rank); + int rank; MPI_Comm_rank(comm, &rank); RCP pl = rcp(new Teuchos::ParameterList); pl->set("X Procs",1); @@ -171,8 +165,8 @@ void test2(Teuchos::FancyOStream &out, bool &success,MPI_Comm & comm) pl->set("X Elements",2); pl->set("Y Elements",4); pl->set("Z Elements",5); - - CubeHexMeshFactory factory; + + CubeHexMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(comm); TEST_ASSERT(mesh!=Teuchos::null); @@ -217,7 +211,7 @@ void test2(Teuchos::FancyOStream &out, bool &success,MPI_Comm & comm) void test4(Teuchos::FancyOStream &out, bool &success,MPI_Comm & comm) { int size; MPI_Comm_size(comm, &size); TEST_EQUALITY(size,4); - int rank; MPI_Comm_rank(comm, &rank); + int rank; MPI_Comm_rank(comm, &rank); RCP pl = rcp(new Teuchos::ParameterList); pl->set("X Procs",1); @@ -226,8 +220,8 @@ void test4(Teuchos::FancyOStream &out, bool &success,MPI_Comm & comm) pl->set("X Elements",2); pl->set("Y Elements",4); pl->set("Z Elements",5); - - CubeHexMeshFactory factory; + + CubeHexMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(comm); TEST_ASSERT(mesh!=Teuchos::null); @@ -290,7 +284,7 @@ void test4(Teuchos::FancyOStream &out, bool &success,MPI_Comm & comm) void test27(Teuchos::FancyOStream &out, bool &success,MPI_Comm & comm) { int size; MPI_Comm_size(comm, &size); TEST_EQUALITY(size,27); - int rank; MPI_Comm_rank(comm, &rank); + int rank; MPI_Comm_rank(comm, &rank); RCP pl = rcp(new Teuchos::ParameterList); pl->set("X Procs",3); @@ -299,8 +293,8 @@ void test27(Teuchos::FancyOStream &out, bool &success,MPI_Comm & comm) pl->set("X Elements",6); pl->set("Y Elements",9); pl->set("Z Elements",12); - - CubeHexMeshFactory factory; + + CubeHexMeshFactory factory; factory.setParameterList(pl); RCP mesh = factory.buildMesh(comm); TEST_ASSERT(mesh!=Teuchos::null); diff --git a/packages/panzer/adapters-stk/test/stk_interface_test/tSquareQuadMeshFactory.cpp b/packages/panzer/adapters-stk/test/stk_interface_test/tSquareQuadMeshFactory.cpp index 67ab53e1baa3..593ed73bdfaa 100644 --- a/packages/panzer/adapters-stk/test/stk_interface_test/tSquareQuadMeshFactory.cpp +++ b/packages/panzer/adapters-stk/test/stk_interface_test/tSquareQuadMeshFactory.cpp @@ -54,12 +54,6 @@ #include "Shards_BasicTopologies.hpp" -#ifdef HAVE_MPI - #include "Epetra_MpiComm.h" -#else - #include "Epetra_SerialComm.h" -#endif - #include "stk_mesh/base/GetEntities.hpp" #include "stk_mesh/base/Selector.hpp" From 019a2d2ce0211b263895a42fe6f01b96b7b91c93 Mon Sep 17 00:00:00 2001 From: Reinhard Resch Date: Sun, 20 Mar 2022 22:00:39 +0100 Subject: [PATCH 045/147] Fix missing initialization of variables in NOX::Solver::TensorBased --- packages/nox/src/NOX_Solver_TensorBased.C | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/nox/src/NOX_Solver_TensorBased.C b/packages/nox/src/NOX_Solver_TensorBased.C index 85a3163add25..f355a62fecf8 100644 --- a/packages/nox/src/NOX_Solver_TensorBased.C +++ b/packages/nox/src/NOX_Solver_TensorBased.C @@ -80,7 +80,11 @@ TensorBased(const Teuchos::RCP& xGrp, tmpVecPtr(xGrp->getX().clone(ShapeCopy)), // create via clone residualVecPtr(xGrp->getX().clone(ShapeCopy)), // create via clone testPtr(t), - paramsPtr(p) + paramsPtr(p), + linearParamsPtr(0), + beta(0.), + sTinvJF(0.), + sTinvJa(0.) { reset(xGrp, t, p); } From a8fb1b1a1db6b1ebad49e32c1e7fa8544b83f0dc Mon Sep 17 00:00:00 2001 From: Roger Pawlowski Date: Mon, 21 Mar 2022 14:38:59 -0600 Subject: [PATCH 046/147] Panzer: fix issue with gcc 11 and view of views --- ...r_Integrator_GradBasisCrossVector_decl.hpp | 12 +++---- ...r_Integrator_GradBasisCrossVector_impl.hpp | 31 ++++++++++++------- ...r_Integrator_GradBasisTimesScalar_decl.hpp | 9 +++--- ...r_Integrator_GradBasisTimesScalar_impl.hpp | 25 +++++++++------ 4 files changed, 45 insertions(+), 32 deletions(-) diff --git a/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisCrossVector_decl.hpp b/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisCrossVector_decl.hpp index 6ce4ba32d1bf..634bd64033f1 100644 --- a/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisCrossVector_decl.hpp +++ b/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisCrossVector_decl.hpp @@ -283,11 +283,10 @@ namespace panzer * \brief The fields to which we'll contribute, or in which we'll store, * the result of computing this integral. */ - // PHX::View*> fields_; - using InnerView = PHX::View; + std::vector> fields_host_; + using InnerView = PHX::UnmanagedView; using OuterView = PHX::View; - typename OuterView::HostMirror fields_host_; - OuterView fields_; + OuterView fields_; /** * \brief A field representing the vector-valued function we're @@ -312,7 +311,7 @@ namespace panzer * of fields that are multipliers out in front of the integral * (\f$ a(x) \f$, \f$ b(x) \f$, etc.). */ - PHX::View*> kokkosFieldMults_; + PHX::View*> kokkosFieldMults_; /** * \brief The number of dimensions associated with the vector. @@ -339,8 +338,7 @@ namespace panzer * \brief The gradient vector basis information necessary for * integration. */ - PHX::MDField basis_; + PHX::MDField basis_; }; // end of class Integrator_GradBasisCrossVector diff --git a/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisCrossVector_impl.hpp b/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisCrossVector_impl.hpp index db6ad90e79b9..d940b1447670 100644 --- a/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisCrossVector_impl.hpp +++ b/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisCrossVector_impl.hpp @@ -137,26 +137,26 @@ namespace panzer // Create the fields that we're either contributing to or evaluating // (storing). - fields_host_ = typename OuterView::HostMirror("Integrator_GradBasisCrossVector::fields_", resNames.size()); + fields_host_.resize(resNames.size()); fields_ = OuterView("Integrator_GradBasisCrossVector::fields_", resNames.size()); { int i=0; for (const auto& name : resNames) - fields_host_(i++) = PHX::View(name, basis.functional->extent(0),basis.functional->extent(1)); + fields_host_[i++] = MDField(name, basis.functional); } // end loop over resNames - Kokkos::deep_copy(fields_,fields_host_); + for (std::size_t i=0; i< fields_.extent(0); ++i) { - const auto& field = fields_host_(i); - PHX::Tag tag(resNames[i],basis.functional); + const auto& field = fields_host_[i]; if (evalStyle_ == EvaluatorStyle::CONTRIBUTES) - this->addContributedField(tag,field); + this->addContributedField(field); else // if (evalStyle_ == EvaluatorStyle::EVALUATES) - this->addEvaluatedField(tag,field); + this->addEvaluatedField(field); } + // Add the dependent field multipliers, if there are any. int i = 0; fieldMults_.resize(fmNames.size()); - kokkosFieldMults_ = View*>("GradBasisCrossVector::KokkosFieldMultipliers", fmNames.size()); + kokkosFieldMults_ = PHX::View*>("GradBasisCrossVector::KokkosFieldMultipliers", fmNames.size()); for (const auto& name : fmNames) { fieldMults_[i++] = MDField(name, ir.dl_scalar); @@ -170,7 +170,7 @@ namespace panzer else // if (evalStyle_ == EvaluatorStyle::EVALUATES) n += "EVALUATES"; n += "): {"; - for (size_t j=0; j < fields_host_.extent(0) - 1; ++j) + for (size_t j=0; j < fields_host_.size() - 1; ++j) n += resNames[j] + ", "; n += resNames[resNames.size()-1] + "}"; this->setName(n); @@ -224,9 +224,18 @@ namespace panzer using Kokkos::createDynRankView; using panzer::getBasisIndex; + // Get the PHX::Views of the fields. + auto fields_host_mirror_ = Kokkos::create_mirror_view(fields_); + for (size_t i=0; i < fields_host_.size(); ++i) { + fields_host_mirror_(i) = fields_host_[i].get_static_view(); + } + Kokkos::deep_copy(fields_,fields_host_mirror_); + // Get the PHX::Views of the field multipliers. - for (size_t i(0); i < fieldMults_.size(); ++i) - kokkosFieldMults_(i) = fieldMults_[i].get_static_view(); + auto field_mults_host_mirror_ = Kokkos::create_mirror_view(kokkosFieldMults_); + for (size_t i=0; i < fieldMults_.size(); ++i) + field_mults_host_mirror_(i) = fieldMults_[i].get_static_view(); + Kokkos::deep_copy(kokkosFieldMults_,field_mults_host_mirror_); // Determine the index in the Workset bases for our particular basis name. basisIndex_ = getBasisIndex(basisName_, (*sd.worksets_)[0], this->wda); diff --git a/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisTimesScalar_decl.hpp b/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisTimesScalar_decl.hpp index d09ecbc638cd..055593f0bc20 100644 --- a/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisTimesScalar_decl.hpp +++ b/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisTimesScalar_decl.hpp @@ -270,11 +270,10 @@ namespace panzer * \brief The fields to which we'll contribute, or in which we'll store, * the result of computing this integral. */ - // PHX::View*> fields_; - using InnerView = PHX::View; + std::vector> fields_host_; + using InnerView = PHX::UnmanagedView; using OuterView = PHX::View; - typename OuterView::HostMirror fields_host_; - OuterView fields_; + OuterView fields_; /** * \brief A field representing the scalar function we're integrating @@ -299,7 +298,7 @@ namespace panzer * of fields that are multipliers out in front of the integral * (\f$ a(x) \f$, \f$ b(x) \f$, etc.). */ - PHX::View*> kokkosFieldMults_; + PHX::View*> kokkosFieldMults_; /** * \brief The number of dimensions associated with the gradient. diff --git a/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisTimesScalar_impl.hpp b/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisTimesScalar_impl.hpp index 9488a45c16c5..f9d0fcfd1b6f 100644 --- a/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisTimesScalar_impl.hpp +++ b/packages/panzer/disc-fe/src/evaluators/Panzer_Integrator_GradBasisTimesScalar_impl.hpp @@ -119,26 +119,25 @@ namespace panzer // Create the fields that we're either contributing to or evaluating // (storing). - fields_host_ = typename OuterView::HostMirror("Integrator_GradBasisCrossVector::fields_", resNames.size()); + fields_host_.resize(resNames.size()); fields_ = OuterView("Integrator_GradBasisCrossVector::fields_", resNames.size()); { int i=0; for (const auto& name : resNames) - fields_host_(i++) = PHX::View(name, basis.functional->extent(0),basis.functional->extent(1)); + fields_host_[i++] = PHX::MDField(name,basis.functional); } for (std::size_t i=0; i tag(resNames[i],basis.functional); + const auto& field = fields_host_[i]; if (evalStyle_ == EvaluatorStyle::CONTRIBUTES) - this->addContributedField(tag,field); + this->addContributedField(field); else // if (evalStyle_ == EvaluatorStyle::EVALUATES) - this->addEvaluatedField(tag,field); + this->addEvaluatedField(field); } // Add the dependent field multipliers, if there are any. int i = 0; fieldMults_.resize(fmNames.size()); - kokkosFieldMults_ = View*>( + kokkosFieldMults_ = PHX::View*>( "GradBasisTimesScalar::KokkosFieldMultipliers", fmNames.size()); for (const auto& name : fmNames) { @@ -153,7 +152,7 @@ namespace panzer else // if (evalStyle_ == EvaluatorStyle::EVALUATES) n += "EVALUATES"; n += "): {"; - for (size_t j=0; j < fields_host_.extent(0) - 1; ++j) + for (size_t j=0; j < fields_host_.size() - 1; ++j) n += resNames[j] + ", "; n += resNames[resNames.size()-1] + "}"; this->setName(n); @@ -204,9 +203,17 @@ namespace panzer using Kokkos::createDynRankView; using panzer::getBasisIndex; + // Get the PHX::Views of the fields. + auto fields_host_mirror = Kokkos::create_mirror_view(fields_); + for (size_t i(0); i < fields_host_.size(); ++i) + fields_host_mirror(i) = fields_host_[i].get_static_view(); + Kokkos::deep_copy(fields_,fields_host_mirror); + // Get the PHX::Views of the field multipliers. + auto field_mults_host_mirror = Kokkos::create_mirror_view(kokkosFieldMults_); for (size_t i(0); i < fieldMults_.size(); ++i) - kokkosFieldMults_(i) = fieldMults_[i].get_static_view(); + field_mults_host_mirror(i) = fieldMults_[i].get_static_view(); + Kokkos::deep_copy(kokkosFieldMults_,field_mults_host_mirror); // Determine the index in the Workset bases for our particular basis name. basisIndex_ = getBasisIndex(basisName_, (*sd.worksets_)[0], this->wda); From d5e9118286aebb276d3c294f066e290c639456a1 Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Tue, 22 Mar 2022 09:23:28 +0100 Subject: [PATCH 047/147] MueLu: rename region cycle adapter function --- .../research/regionMG/src/SolveRegionHierarchy_def.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp index fa5bb4f01f6d..df8ea06192f6 100644 --- a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp +++ b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp @@ -312,7 +312,7 @@ void vCycle(const int l, ///< ID of current level //! Adapter that uses composite vectors and a region hierarchy // and performs a region vCycle on them. template -void vCycleAdapter(const int numLevels, ///< Total number of levels +void RegionMgCycleAdapter(const int numLevels, ///< Total number of levels const std::string cycleType, RCP > & regHierarchy, RCP >& X, ///< solution @@ -360,7 +360,7 @@ void vCycleAdapter(const int numLevels, ///< Total number of levels // Bring solution back to composite format scaleInterfaceDOFs(regX, regInterfaceScalings, true); regionalToComposite(regX, X, rowImport); -} // vCycleAdapter +} // RegionMgCycleAdapter template void solveRegionProblem(const double tol, const bool scaleResidualHist, const int maxIts, @@ -600,7 +600,7 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co normResIni = Res->norm2(); Z->putScalar(SC_zero); - vCycleAdapter(numLevels, cycleType, regHierarchy, + RegionMgCycleAdapter(numLevels, cycleType, regHierarchy, Z, Res, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); P->update(SC_one, *Z, SC_zero); // deep copy values of Z into P @@ -635,7 +635,7 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co } Z->putScalar(SC_zero); - vCycleAdapter(numLevels, cycleType, regHierarchy, + RegionMgCycleAdapter(numLevels, cycleType, regHierarchy, Z, Res, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); @@ -749,7 +749,7 @@ void solveCompositeProblemRichardson(const double tol, const bool scaleResidualH break; } - vCycleAdapter(numLevels, cycleType, regHierarchy, + RegionMgCycleAdapter(numLevels, cycleType, regHierarchy, Correct, Res, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); From 7e4a37264cd920499905418f33b12a8e7c8b3956 Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Tue, 22 Mar 2022 10:20:44 +0100 Subject: [PATCH 048/147] MueLu: reduce number of region function args numLevels can internally be extracted from the region hierarchy, so we don't need to pass it as a function argument --- .../regionMG/src/SolveRegionHierarchy_def.hpp | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp index df8ea06192f6..49e48b3e5e7c 100644 --- a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp +++ b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp @@ -54,7 +54,6 @@ using Teuchos::Array; //! Recursive V-cycle in region fashion template void vCycle(const int l, ///< ID of current level - const int numLevels, ///< Total number of levels const std::string cycleType, RCP > & regHierarchy, RCP >& fineRegX, ///< solution @@ -78,7 +77,7 @@ void vCycle(const int l, ///< ID of current level int cycleCount = 1; if(cycleType == "W" && l > 0) // W cycle and not on finest level cycleCount=2; - if (l < numLevels - 1) { // fine or intermediate levels + if (l < regHierarchy->GetNumLevels() - 1) { // fine or intermediate levels for(int cycle=0; cycle < cycleCount; cycle++){ // std::cout << "level: " << l << std::endl; @@ -143,7 +142,7 @@ void vCycle(const int l, ///< ID of current level bool coarseZeroInitGuess = true; // Call V-cycle recursively - vCycle(l+1, numLevels, cycleType, regHierarchy, + vCycle(l+1, cycleType, regHierarchy, coarseRegX, coarseRegB, smootherParams, coarseZeroInitGuess, coarseSolverData, hierarchyData); @@ -312,15 +311,15 @@ void vCycle(const int l, ///< ID of current level //! Adapter that uses composite vectors and a region hierarchy // and performs a region vCycle on them. template -void RegionMgCycleAdapter(const int numLevels, ///< Total number of levels - const std::string cycleType, - RCP > & regHierarchy, - RCP >& X, ///< solution - RCP > B, ///< right hand side - Array > smootherParams, ///< region smoother parameter list - bool& zeroInitGuess, - RCP coarseSolverData = Teuchos::null, - RCP hierarchyData = Teuchos::null) { +void RegionMgCycleAdapter(const std::string cycleType, + RCP > & regHierarchy, + RCP >& X, ///< solution + RCP > B, ///< right hand side + Array > smootherParams, ///< region smoother parameter list + bool& zeroInitGuess, + RCP coarseSolverData = Teuchos::null, + RCP hierarchyData = Teuchos::null) +{ using LO = LocalOrdinal; using GO = GlobalOrdinal; @@ -353,7 +352,7 @@ void RegionMgCycleAdapter(const int numLevels, ///< Total number of levels compositeToRegional(X, quasiRegX, regX, revisedRowMap, rowImport); - vCycle(0, numLevels, cycleType, regHierarchy, + vCycle(0, cycleType, regHierarchy, regX, regB, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); @@ -391,7 +390,6 @@ void solveRegionProblem(const double tol, const bool scaleResidualHist, const in const Scalar SC_one = STS::one(); // we start by extracting some basic data from the hierarchy - const int numLevels = regHierarchy->GetNumLevels(); RCP level0 = regHierarchy->GetLevel(0); RCP regMat = level0->Get >("A"); RCP revisedRowMap = regMat->getRowMap(); @@ -422,7 +420,7 @@ void solveRegionProblem(const double tol, const bool scaleResidualHist, const in else out << "Using unscaled residual norm." << std::endl; - TEUCHOS_TEST_FOR_EXCEPT_MSG(!(numLevels>0), "We require numLevel > 0. Probably, numLevel has not been set, yet."); + TEUCHOS_TEST_FOR_EXCEPT_MSG(!(regHierarchy->GetNumLevels()>0), "We require numLevel > 0. Probably, numLevel has not been set, yet."); // We first use the non-level container variables to setup the fine grid problem. // This is ok since the initial setup just mimics the application and the outer @@ -499,7 +497,7 @@ void solveRegionProblem(const double tol, const bool scaleResidualHist, const in scaleInterfaceDOFs(regRes, regInterfaceScalings, false); // std::cout << "regB->norm2() " << regRes->norm2() << std::endl; - vCycle(0, numLevels, cycleType, regHierarchy, + vCycle(0, cycleType, regHierarchy, regCorrect, regRes, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); @@ -544,7 +542,6 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co const Scalar SC_one = STS::one(); // we start by extracting some basic data from the hierarchy - const int numLevels = regHierarchy->GetNumLevels(); RCP level0 = regHierarchy->GetLevel(0); RCP regMat = level0->Get >("A"); RCP revisedRowMap = regMat->getRowMap(); @@ -575,7 +572,7 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co else out << "Using unscaled residual norm." << std::endl; - TEUCHOS_TEST_FOR_EXCEPT_MSG(!(numLevels>0), "We require numLevel > 0. Probably, numLevel has not been set, yet."); + TEUCHOS_TEST_FOR_EXCEPT_MSG(!(regHierarchy->GetNumLevels()>0), "We require numLevel > 0. Probably, numLevel has not been set, yet."); // PCG iterations const int old_precision = std::cout.precision(); @@ -600,7 +597,7 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co normResIni = Res->norm2(); Z->putScalar(SC_zero); - RegionMgCycleAdapter(numLevels, cycleType, regHierarchy, + RegionMgCycleAdapter(cycleType, regHierarchy, Z, Res, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); P->update(SC_one, *Z, SC_zero); // deep copy values of Z into P @@ -635,7 +632,7 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co } Z->putScalar(SC_zero); - RegionMgCycleAdapter(numLevels, cycleType, regHierarchy, + RegionMgCycleAdapter(cycleType, regHierarchy, Z, Res, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); @@ -679,7 +676,6 @@ void solveCompositeProblemRichardson(const double tol, const bool scaleResidualH const Scalar SC_one = STS::one(); // we start by extracting some basic data from the hierarchy - const int numLevels = regHierarchy->GetNumLevels(); RCP level0 = regHierarchy->GetLevel(0); RCP regMat = level0->Get >("A"); RCP revisedRowMap = regMat->getRowMap(); @@ -710,7 +706,7 @@ void solveCompositeProblemRichardson(const double tol, const bool scaleResidualH else out << "Using unscaled residual norm." << std::endl; - TEUCHOS_TEST_FOR_EXCEPT_MSG(!(numLevels>0), "We require numLevel > 0. Probably, numLevel has not been set, yet."); + TEUCHOS_TEST_FOR_EXCEPT_MSG(!(regHierarchy->GetNumLevels()>0), "We require numLevel > 0. Probably, numLevel has not been set, yet."); // Richardson iterations const int old_precision = std::cout.precision(); @@ -749,7 +745,7 @@ void solveCompositeProblemRichardson(const double tol, const bool scaleResidualH break; } - RegionMgCycleAdapter(numLevels, cycleType, regHierarchy, + RegionMgCycleAdapter(cycleType, regHierarchy, Correct, Res, smootherParams, zeroInitGuess, coarseSolverData, hierarchyData); From 1a749fbd6bf28bc8346ff3e31845a66c438e53cc Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Tue, 22 Mar 2022 10:26:28 +0100 Subject: [PATCH 049/147] MueLu: fix indentation in region code --- .../regionMG/src/SolveRegionHierarchy_def.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp index 49e48b3e5e7c..79efaaaf7c4f 100644 --- a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp +++ b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp @@ -691,13 +691,13 @@ void solveCompositeProblemRichardson(const double tol, const bool scaleResidualH // Prepare output of residual norm to file RCP log; if (myRank == 0) - { - log = rcp(new std::ofstream(convergenceLog.c_str())); - (*log) << "# num procs = " << dofMap->getComm()->getSize() << "\n" - << "# iteration | res-norm (scaled=" << scaleResidualHist << ")\n" - << "#\n"; - *log << std::setprecision(16) << std::scientific; - } + { + log = rcp(new std::ofstream(convergenceLog.c_str())); + (*log) << "# num procs = " << dofMap->getComm()->getSize() << "\n" + << "# iteration | res-norm (scaled=" << scaleResidualHist << ")\n" + << "#\n"; + *log << std::setprecision(16) << std::scientific; + } // Print type of residual norm to the screen out << "Using Richardson solver" << std::endl; From 2a13ed3483b534c43e2d0370ed091aaade82541d Mon Sep 17 00:00:00 2001 From: Matthias Mayr Date: Tue, 22 Mar 2022 10:26:51 +0100 Subject: [PATCH 050/147] MueLu: remove unused variables from region code --- .../research/regionMG/src/SolveRegionHierarchy_def.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp index 79efaaaf7c4f..8f966ed7f031 100644 --- a/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp +++ b/packages/muelu/research/regionMG/src/SolveRegionHierarchy_def.hpp @@ -543,9 +543,6 @@ void solveCompositeProblemPCG(const double tol, const bool scaleResidualHist, co // we start by extracting some basic data from the hierarchy RCP level0 = regHierarchy->GetLevel(0); - RCP regMat = level0->Get >("A"); - RCP revisedRowMap = regMat->getRowMap(); - RCP rowImport = level0->Get >("rowImport"); RCP dofMap = X->getMap(); const int myRank = dofMap->getComm()->getRank(); @@ -677,9 +674,6 @@ void solveCompositeProblemRichardson(const double tol, const bool scaleResidualH // we start by extracting some basic data from the hierarchy RCP level0 = regHierarchy->GetLevel(0); - RCP regMat = level0->Get >("A"); - RCP revisedRowMap = regMat->getRowMap(); - RCP rowImport = level0->Get >("rowImport"); RCP dofMap = X->getMap(); const int myRank = dofMap->getComm()->getRank(); From 15d0f392d79bbc4b5495a96db5786e2f72e053b2 Mon Sep 17 00:00:00 2001 From: meriadeg perrinel Date: Tue, 22 Mar 2022 14:43:12 +0100 Subject: [PATCH 051/147] Zoltan2: SphynProblem inherits now from PartioningProblem --- .../problems/Zoltan2_PartitioningProblem.hpp | 590 ++++++++++-------- .../src/Zoltan2_SphynxRefactoredProblem.hpp | 244 ++++++++ packages/zoltan2/test/sphynx/CMakeLists.txt | 130 ++++ .../test/sphynx/Test_SphynxRefactored.cpp | 461 ++++++++++++++ 4 files changed, 1157 insertions(+), 268 deletions(-) create mode 100644 packages/zoltan2/sphynx/src/Zoltan2_SphynxRefactoredProblem.hpp create mode 100644 packages/zoltan2/test/sphynx/Test_SphynxRefactored.cpp diff --git a/packages/zoltan2/core/src/problems/Zoltan2_PartitioningProblem.hpp b/packages/zoltan2/core/src/problems/Zoltan2_PartitioningProblem.hpp index 1049136f7b42..4fa907e85756 100644 --- a/packages/zoltan2/core/src/problems/Zoltan2_PartitioningProblem.hpp +++ b/packages/zoltan2/core/src/problems/Zoltan2_PartitioningProblem.hpp @@ -256,23 +256,56 @@ class PartitioningProblem : public Problem void setMachine(MachineRepresentation *machine); */ + /*! \brief Set up validators specific to this algorithm + */ + static void getSphynxValidParameters(ParameterList & pl) + { + + RCP sphynx_preconditionner_type_method_Validator = + Teuchos::rcp( new Teuchos::StringValidator(Teuchos::tuple( "muelu", "jacobi", "polynomial"))); + + pl.set("sphynx_preconditioner_type", "polynomial", "Sphynx preconditioner type", sphynx_preconditionner_type_method_Validator); + + + RCP sphynx_initial_guess_method_Validator = + Teuchos::rcp( new Teuchos::StringValidator(Teuchos::tuple( "random", "constants"))); + + pl.set("sphynx_initial_guess", "random", "Sphynx initial guess", sphynx_initial_guess_method_Validator); + + RCP sphynx_problem_type_method_Validator = + Teuchos::rcp( new Teuchos::StringValidator(Teuchos::tuple( "combinatorial", "normalized", "generalized"))); + + pl.set("sphynx_problem_type", "combinatorial", "Sphynx problem type", sphynx_problem_type_method_Validator); + + RCP> sphynx_verbosity_validator = + Teuchos::rcp( new Teuchos::EnhancedNumberValidator(0, 1) ); + pl.set("sphynx_verbosity", 0, "Sphynx verbosity.", sphynx_verbosity_validator); + + // bool parameter + pl.set("sphynx_skip_preprocessing", false, "Sphynx skip preprocessing.", Environment::getBoolValidator()); + pl.set("sphynx_use_full_ortho", true, "Sphynx use full ortho.", Environment::getBoolValidator()); + } + /*! \brief Set up validators specific to this Problem */ static void getValidParameters(ParameterList & pl) { Zoltan2_AlgMJ::getValidParameters(pl); + AlgPuLP::getValidParameters(pl); + AlgQuotient::getValidParameters(pl); AlgPTScotch::getValidParameters(pl); AlgSerialGreedy::getValidParameters(pl); AlgForTestingOnly::getValidParameters(pl); + getSphynxValidParameters(pl); // MPL NOT THE GOOD PLACE !!! // This set up does not use tuple because we didn't have constructors // that took that many elements - Tuple will need to be modified and I // didn't want to have low level changes with this particular refactor // TO DO: Add more Tuple constructors and then redo this code to be // Teuchos::tuple algorithm_names( "rcb", "multijagged" ... ); - Array algorithm_names(19); + Array algorithm_names(20); algorithm_names[0] = "rcb"; algorithm_names[1] = "multijagged"; algorithm_names[2] = "rib"; @@ -292,6 +325,7 @@ class PartitioningProblem : public Problem algorithm_names[16] = "random"; algorithm_names[17] = "zoltan"; algorithm_names[18] = "forTestingOnly"; + algorithm_names[19] = "sphynx"; RCP algorithm_Validator = Teuchos::rcp( new Teuchos::StringValidator( algorithm_names )); pl.set("algorithm", "random", "partitioning algorithm", @@ -375,10 +409,13 @@ class PartitioningProblem : public Problem "hypergraph ghost method", ghost_layers_Validator); } -private: +protected: void initializeProblem(); + virtual void processAlgorithmName(const std::string& algorithm, const std::string& defString, const std::string& model, + Environment &env, bool& removeSelfEdges, bool& needConsecutiveGlobalIds); void createPartitioningProblem(bool newData); + virtual void createAlgorithm(); RCP > solution_; #ifdef ZOLTAN2_TASKMAPPING_MOVE @@ -525,6 +562,89 @@ template partSizes_[criteria] = arcp(z2_partSizes, 0, len, own_memory); } + template + void PartitioningProblem::createAlgorithm() + { + std::cout << "PartitioningProblem::createAlgorithm" << std::endl; + // Create the algorithm + if (algName_ == std::string("multijagged")) { + this->algorithm_ = rcp(new Zoltan2_AlgMJ(this->envConst_, + this->comm_, + this->coordinateModel_)); + } + else if (algName_ == std::string("zoltan")) { + this->algorithm_ = rcp(new AlgZoltan(this->envConst_, + this->comm_, + this->baseInputAdapter_)); + } + else if (algName_ == std::string("parma")) { + this->algorithm_ = rcp(new AlgParMA(this->envConst_, + this->comm_, + this->baseInputAdapter_)); + } + else if (algName_ == std::string("scotch")) { + this->algorithm_ = rcp(new AlgPTScotch(this->envConst_, + this->comm_, + this->baseInputAdapter_)); + } + else if (algName_ == std::string("parmetis")) { + using model_t = GraphModel; + this->algorithm_ = rcp(new AlgParMETIS(this->envConst_, + this->comm_, + this->graphModel_)); + } + else if (algName_ == std::string("quotient")) { + this->algorithm_ = rcp(new AlgQuotient(this->envConst_, + this->comm_, + this->baseInputAdapter_)); + //"parmetis")); // The default alg. to use inside Quotient + } // is ParMETIS for now. + else if (algName_ == std::string("pulp")) { + this->algorithm_ = rcp(new AlgPuLP(this->envConst_, + this->comm_, + this->baseInputAdapter_)); + } + else if (algName_ == std::string("block")) { + this->algorithm_ = rcp(new AlgBlock(this->envConst_, + this->comm_, this->identifierModel_)); + } + else if (algName_ == std::string("phg") || + algName_ == std::string("patoh")) { + // phg and patoh provided through Zoltan + Teuchos::ParameterList &pl = this->env_->getParametersNonConst(); + Teuchos::ParameterList &zparams = pl.sublist("zoltan_parameters",false); + if (numberOfWeights_ > 0) { + char strval[20]; + sprintf(strval, "%d", numberOfWeights_); + zparams.set("OBJ_WEIGHT_DIM", strval); + } + zparams.set("LB_METHOD", algName_.c_str()); + zparams.set("LB_APPROACH", "PARTITION"); + algName_ = std::string("zoltan"); + + this->algorithm_ = rcp(new AlgZoltan(this->envConst_, + this->comm_, + this->baseInputAdapter_)); + } + else if (algName_ == std::string("sarma")) { + this->algorithm_ = rcp(new AlgSarma(this->envConst_, + this->comm_, + this->baseInputAdapter_)); + } + else if (algName_ == std::string("forTestingOnly")) { + this->algorithm_ = rcp(new AlgForTestingOnly(this->envConst_, + this->comm_, + this->baseInputAdapter_)); + } + // else if (algName_ == std::string("rcb")) { + // this->algorithm_ = rcp(new AlgRCB(this->envConst_,this->comm_, + // this->coordinateModel_)); + // } + else { + throw std::logic_error("partitioning algorithm not supported"); + } + } + template void PartitioningProblem::solve(bool updateInputData) { @@ -546,85 +666,9 @@ void PartitioningProblem::solve(bool updateInputData) // Create the algorithm try { - if (algName_ == std::string("multijagged")) { - this->algorithm_ = rcp(new Zoltan2_AlgMJ(this->envConst_, - this->comm_, - this->coordinateModel_)); - } - else if (algName_ == std::string("zoltan")) { - this->algorithm_ = rcp(new AlgZoltan(this->envConst_, - this->comm_, - this->baseInputAdapter_)); - } - else if (algName_ == std::string("parma")) { - this->algorithm_ = rcp(new AlgParMA(this->envConst_, - this->comm_, - this->baseInputAdapter_)); - } - else if (algName_ == std::string("scotch")) { - this->algorithm_ = rcp(new AlgPTScotch(this->envConst_, - this->comm_, - this->baseInputAdapter_)); - } - else if (algName_ == std::string("parmetis")) { - using model_t = GraphModel; - this->algorithm_ = rcp(new AlgParMETIS(this->envConst_, - this->comm_, - this->graphModel_)); - } - else if (algName_ == std::string("quotient")) { - this->algorithm_ = rcp(new AlgQuotient(this->envConst_, - this->comm_, - this->baseInputAdapter_)); - //"parmetis")); // The default alg. to use inside Quotient - } // is ParMETIS for now. - else if (algName_ == std::string("pulp")) { - this->algorithm_ = rcp(new AlgPuLP(this->envConst_, - this->comm_, - this->baseInputAdapter_)); - } - else if (algName_ == std::string("block")) { - this->algorithm_ = rcp(new AlgBlock(this->envConst_, - this->comm_, this->identifierModel_)); - } - else if (algName_ == std::string("phg") || - algName_ == std::string("patoh")) { - // phg and patoh provided through Zoltan - Teuchos::ParameterList &pl = this->env_->getParametersNonConst(); - Teuchos::ParameterList &zparams = pl.sublist("zoltan_parameters",false); - if (numberOfWeights_ > 0) { - char strval[20]; - sprintf(strval, "%d", numberOfWeights_); - zparams.set("OBJ_WEIGHT_DIM", strval); - } - zparams.set("LB_METHOD", algName_.c_str()); - zparams.set("LB_APPROACH", "PARTITION"); - algName_ = std::string("zoltan"); - - this->algorithm_ = rcp(new AlgZoltan(this->envConst_, - this->comm_, - this->baseInputAdapter_)); - } - else if (algName_ == std::string("sarma")) { - this->algorithm_ = rcp(new AlgSarma(this->envConst_, - this->comm_, - this->baseInputAdapter_)); - } - else if (algName_ == std::string("forTestingOnly")) { - this->algorithm_ = rcp(new AlgForTestingOnly(this->envConst_, - this->comm_, - this->baseInputAdapter_)); - } - // else if (algName_ == std::string("rcb")) { - // this->algorithm_ = rcp(new AlgRCB(this->envConst_,this->comm_, - // this->coordinateModel_)); - // } - else { - throw std::logic_error("partitioning algorithm not supported"); - } + this->createAlgorithm(); } Z2_FORWARD_EXCEPTIONS; - // Create the solution this->env_->timerStart(MACRO_TIMERS, "create solution"); PartitioningSolution *soln = NULL; @@ -702,6 +746,204 @@ void PartitioningProblem::solve(bool updateInputData) this->env_->debug(DETAILED_STATUS, "Exiting solve"); } +template +void PartitioningProblem::processAlgorithmName(const std::string& algorithm, const std::string& defString, const std::string& model, + Environment &env, bool& removeSelfEdges, bool& needConsecutiveGlobalIds) { + ParameterList &pl = env.getParametersNonConst(); + + if (algorithm != defString) + { + + // Figure out the model required by the algorithm + if (algorithm == std::string("block") || + algorithm == std::string("random") || + algorithm == std::string("cyclic") ){ + + //modelType_ = IdentifierModelType; + modelAvail_[IdentifierModelType] = true; + + algName_ = algorithm; + } + else if (algorithm == std::string("zoltan") || + algorithm == std::string("parma") || + algorithm == std::string("forTestingOnly")) + { + algName_ = algorithm; + } + else if (algorithm == std::string("rcb") || + algorithm == std::string("rib") || + algorithm == std::string("hsfc")) + { + // rcb, rib, hsfc provided through Zoltan + Teuchos::ParameterList &zparams = pl.sublist("zoltan_parameters",false); + zparams.set("LB_METHOD", algorithm); + if (numberOfWeights_ > 0) { + char strval[20]; + sprintf(strval, "%d", numberOfWeights_); + zparams.set("OBJ_WEIGHT_DIM", strval); + } + algName_ = std::string("zoltan"); + } + else if (algorithm == std::string("multijagged")) + { + //modelType_ = CoordinateModelType; + modelAvail_[CoordinateModelType]=true; + + algName_ = algorithm; + } + else if (algorithm == std::string("metis") || + algorithm == std::string("parmetis")) + { + + //modelType_ = GraphModelType; + modelAvail_[GraphModelType]=true; + algName_ = algorithm; + removeSelfEdges = true; + needConsecutiveGlobalIds = true; + } + else if (algorithm == std::string("quotient")) + { + algName_ = algorithm; + } + else if (algorithm == std::string("scotch") || + algorithm == std::string("ptscotch")) // BDD: Don't construct graph for scotch here + { + algName_ = algorithm; + } + else if (algorithm == std::string("pulp")) + { + algName_ = algorithm; + } + else if (algorithm == std::string("sarma")) + { + algName_ = algorithm; + } + else if (algorithm == std::string("patoh") || + algorithm == std::string("phg")) + { + // if ((modelType_ != GraphModelType) && + // (modelType_ != HypergraphModelType) ) + if ((modelAvail_[GraphModelType]==false) && + (modelAvail_[HypergraphModelType]==false) ) + { + //modelType_ = HypergraphModelType; + modelAvail_[HypergraphModelType]=true; + } + algName_ = algorithm; + } + else + { + // Parameter list should ensure this does not happen. + throw std::logic_error("parameter list algorithm is invalid"); + } + } + else if (model != defString) + { + // Figure out the algorithm suggested by the model. + if (model == std::string("hypergraph")) + { + //modelType_ = HypergraphModelType; + modelAvail_[HypergraphModelType]=true; + + algName_ = std::string("phg"); + } + else if (model == std::string("graph")) + { + //modelType_ = GraphModelType; + modelAvail_[GraphModelType]=true; + + #ifdef HAVE_ZOLTAN2_SCOTCH + modelAvail_[GraphModelType]=false; // graph constructed by AlgPTScotch + if (this->comm_->getSize() > 1) + algName_ = std::string("ptscotch"); + else + algName_ = std::string("scotch"); + #else + #ifdef HAVE_ZOLTAN2_PARMETIS + if (this->comm_->getSize() > 1) + algName_ = std::string("parmetis"); + else + algName_ = std::string("metis"); + removeSelfEdges = true; + needConsecutiveGlobalIds = true; + #else + #ifdef HAVE_ZOLTAN2_PULP + // TODO: XtraPuLP + //if (this->comm_->getSize() > 1) + // algName_ = std::string("xtrapulp"); + //else + algName_ = std::string("pulp"); + #else + algName_ = std::string("phg"); + #endif + #endif + #endif + } + else if (model == std::string("geometry")) + { + //modelType_ = CoordinateModelType; + modelAvail_[CoordinateModelType]=true; + + algName_ = std::string("multijagged"); + } + else if (model == std::string("ids")) + { + //modelType_ = IdentifierModelType; + modelAvail_[IdentifierModelType]=true; + + algName_ = std::string("block"); + } + else + { + // Parameter list should ensure this does not happen. + env.localBugAssertion(__FILE__, __LINE__, + "parameter list model type is invalid", 1, BASIC_ASSERTION); + } + } + else + { + // Determine an algorithm and model suggested by the input type. + // TODO: this is a good time to use the time vs. quality parameter + // in choosing an algorithm, and setting some parameters + + if (inputType_ == MatrixAdapterType) + { + //modelType_ = HypergraphModelType; + modelAvail_[HypergraphModelType]=true; + + algName_ = std::string("phg"); + } + else if (inputType_ == GraphAdapterType || + inputType_ == MeshAdapterType) + { + //modelType_ = GraphModelType; + modelAvail_[GraphModelType]=true; + + algName_ = std::string("phg"); + } + else if (inputType_ == VectorAdapterType) + { + //modelType_ = CoordinateModelType; + modelAvail_[CoordinateModelType]=true; + + algName_ = std::string("multijagged"); + } + else if (inputType_ == IdentifierAdapterType) + { + //modelType_ = IdentifierModelType; + modelAvail_[IdentifierModelType]=true; + + algName_ = std::string("block"); + } + else{ + // This should never happen + throw std::logic_error("input type is invalid"); + } + } + + +} + template void PartitioningProblem::createPartitioningProblem(bool newData) { @@ -785,195 +1027,7 @@ void PartitioningProblem::createPartitioningProblem(bool newData) // Determine algorithm, model, and algorithm requirements. This // is a first pass. Feel free to change this and add to it. - if (algorithm != defString) - { - - // Figure out the model required by the algorithm - if (algorithm == std::string("block") || - algorithm == std::string("random") || - algorithm == std::string("cyclic") ){ - - //modelType_ = IdentifierModelType; - modelAvail_[IdentifierModelType] = true; - - algName_ = algorithm; - } - else if (algorithm == std::string("zoltan") || - algorithm == std::string("parma") || - algorithm == std::string("forTestingOnly")) - { - algName_ = algorithm; - } - else if (algorithm == std::string("rcb") || - algorithm == std::string("rib") || - algorithm == std::string("hsfc")) - { - // rcb, rib, hsfc provided through Zoltan - Teuchos::ParameterList &zparams = pl.sublist("zoltan_parameters",false); - zparams.set("LB_METHOD", algorithm); - if (numberOfWeights_ > 0) { - char strval[20]; - sprintf(strval, "%d", numberOfWeights_); - zparams.set("OBJ_WEIGHT_DIM", strval); - } - algName_ = std::string("zoltan"); - } - else if (algorithm == std::string("multijagged")) - { - //modelType_ = CoordinateModelType; - modelAvail_[CoordinateModelType]=true; - - algName_ = algorithm; - } - else if (algorithm == std::string("metis") || - algorithm == std::string("parmetis")) - { - - //modelType_ = GraphModelType; - modelAvail_[GraphModelType]=true; - algName_ = algorithm; - removeSelfEdges = true; - needConsecutiveGlobalIds = true; - } - else if (algorithm == std::string("quotient")) - { - algName_ = algorithm; - } - else if (algorithm == std::string("scotch") || - algorithm == std::string("ptscotch")) // BDD: Don't construct graph for scotch here - { - algName_ = algorithm; - } - else if (algorithm == std::string("pulp")) - { - algName_ = algorithm; - } - else if (algorithm == std::string("sarma")) - { - algName_ = algorithm; - } - else if (algorithm == std::string("patoh") || - algorithm == std::string("phg")) - { - // if ((modelType_ != GraphModelType) && - // (modelType_ != HypergraphModelType) ) - if ((modelAvail_[GraphModelType]==false) && - (modelAvail_[HypergraphModelType]==false) ) - { - //modelType_ = HypergraphModelType; - modelAvail_[HypergraphModelType]=true; - } - algName_ = algorithm; - } - else - { - // Parameter list should ensure this does not happen. - throw std::logic_error("parameter list algorithm is invalid"); - } - } - else if (model != defString) - { - // Figure out the algorithm suggested by the model. - if (model == std::string("hypergraph")) - { - //modelType_ = HypergraphModelType; - modelAvail_[HypergraphModelType]=true; - - algName_ = std::string("phg"); - } - else if (model == std::string("graph")) - { - //modelType_ = GraphModelType; - modelAvail_[GraphModelType]=true; - -#ifdef HAVE_ZOLTAN2_SCOTCH - modelAvail_[GraphModelType]=false; // graph constructed by AlgPTScotch - if (this->comm_->getSize() > 1) - algName_ = std::string("ptscotch"); - else - algName_ = std::string("scotch"); -#else -#ifdef HAVE_ZOLTAN2_PARMETIS - if (this->comm_->getSize() > 1) - algName_ = std::string("parmetis"); - else - algName_ = std::string("metis"); - removeSelfEdges = true; - needConsecutiveGlobalIds = true; -#else -#ifdef HAVE_ZOLTAN2_PULP - // TODO: XtraPuLP - //if (this->comm_->getSize() > 1) - // algName_ = std::string("xtrapulp"); - //else - algName_ = std::string("pulp"); -#else - algName_ = std::string("phg"); -#endif -#endif -#endif - } - else if (model == std::string("geometry")) - { - //modelType_ = CoordinateModelType; - modelAvail_[CoordinateModelType]=true; - - algName_ = std::string("multijagged"); - } - else if (model == std::string("ids")) - { - //modelType_ = IdentifierModelType; - modelAvail_[IdentifierModelType]=true; - - algName_ = std::string("block"); - } - else - { - // Parameter list should ensure this does not happen. - env.localBugAssertion(__FILE__, __LINE__, - "parameter list model type is invalid", 1, BASIC_ASSERTION); - } - } - else - { - // Determine an algorithm and model suggested by the input type. - // TODO: this is a good time to use the time vs. quality parameter - // in choosing an algorithm, and setting some parameters - - if (inputType_ == MatrixAdapterType) - { - //modelType_ = HypergraphModelType; - modelAvail_[HypergraphModelType]=true; - - algName_ = std::string("phg"); - } - else if (inputType_ == GraphAdapterType || - inputType_ == MeshAdapterType) - { - //modelType_ = GraphModelType; - modelAvail_[GraphModelType]=true; - - algName_ = std::string("phg"); - } - else if (inputType_ == VectorAdapterType) - { - //modelType_ = CoordinateModelType; - modelAvail_[CoordinateModelType]=true; - - algName_ = std::string("multijagged"); - } - else if (inputType_ == IdentifierAdapterType) - { - //modelType_ = IdentifierModelType; - modelAvail_[IdentifierModelType]=true; - - algName_ = std::string("block"); - } - else{ - // This should never happen - throw std::logic_error("input type is invalid"); - } - } + this->processAlgorithmName(algorithm, defString, model, env, removeSelfEdges, needConsecutiveGlobalIds); // Hierarchical partitioning? diff --git a/packages/zoltan2/sphynx/src/Zoltan2_SphynxRefactoredProblem.hpp b/packages/zoltan2/sphynx/src/Zoltan2_SphynxRefactoredProblem.hpp new file mode 100644 index 000000000000..e5e839c37195 --- /dev/null +++ b/packages/zoltan2/sphynx/src/Zoltan2_SphynxRefactoredProblem.hpp @@ -0,0 +1,244 @@ +// @HEADER +// +// *********************************************************************** +// +// Sphynx +// Copyright 2020 National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Seher Acer (sacer@sandia.gov) +// Erik Boman (egboman@sandia.gov) +// Siva Rajamanickam (srajama@sandia.gov) +// Karen Devine (kddevin@sandia.gov) +// +// *********************************************************************** +// +// @HEADER +#ifndef _ZOLTAN2_SPHYNXREFACTOREDPROBLEM_HPP_ +#define _ZOLTAN2_SPHYNXREFACTOREDPROBLEM_HPP_ + + +//////////////////////////////////////////////////////////////////////////////// +// This file contains the implementation of SphynxRefactoredProblem. +// +// SphynxRefactoredProblem is a subset of PartitioningProblem in Zoltan2Core. This subset +// only consists of the functionality and data members needed by Sphynx. +// +// SphynxRefactoredProblem acts as an interface between user and the Sphynx algorithm. +// User creates the SphynxRefactoredProblem object on her adapter and calls solve() to +// get a partitioning solution. +// +//////////////////////////////////////////////////////////////////////////////// + +#include "Zoltan2_PartitioningSolution.hpp" +#include "Zoltan2_Sphynx.hpp" +#include + +namespace Zoltan2 { + + +/*! \brief Set up validators specific to this algorithm + */ +static void getSphynxValidParameters(ParameterList & pl) +{ + + RCP sphynx_preconditionner_type_method_Validator = + Teuchos::rcp( new Teuchos::StringValidator(Teuchos::tuple( "muelu", "jacobi", "polynomial"))); + + pl.set("sphynx_preconditioner_type", "polynomial", "Sphynx preconditioner type", sphynx_preconditionner_type_method_Validator); + + + RCP sphynx_initial_guess_method_Validator = + Teuchos::rcp( new Teuchos::StringValidator(Teuchos::tuple( "random", "constants"))); + + pl.set("sphynx_initial_guess", "random", "Sphynx initial guess", sphynx_initial_guess_method_Validator); + + RCP sphynx_problem_type_method_Validator = + Teuchos::rcp( new Teuchos::StringValidator(Teuchos::tuple( "combinatorial", "normalized", "generalized"))); + + pl.set("sphynx_problem_type", "combinatorial", "Sphynx problem type", sphynx_problem_type_method_Validator); + + RCP> sphynx_verbosity_validator = + Teuchos::rcp( new Teuchos::EnhancedNumberValidator(0, 1) ); + pl.set("sphynx_verbosity", 0, "Sphynx verbosity.", sphynx_verbosity_validator); + + // bool parameter + pl.set("sphynx_skip_preprocessing", false, "Sphynx skip preprocessing.", Environment::getBoolValidator()); + pl.set("sphynx_use_full_ortho", true, "Sphynx use full ortho.", Environment::getBoolValidator()); +} + + + template + class SphynxRefactoredProblem : public PartitioningProblem + { + + public: + + using part_t = typename Adapter::part_t; + using weight_t = typename Adapter::scalar_t; + typedef typename Adapter::base_adapter_t base_adapter_t; // CHeck to Remove + + /////////////////////////////////////////////////////////////////////////// + ///////////////////////// CONSTRUCTORS //////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + // Constructor where Teuchos communicator is specified + SphynxRefactoredProblem(Adapter *A, + Teuchos::ParameterList *p, + const RCP > &comm): + PartitioningProblem(A, p, comm) + { +// this->numberOfWeights_ = this->inputAdapter_->getNumWeightsPerID(); +// this->numberOfCriteria_ = (this->numberOfWeights_ > 1) ? this->numberOfWeights_ : 1; + +// Teuchos::ArrayRCP *noIds = +// new Teuchos::ArrayRCP [this->numberOfCriteria_]; +// Teuchos::ArrayRCP *noSizes = +// new Teuchos::ArrayRCP [this->numberOfCriteria_]; + +// this->partIds_ = Teuchos::arcp(noIds, 0, this->numberOfCriteria_, true); +// this->partSizes_ = Teuchos::arcp(noSizes, 0, this->numberOfCriteria_, true); + +// int nparts = -1; +// const Teuchos::ParameterEntry *pe = params_->getEntryPtr("num_global_parts"); +// if(pe) +// nparts = pe->getValue(&nparts); + +// if(nparts == -1) +// throw std::runtime_error("\nUser did not set num_global_parts" +// "in the parameter list!n"); + + +// envParams_ = Teuchos::rcp(new Teuchos::ParameterList()); +// envParams_->set("num_global_parts", nparts); + +// env_ = Teuchos::rcp(new Environment(*envParams_, comm_)); +// envConst_ = Teuchos::rcp_const_cast(env_); + + } + +#ifdef HAVE_ZOLTAN2_MPI + // Constructor where MPI communicator can be specified + SphynxRefactoredProblem(Adapter *A, ParameterList *p, MPI_Comm mpicomm): + SphynxRefactoredProblem(A, p, + rcp >(new Teuchos::MpiComm( + Teuchos::opaqueWrapper(mpicomm)))) + {} +#endif + + // Constructor where communicator is the Teuchos default. + SphynxRefactoredProblem(Adapter *A, ParameterList *p): + SphynxRefactoredProblem(A, p, Tpetra::getDefaultComm()) + {} + + // Destructor + ~SphynxRefactoredProblem() {}; + + /////////////////////////////////////////////////////////////////////////// + ///////////////////// FORWARD DECLARATIONS /////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + +// void solve(); + //! \brief Direct the problem to create a solution. + // + // \param updateInputData If true this indicates that either + // this is the first attempt at solution, or that we + // are computing a new solution and the input data has + // changed since the previous solution was computed. + // By input data we mean coordinates, topology, or weights. + // If false, this indicates that we are computing a + // new solution using the same input data was used for + // the previous solution, even though the parameters + // may have been changed. + // + // For the sake of performance, we ask the caller to set \c updateInputData + // to false if he/she is computing a new solution using the same input data, + // but different problem parameters, than that which was used to compute + // the most recent solution. + +// void solve(bool updateInputData=true) override; + + + void createAlgorithm() override; + void processAlgorithmName(const std::string& algorithm, const std::string& defString, const std::string& model, + Environment &env, bool& removeSelfEdges, bool& needConsecutiveGlobalIds) override; + + /////////////////////////////////////////////////////////////////////////// + /////////////////////// MEMBER FUNCTIONS ///////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + + const PartitioningSolution &getSolution() { + return *(this->solution_.getRawPtr()); + }; + + /////////////////////////////////////////////////////////////////////////// + ///////////////////////////// DATA MEMBERS //////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + private: + Teuchos::RCP envParams_; + + }; + + /////////////////////////////////////////////////////////////////////////// + /////////////////////// MORE MEMBER FUNCTIONS //////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + + template + void SphynxRefactoredProblem::processAlgorithmName(const std::string& algorithm, const std::string& defString, const std::string& model, + Environment &env, bool& removeSelfEdges, bool& needConsecutiveGlobalIds) { + this->algName_ = std::string("sphynx"); + std::cout << "SphynxRefactoredProblem::createAlgorithm " << std::endl; +} + + template + void SphynxRefactoredProblem::createAlgorithm() + { + std::cout << "SphynxRefactoredProblem::createAlgorithm" << std::endl; + // Create the algorithm + if (this->algName_ == std::string("sphynx")) { + this->algorithm_ = Teuchos::rcp(new Zoltan2::Sphynx(this->envConst_, + this->params_, + this->comm_, + this->inputAdapter_)); + } + else { + throw std::logic_error("partitioning algorithm not supported"); + } + } + +} // namespace Zoltan2 + +#endif diff --git a/packages/zoltan2/test/sphynx/CMakeLists.txt b/packages/zoltan2/test/sphynx/CMakeLists.txt index 3480e9517819..78d1cd5f3928 100644 --- a/packages/zoltan2/test/sphynx/CMakeLists.txt +++ b/packages/zoltan2/test/sphynx/CMakeLists.txt @@ -128,6 +128,136 @@ IF(Trilinos_ENABLE_MueLu) ) ENDIF() +TRIBITS_ADD_EXECUTABLE_AND_TEST( + SphynxRefactored + SOURCES Test_SphynxRefactored.cpp + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + "--inputFile=simple" + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) + +TRIBITS_ADD_TEST( + SphynxRefactored + NAME SphynxRefactored_VWeights + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + "--inputFile=simple --vertexWeights=3" + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) + +TRIBITS_ADD_TEST( + SphynxRefactored + NAME SphynxRefactored_OneProc_VWeights + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + "--inputFile=simple --no-distribute --vertexWeights=1" + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) + +TRIBITS_ADD_TEST( + SphynxRefactored + NAME SphynxRefactored_NormalizedLaplacian + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + "--inputFile=simple --normalized" + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) + +TRIBITS_ADD_TEST( + SphynxRefactored + NAME SphynxRefactored_GeneralizedLaplacian + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + "--inputFile=simple --generalized" + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) + + +TRIBITS_ADD_TEST( + SphynxRefactored + NAME SphynxRefactored_ConstantsInitialGuess + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + "--inputFile=simple --initialGuess=constants" + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) + + +TRIBITS_ADD_TEST( + SphynxRefactored + NAME SphynxRefactored_PartialOrtho + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + "--inputFile=simple --partialOrtho" + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) + + +IF(Trilinos_ENABLE_Galeri) + TRIBITS_ADD_TEST( + SphynxRefactored + NAME SphynxRefactored_Galeri + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) + + TRIBITS_ADD_TEST( + SphynxRefactored + NAME SphynxRefactored_Galeri_VWeights + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + "--vertexWeights=3" + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) + +ENDIF() + +IF(Trilinos_ENABLE_MueLu) + TRIBITS_ADD_TEST( + SphynxRefactored + NAME SphynxRefactored_PolyPrec + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + "--inputFile=simple --precond=polynomial" + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) +ENDIF() + +IF(Trilinos_ENABLE_MueLu) + TRIBITS_ADD_TEST( + SphynxRefactored + NAME SphynxRefactored_JacobiPrec + NUM_MPI_PROCS 4 + COMM serial mpi + ARGS + "--inputFile=simple --precond=jacobi" + PASS_REGULAR_EXPRESSION "PASS" + FAIL_REGULAR_EXPRESSION "FAIL" + ) +ENDIF() + # Command that copies files to the executable directory. TRIBITS_COPY_FILES_TO_BINARY_DIR(copy_files_for_sphynx_tests diff --git a/packages/zoltan2/test/sphynx/Test_SphynxRefactored.cpp b/packages/zoltan2/test/sphynx/Test_SphynxRefactored.cpp new file mode 100644 index 000000000000..9791501d0af1 --- /dev/null +++ b/packages/zoltan2/test/sphynx/Test_SphynxRefactored.cpp @@ -0,0 +1,461 @@ +// @HEADER +// +// *********************************************************************** +// +// Zoltan2: A package of combinatorial algorithms for scientific computing +// Copyright 2012 Sandia Corporation +// +// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Seher Acer (sacer@sandia.gov) +// Erik Boman (egboman@sandia.gov) +// Siva Rajamanickam (srajama@sandia.gov) +// Karen Devine (kddevin@sandia.gov) +// +// *********************************************************************** +// +// @HEADER +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using Teuchos::RCP; + +///////////////////////////////////////////////////////////////////////////// +// This program is a modified version of partitioning1.cpp (Karen Devine, 2011) +// which can be found in zoltan2/test/core/partition/. +// This version demonstrates use of Sphynx to partition a Tpetra matrix +// (read from a MatrixMarket file or generated by Galeri::Xpetra). +// Usage: +// Zoltan2_Sphynx.exe [--inputFile=filename] [--outputFile=outfile] [--verbose] +// [--x=#] [--y=#] [--z=#] [--matrix={Laplace1D,Laplace2D,Laplace3D} +// [--normalized] [--generalized] [--polynomial] +///////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////// +// Eventually want to use Teuchos unit tests to vary z2TestLO and +// GO. For now, we set them at compile time based on whether Tpetra +// is built with explicit instantiation on. (in Zoltan2_TestHelpers.hpp) + +typedef zlno_t z2TestLO; +typedef zgno_t z2TestGO; +typedef zscalar_t z2TestScalar; + +typedef Tpetra::CrsMatrix SparseMatrix; +typedef Tpetra::CrsGraph SparseGraph; +typedef Tpetra::Vector VectorT; +typedef VectorT::node_type Node; + +typedef Zoltan2::XpetraCrsMatrixAdapter SparseMatrixAdapter; +typedef Zoltan2::XpetraCrsGraphAdapter SparseGraphAdapter; +typedef Zoltan2::XpetraMultiVectorAdapter MultiVectorAdapter; + + +// Integer vector +typedef Tpetra::Vector IntVector; +typedef Zoltan2::XpetraMultiVectorAdapter IntVectorAdapter; + +#define epsilon 0.00000001 +#define NNZ_IDX 1 + +///////////////////////////////////////////////////////////////////////////// +int main(int narg, char** arg) +{ + std::string inputFile = ""; // Matrix Market or Zoltan file to read + std::string outputFile = ""; // Matrix Market or Zoltan file to write + std::string inputPath = testDataFilePath; // Directory with input file + bool verbose = false; // Verbosity of output + bool distributeInput = true; + bool haveFailure = false; + int nVwgts = 0; + int testReturn = 0; + + // Sphynx-related parameters + bool isNormalized = false; + bool isGeneralized = false; + std::string precType = "jacobi"; + std::string initialGuess = "random"; + bool useFullOrtho = true; + + ////// Establish session. + Tpetra::ScopeGuard tscope(&narg, &arg); + RCP > comm = Tpetra::getDefaultComm(); + int me = comm->getRank(); + int commsize = comm->getSize(); + + // Read run-time options. + Teuchos::CommandLineProcessor cmdp (false, false); + cmdp.setOption("inputPath", &inputPath, + "Path to the MatrixMarket or Zoltan file to be read; " + "if not specified, a default path will be used."); + cmdp.setOption("inputFile", &inputFile, + "Name of the Matrix Market or Zoltan file to read; " + "if not specified, a matrix will be generated by MueLu."); + cmdp.setOption("outputFile", &outputFile, + "Name of the Matrix Market sparse matrix file to write, " + "echoing the input/generated matrix."); + cmdp.setOption("vertexWeights", &nVwgts, + "Number of weights to generate for each vertex"); + cmdp.setOption("verbose", "quiet", &verbose, + "Print messages and results."); + cmdp.setOption("distribute", "no-distribute", &distributeInput, + "indicate whether or not to distribute " + "input across the communicator"); + // Sphynx-related parameters: + cmdp.setOption("normalized", "combinatorial", &isNormalized, + "indicate whether or not to use a normalized Laplacian."); + cmdp.setOption("generalized", "non-generalized", &isGeneralized, + "indicate whether or not to use a generalized Laplacian."); + cmdp.setOption("precond", &precType, + "indicate which preconditioner to use [muelu|jacobi|polynomial]."); + cmdp.setOption("initialGuess", &initialGuess, + "initial guess for LOBPCG"); + cmdp.setOption("useFullOrtho", "partialOrtho", &useFullOrtho, + "use full orthogonalization."); + + ////////////////////////////////// + // Even with cmdp option "true", I get errors for having these + // arguments on the command line. (On redsky build) + // KDDKDD Should just be warnings, right? Code should still work with these + // KDDKDD params in the create-a-matrix file. Better to have them where + // KDDKDD they are used. + int xdim=10; + int ydim=10; + int zdim=10; + std::string matrixType("Laplace3D"); + + cmdp.setOption("x", &xdim, + "number of gridpoints in X dimension for " + "mesh used to generate matrix."); + cmdp.setOption("y", &ydim, + "number of gridpoints in Y dimension for " + "mesh used to generate matrix."); + cmdp.setOption("z", &zdim, + "number of gridpoints in Z dimension for " + "mesh used to generate matrix."); + cmdp.setOption("matrix", &matrixType, + "Matrix type: Laplace1D, Laplace2D, or Laplace3D"); + ////////////////////////////////// + + cmdp.parse(narg, arg); + + RCP uinput; + + if (inputFile != "") // Input file specified; read a matrix + uinput = rcp(new UserInputForTests(inputPath, inputFile, comm, + true, distributeInput)); + + else // Let MueLu generate a default matrix + uinput = rcp(new UserInputForTests(xdim, ydim, zdim, string(""), comm, + true, distributeInput)); + + RCP origMatrix = uinput->getUITpetraCrsMatrix(); + + if (origMatrix->getGlobalNumRows() < 40) { + Teuchos::FancyOStream out(Teuchos::rcp(&std::cout,false)); + origMatrix->describe(out, Teuchos::VERB_EXTREME); + } + + + if (outputFile != "") { + // Just a sanity check. + Tpetra::MatrixMarket::Writer::writeSparseFile(outputFile, + origMatrix, verbose); + } + + if (me == 0) + std::cout << "NumRows = " << origMatrix->getGlobalNumRows() << std::endl + << "NumNonzeros = " << origMatrix->getGlobalNumEntries() << std::endl + << "NumProcs = " << comm->getSize() << std::endl + << "NumLocalRows (rank 0) = " << origMatrix->getLocalNumRows() << std::endl; + + ////// Create a vector to use with the matrix. + RCP origVector, origProd; + origProd = Tpetra::createVector( + origMatrix->getRangeMap()); + origVector = Tpetra::createVector( + origMatrix->getDomainMap()); + origVector->randomize(); + + ////// Specify the Sphynx parameters + Teuchos::RCP params(new Teuchos::ParameterList); + params->set("num_global_parts", commsize); + params->set("sphynx_skip_preprocessing", true); // Preprocessing has not been implemented yet. + params->set("sphynx_preconditioner_type", precType); + params->set("sphynx_verbosity", verbose ? 1 : 0); + params->set("sphynx_initial_guess", initialGuess); + params->set("sphynx_use_full_ortho", useFullOrtho); + std::string problemType = "combinatorial"; + if(isNormalized) + problemType = "normalized"; + else if(isGeneralized) + problemType = "generalized"; + params->set("sphynx_problem_type", problemType); // Type of the eigenvalue problem. + + ////// Create an input adapter for the graph of the Tpetra matrix. + Teuchos::RCP adapter = Teuchos::rcp( new SparseGraphAdapter(origMatrix->getCrsGraph(), nVwgts)); + + ////// Add weights, if requested. + ////// Generate some artificial weights. + ////// Maybe this code should go into UserInputForTests. + + zscalar_t *vwgts = NULL; + if (nVwgts) { + // Test vertex weights with stride nVwgts. + size_t nrows = origMatrix->getLocalNumRows(); + if (nrows) { + vwgts = new zscalar_t[nVwgts * nrows]; + for (size_t i = 0; i < nrows; i++) { + size_t idx = i * nVwgts; + vwgts[idx] = zscalar_t(origMatrix->getRowMap()->getGlobalElement(i)); + for (int j = 1; j < nVwgts; j++) vwgts[idx+j] = 1.; + } + for (int j = 0; j < nVwgts; j++) { + if (j != NNZ_IDX) adapter->setVertexWeights(&vwgts[j], nVwgts, j); + else adapter->setVertexWeightIsDegree(NNZ_IDX); + } + } + } + + ////// Create and solve partitioning problem + Zoltan2::SphynxRefactoredProblem problem(adapter.get(), params.get()); + + try { + if (me == 0) std::cout << "Calling solve() " << std::endl; + + problem.solve(); + + if (me == 0) std::cout << "Done solve() " << std::endl; + } + catch (std::runtime_error &e) { + delete [] vwgts; + std::cout << "Runtime exception returned from solve(): " << e.what(); + if (!strncmp(e.what(), "BUILD ERROR", 11)) { + // Catching build errors as exceptions is OK in the tests + std::cout << " PASS" << std::endl; + return 0; + } + else { + // All other runtime_errors are failures + std::cout << " FAIL" << std::endl; + return -1; + } + } + catch (std::logic_error &e) { + delete [] vwgts; + std::cout << "Logic exception returned from solve(): " << e.what() + << " FAIL" << std::endl; + return -1; + } + catch (std::bad_alloc &e) { + delete [] vwgts; + std::cout << "Bad_alloc exception returned from solve(): " << e.what() + << " FAIL" << std::endl; + return -1; + } + catch (std::exception &e) { + delete [] vwgts; + std::cout << "Unknown exception returned from solve(). " << e.what() + << " FAIL" << std::endl; + return -1; + } + + ///// Basic metric checking of the partitioning solution + ///// Not ordinarily done in application code; just doing it for testing here. + size_t checkNparts = comm->getSize(); + + size_t checkLength = origMatrix->getLocalNumRows(); + const SparseGraphAdapter::part_t *checkParts = problem.getSolution().getPartListView(); + + // Check for load balance + size_t *countPerPart = new size_t[checkNparts]; + size_t *globalCountPerPart = new size_t[checkNparts]; + zscalar_t *wtPerPart = (nVwgts ? new zscalar_t[checkNparts*nVwgts] : NULL); + zscalar_t *globalWtPerPart = (nVwgts ? new zscalar_t[checkNparts*nVwgts] : NULL); + for (size_t i = 0; i < checkNparts; i++) countPerPart[i] = 0; + for (size_t i = 0; i < checkNparts * nVwgts; i++) wtPerPart[i] = 0.; + + for (size_t i = 0; i < checkLength; i++) { + if (size_t(checkParts[i]) >= checkNparts) + std::cout << "Invalid Part " << checkParts[i] << ": FAIL" << std::endl; + countPerPart[checkParts[i]]++; + for (int j = 0; j < nVwgts; j++) { + if (j != NNZ_IDX) + wtPerPart[checkParts[i]*nVwgts+j] += vwgts[i*nVwgts+j]; + else + wtPerPart[checkParts[i]*nVwgts+j] += origMatrix->getNumEntriesInLocalRow(i); + } + } + Teuchos::reduceAll(*comm, Teuchos::REDUCE_SUM, checkNparts, + countPerPart, globalCountPerPart); + Teuchos::reduceAll(*comm, Teuchos::REDUCE_SUM, + checkNparts*nVwgts, + wtPerPart, globalWtPerPart); + + size_t min = std::numeric_limits::max(); + size_t max = 0; + size_t sum = 0; + size_t minrank = 0, maxrank = 0; + for (size_t i = 0; i < checkNparts; i++) { + if (globalCountPerPart[i] < min) {min = globalCountPerPart[i]; minrank = i;} + if (globalCountPerPart[i] > max) {max = globalCountPerPart[i]; maxrank = i;} + sum += globalCountPerPart[i]; + } + + if (me == 0) { + float avg = (float) sum / (float) checkNparts; + std::cout << "Minimum count: " << min << " on rank " << minrank << std::endl; + std::cout << "Maximum count: " << max << " on rank " << maxrank << std::endl; + std::cout << "Average count: " << avg << std::endl; + std::cout << "Total count: " << sum + << (sum != origMatrix->getGlobalNumRows() + ? "Work was lost; FAIL" + : " ") + << std::endl; + std::cout << "Imbalance: " << max / avg << std::endl; + if (nVwgts) { + std::vector minwt(nVwgts, std::numeric_limits::max()); + std::vector maxwt(nVwgts, 0.); + std::vector sumwt(nVwgts, 0.); + for (size_t i = 0; i < checkNparts; i++) { + for (int j = 0; j < nVwgts; j++) { + size_t idx = i*nVwgts+j; + if (globalWtPerPart[idx] < minwt[j]) minwt[j] = globalWtPerPart[idx]; + if (globalWtPerPart[idx] > maxwt[j]) maxwt[j] = globalWtPerPart[idx]; + sumwt[j] += globalWtPerPart[idx]; + } + } + for (int j = 0; j < nVwgts; j++) { + float avgwt = (float) sumwt[j] / (float) checkNparts; + std::cout << std::endl; + std::cout << "Minimum weight[" << j << "]: " << minwt[j] << std::endl; + std::cout << "Maximum weight[" << j << "]: " << maxwt[j] << std::endl; + std::cout << "Average weight[" << j << "]: " << avgwt << std::endl; + std::cout << "Imbalance: " << maxwt[j] / avgwt << std::endl; + } + } + } + + delete [] countPerPart; + delete [] wtPerPart; + delete [] globalCountPerPart; + delete [] globalWtPerPart; + delete [] vwgts; + + ////// Redistribute matrix and vector into new matrix and vector. + if (me == 0) std::cout << "Redistributing matrix..." << std::endl; + SparseMatrix *redistribMatrix; + SparseMatrixAdapter adapterMatrix(origMatrix); + adapterMatrix.applyPartitioningSolution(*origMatrix, redistribMatrix, + problem.getSolution()); + if (redistribMatrix->getGlobalNumRows() < 40) { + Teuchos::FancyOStream out(Teuchos::rcp(&std::cout,false)); + redistribMatrix->describe(out, Teuchos::VERB_EXTREME); + } + + if (me == 0) std::cout << "Redistributing vectors..." << std::endl; + VectorT *redistribVector; + MultiVectorAdapter adapterVector(origVector); //, weights, weightStrides); + adapterVector.applyPartitioningSolution(*origVector, redistribVector, + problem.getSolution()); + + RCP redistribProd; + redistribProd = Tpetra::createVector( + redistribMatrix->getRangeMap()); + + // Test redistributing an integer vector with the same solution. + // This test is mostly to make sure compilation always works. + RCP origIntVec; + IntVector *redistIntVec; + origIntVec = Tpetra::createVector( + origMatrix->getRangeMap()); + for (size_t i = 0; i < origIntVec->getLocalLength(); i++) + origIntVec->replaceLocalValue(i, me); + + IntVectorAdapter int_vec_adapter(origIntVec); + int_vec_adapter.applyPartitioningSolution(*origIntVec, redistIntVec, + problem.getSolution()); + int origIntNorm = origIntVec->norm1(); + int redistIntNorm = redistIntVec->norm1(); + if (me == 0) std::cout << "IntegerVectorTest: " << origIntNorm << " == " + << redistIntNorm << " ?"; + if (origIntNorm != redistIntNorm) { + if (me == 0) std::cout << " FAIL" << std::endl; + haveFailure = true; + } + else if (me == 0) std::cout << " OK" << std::endl; + delete redistIntVec; + + ////// Verify that redistribution is "correct"; perform matvec with + ////// original and redistributed matrices/vectors and compare norms. + + if (me == 0) std::cout << "Matvec original..." << std::endl; + origMatrix->apply(*origVector, *origProd); + z2TestScalar origNorm = origProd->norm2(); + if (me == 0) + std::cout << "Norm of Original matvec prod: " << origNorm << std::endl; + + if (me == 0) std::cout << "Matvec redistributed..." << std::endl; + redistribMatrix->apply(*redistribVector, *redistribProd); + z2TestScalar redistribNorm = redistribProd->norm2(); + if (me == 0) + std::cout << "Norm of Redistributed matvec prod: " << redistribNorm << std::endl; + + if (redistribNorm > origNorm+epsilon || redistribNorm < origNorm-epsilon) { + testReturn = 1; + haveFailure = true; + } + + delete redistribVector; + delete redistribMatrix; + + if (me == 0) { + if (testReturn) { + std::cout << "Mat-Vec product changed; FAIL" << std::endl; + haveFailure = true; + } + if (!haveFailure) + std::cout << "PASS" << std::endl; + } + + return testReturn; +} From bfd58738e0998005a54c519bc506afe0d8186320 Mon Sep 17 00:00:00 2001 From: gsjaardema Date: Tue, 22 Mar 2022 09:34:01 -0600 Subject: [PATCH 052/147] * More use of initializers * CPUP -- can use just basename.ext instead of basename.ext.#proc.00 * EPU -- Same as above * Improved windows build/portability * GJOIN -- improved long name handling * GREPOS -- improved long name handling * Fix so compiles with strict prototype warnings enabled * EXODUS: Add ex_get_block_id_map function -- global ids on a block-by-block basis -- Clean up testing files to accomodate different order of attributes in new netcdf * IOSS: -- cgns -- better handling of 2D unstructured mesh -- cgns -- fix issue with lambda -- cgns -- handle decomposition with over constrained zones due to line specification -- exodus -- better assembly omission/inclusion handling -- exodus -- add EXODUS_CALL_GET_ALL_TIMES property to improve pseudo-parallel performance -- exodus - consolidate common code -- textmesh - better assembly handling, refactoring -- fix beam4 edge connectivity -- surface split type can be specified via property -- add property to disable recognizing field_1, field_2, ..., field_n type fields --- packages/seacas/Jamfile | 26 +- .../applications/conjoin/CJ_SystemInterface.h | 24 +- .../applications/cpup/CP_SystemInterface.C | 119 +- .../seacas/applications/cpup/CP_Version.h | 6 +- packages/seacas/applications/cpup/cpup.C | 1 + .../applications/epu/EP_SystemInterface.C | 122 +- .../applications/epu/EP_SystemInterface.h | 16 +- packages/seacas/applications/epu/EP_Version.h | 6 +- .../applications/exodiff/ED_SystemInterface.h | 48 +- .../seacas/applications/exodiff/edge_block.h | 4 +- .../seacas/applications/exodiff/exoII_read.h | 24 +- .../seacas/applications/exodiff/exo_block.h | 6 +- .../seacas/applications/exodiff/exo_entity.h | 22 +- .../seacas/applications/exodiff/face_block.h | 4 +- packages/seacas/applications/exodiff/util.C | 3 +- .../exomatlab/EML_SystemInterface.C | 2 +- .../seacas/applications/gjoin/gj_inigen.f | 5 +- .../seacas/applications/gjoin/gj_qainfo.blk | 9 +- packages/seacas/applications/gjoin/gj_rdgen.f | 7 +- packages/seacas/applications/gjoin/gj_wrgen.f | 5 +- .../seacas/applications/grepos/gp_munelb.f | 5 +- .../seacas/applications/grepos/gp_muness.f | 4 +- .../seacas/applications/grepos/gp_munnps.f | 4 +- .../seacas/applications/grepos/gp_qainfo.blk | 6 +- packages/seacas/applications/grepos/grepos.f | 8 +- .../seacas/applications/mapvar-kd/optkd.c | 12 +- .../applications/nas2exo/N2EDataTypes.h | 14 +- .../applications/nas2exo/N2EExoWriter.h | 10 +- .../applications/nas2exo/N2ENasReader.h | 10 +- packages/seacas/applications/nem_slice/elb.h | 22 +- .../applications/nem_spread/ps_pario_const.h | 36 +- .../seacas/applications/zellij/Decompose.C | 5 +- packages/seacas/cmake/FortranSettings.cmake | 7 +- .../seacas/libraries/aprepro_lib/aprepro.h | 7 +- .../seacas/libraries/chaco/assign/median.c | 64 +- .../seacas/libraries/chaco/bpmatch/movevtxs.c | 28 +- .../seacas/libraries/chaco/coarsen/coarsen.c | 47 +- .../seacas/libraries/chaco/coarsen/coarsen1.c | 20 +- .../libraries/chaco/coarsen/makecgraph.c | 36 +- .../libraries/chaco/coarsen/makecgraph2.c | 38 +- .../libraries/chaco/coarsen/makefgraph.c | 38 +- .../libraries/chaco/coarsen/maxmatch1.c | 6 +- .../libraries/chaco/coarsen/maxmatch2.c | 4 +- .../libraries/chaco/coarsen/maxmatch3.c | 10 +- .../libraries/chaco/coarsen/maxmatch4.c | 14 +- .../libraries/chaco/coarsen/maxmatch5.c | 8 +- .../libraries/chaco/coarsen/maxmatch9.c | 10 +- .../libraries/chaco/connect/find_comps.c | 20 +- packages/seacas/libraries/chaco/eigen/Tevec.c | 12 +- .../seacas/libraries/chaco/eigen/checkeig.c | 2 +- .../libraries/chaco/eigen/checkeig_ext.c | 18 +- .../seacas/libraries/chaco/eigen/checkorth.c | 4 +- .../seacas/libraries/chaco/eigen/eigensolve.c | 30 +- .../seacas/libraries/chaco/eigen/get_extval.c | 4 +- .../libraries/chaco/eigen/get_ritzvals.c | 38 +- .../libraries/chaco/eigen/lanc_seconds.c | 2 +- .../seacas/libraries/chaco/eigen/lanczos_FO.c | 70 +- .../seacas/libraries/chaco/eigen/lanczos_SO.c | 110 +- .../libraries/chaco/eigen/lanczos_SO_float.c | 124 +- .../libraries/chaco/eigen/lanczos_ext.c | 76 +- .../libraries/chaco/eigen/lanczos_ext_float.c | 122 +- .../seacas/libraries/chaco/eigen/lanpause.c | 8 +- .../seacas/libraries/chaco/eigen/mkeigvecs.c | 23 +- .../seacas/libraries/chaco/eigen/orthogvec.c | 4 +- packages/seacas/libraries/chaco/eigen/rqi.c | 26 +- .../seacas/libraries/chaco/eigen/sorthog.c | 8 +- .../libraries/chaco/inertial/inertial.c | 12 +- .../libraries/chaco/inertial/inertial1d.c | 14 +- .../libraries/chaco/inertial/inertial2d.c | 10 +- .../libraries/chaco/inertial/inertial3d.c | 10 +- .../libraries/chaco/input/read_params.c | 12 +- .../libraries/chaco/input/reflect_input.c | 18 +- .../libraries/chaco/internal/force_internal.c | 16 +- .../seacas/libraries/chaco/klspiff/buckets.c | 18 +- .../libraries/chaco/klspiff/buckets_bi.c | 20 +- .../seacas/libraries/chaco/klspiff/klspiff.c | 26 +- .../seacas/libraries/chaco/klspiff/nway_kl.c | 38 +- .../libraries/chaco/klvspiff/bucketsv.c | 22 +- .../libraries/chaco/klvspiff/klvspiff.c | 32 +- .../libraries/chaco/klvspiff/nway_klv.c | 4 +- .../seacas/libraries/chaco/main/interface.c | 30 +- packages/seacas/libraries/chaco/main/main.c | 38 +- .../seacas/libraries/chaco/misc/perturb.c | 6 +- .../seacas/libraries/chaco/misc/sequence.c | 30 +- .../seacas/libraries/chaco/misc/simple_part.c | 8 +- .../libraries/chaco/misc/time_kernels.c | 32 +- .../seacas/libraries/chaco/optimize/opt3d.c | 10 +- .../libraries/chaco/refine_map/refine_map.c | 8 +- .../libraries/chaco/refine_part/refine_part.c | 52 +- .../seacas/libraries/chaco/submain/submain.c | 36 +- .../seacas/libraries/chaco/symmlq/msolve.c | 6 +- .../seacas/libraries/chaco/symmlq/symmlq.c | 21 +- .../libraries/chaco/symmlq/symmlqblas.c | 5 +- .../seacas/libraries/chaco/util/randomize.c | 2 +- .../libraries/exoIIv2for32/src/exo_jack_32.c | 8 +- .../libraries/exoIIv2for32/test/test.dmp | 63 +- .../libraries/exoIIv2for32/test/testall.in | 12 +- .../exoIIv2for32/test/testall_i64.in | 16 +- .../libraries/exoIIv2for32/test/testd.dmp | 63 +- .../libraries/exoIIv2for32/test/testdi64.dmp | 63 +- .../libraries/exoIIv2for32/test/testrd.f | 2 - .../libraries/exoIIv2for32/test/testrdd.f | 2 - .../libraries/exoIIv2for32/test/testrddi64.f | 2 - .../seacas/libraries/exodus/CMakeLists.txt | 2 +- .../libraries/exodus/include/exodusII.h | 11 +- .../libraries/exodus/src/ex_get_assemblies.c | 4 +- .../exodus/src/ex_get_block_id_map.c | 103 + .../seacas/libraries/exodus/test/rd_wt_mesh.c | 2 +- .../libraries/exodus/test/test-compress.dmp | 2 +- .../seacas/libraries/exodus/test/test-empty.c | 2 +- .../seacas/libraries/exodus/test/test.dmp | 91 +- .../seacas/libraries/exodus/test/test1.dmp | 85 +- .../seacas/libraries/exodus/test/test2-1.dmp | 68 +- .../seacas/libraries/exodus/test/test2-2.dmp | 67 +- .../seacas/libraries/exodus/test/test2.dmp | 12 +- .../seacas/libraries/exodus/test/test_clb.dmp | 91 +- .../libraries/exodus/test/test_ts_files.c | 6 +- .../libraries/exodus/test/test_ts_nvar.dmp | 111 +- .../exodus/test/test_ts_partial_nvar.dmp | 71 +- .../seacas/libraries/exodus/test/testall.in | 73 +- .../libraries/exodus/test/testcp_dd.dmp | 11 +- .../libraries/exodus/test/testcp_ds.dmp | 12 +- .../libraries/exodus/test/testcp_nl.dmp | 12 +- .../libraries/exodus/test/testcp_sd.dmp | 12 +- .../libraries/exodus/test/testcp_ss.dmp | 11 +- .../libraries/exodus/test/testcp_tran.dmp | 131 +- .../seacas/libraries/exodus/test/testd.dmp | 67 +- .../libraries/exodus/test/testrd-blob.c | 16 +- .../libraries/exodus/test/testrd-long-name.c | 4 +- .../exodus/test/testrd-long-name.dmp | 2 +- .../libraries/exodus/test/testrd-nm32.dmp | 16 +- .../libraries/exodus/test/testrd-nsided.c | 4 +- .../libraries/exodus/test/testrd-nsided.dmp | 2 +- .../libraries/exodus/test/testrd-oned.dmp | 22 +- .../seacas/libraries/exodus/test/testrd.c | 27 +- .../seacas/libraries/exodus/test/testrd.dmp | 16 +- .../seacas/libraries/exodus/test/testrd_nc.c | 4 +- .../libraries/exodus/test/testrd_nc.dmp | 16 +- .../seacas/libraries/exodus/test/testrd_par.c | 4 +- .../libraries/exodus/test/testrd_zeroe.dmp | 2 +- .../libraries/exodus/test/testrd_zeron.dmp | 2 +- .../seacas/libraries/exodus/test/testrdd.c | 4 +- .../seacas/libraries/exodus/test/testrdd.dmp | 2 +- .../seacas/libraries/exodus/test/testrdwt.c | 8 +- .../libraries/exodus/test/testwt-compress.c | 4 +- .../libraries/exodus/test/testwt-groups.c | 4 +- .../libraries/exodus/test/testwt-long-name.c | 4 +- .../exodus/test/testwt-long-name.dmp | 91 +- .../libraries/exodus/test/testwt-nfaced.dmp | 5 +- .../libraries/exodus/test/testwt-nsided.c | 4 +- .../libraries/exodus/test/testwt-nsided.dmp | 93 +- .../libraries/exodus/test/testwt-oned.c | 2 +- .../libraries/exodus/test/testwt-oned.dmp | 7 +- .../libraries/exodus/test/testwt-partial.c | 4 +- .../libraries/exodus/test/testwt-results.dmp | 81 +- .../libraries/exodus/test/testwt-zeroe.dmp | 87 +- .../libraries/exodus/test/testwt-zeron.dmp | 1 - .../seacas/libraries/exodus/test/testwt.c | 25 +- .../seacas/libraries/exodus/test/testwt2.c | 8 +- .../seacas/libraries/exodus/test/testwt_clb.c | 7 +- .../seacas/libraries/exodus/test/testwt_nc.c | 8 +- .../libraries/exodus/test/testwt_nossnsdf.c | 2 +- .../libraries/exodus/test/testwt_ss.dmp | 7 +- .../seacas/libraries/exodus/test/testwtd.c | 4 +- .../seacas/libraries/exodus/test/testwtm.c | 8 +- packages/seacas/libraries/exodus/test/twod.c | 2 +- .../libraries/exodus/test/update_all_tests | 44 +- .../libraries/exodus_for/src/exo_jack.c | 8 +- .../seacas/libraries/ioss/src/Ioss_Beam4.C | 6 +- .../libraries/ioss/src/Ioss_CodeTypes.h | 2 +- .../seacas/libraries/ioss/src/Ioss_DataPool.h | 38 +- .../libraries/ioss/src/Ioss_DatabaseIO.C | 68 +- .../libraries/ioss/src/Ioss_DatabaseIO.h | 41 +- .../libraries/ioss/src/Ioss_Decomposition.C | 6 +- .../libraries/ioss/src/Ioss_Decomposition.h | 2 +- .../seacas/libraries/ioss/src/Ioss_Doxygen.h | 20 +- .../libraries/ioss/src/Ioss_ElementTopology.h | 2 +- .../seacas/libraries/ioss/src/Ioss_Field.h | 1 + .../seacas/libraries/ioss/src/Ioss_FileInfo.C | 16 +- .../seacas/libraries/ioss/src/Ioss_Getline.c | 37 +- .../seacas/libraries/ioss/src/Ioss_Glob.h | 2457 +++++++++-------- .../libraries/ioss/src/Ioss_IOFactory.h | 2 +- .../libraries/ioss/src/Ioss_ParallelUtils.C | 17 +- .../libraries/ioss/src/Ioss_ParallelUtils.h | 10 +- .../libraries/ioss/src/Ioss_PropertyManager.C | 21 + .../libraries/ioss/src/Ioss_PropertyManager.h | 4 +- .../libraries/ioss/src/Ioss_StructuredBlock.C | 2 +- .../seacas/libraries/ioss/src/Ioss_Utils.C | 83 +- .../seacas/libraries/ioss/src/Ioss_Utils.h | 12 + .../libraries/ioss/src/Ioss_VariableType.C | 15 +- .../libraries/ioss/src/Ioss_VariableType.h | 3 +- .../seacas/libraries/ioss/src/Ioss_Version.h | 2 +- .../ioss/src/cgns/Iocgns_DatabaseIO.C | 89 +- .../ioss/src/cgns/Iocgns_ParallelDatabaseIO.C | 12 +- .../libraries/ioss/src/cgns/Iocgns_Utils.C | 37 +- .../ioss/src/exodus/Ioex_BaseDatabaseIO.C | 210 +- .../ioss/src/exodus/Ioex_BaseDatabaseIO.h | 2 + .../ioss/src/exodus/Ioex_DatabaseIO.C | 122 +- .../ioss/src/exodus/Ioex_DatabaseIO.h | 4 +- .../ioss/src/exodus/Ioex_DecompositionData.C | 50 +- .../ioss/src/exodus/Ioex_ParallelDatabaseIO.C | 106 +- .../libraries/ioss/src/main/CMakeLists.txt | 9 + .../libraries/ioss/src/main/cgns_decomp.C | 37 +- .../libraries/ioss/src/main/info_interface.C | 32 +- .../libraries/ioss/src/main/info_interface.h | 2 +- .../seacas/libraries/ioss/src/main/io_info.C | 5 +- .../libraries/ioss/src/main/io_modify.C | 14 +- .../seacas/libraries/ioss/src/main/io_shell.C | 2 +- .../ioss/src/main/modify_interface.C | 28 +- .../libraries/ioss/src/main/shell_interface.C | 33 +- .../libraries/ioss/src/main/shell_interface.h | 2 +- .../ioss/src/main/skinner_interface.C | 28 +- .../ioss/src/main/test/circle-square-2d.cgns | Bin 0 -> 95113 bytes .../src/main/test/exodus_Q2_bc_parents.gold | Bin 1374672 -> 1966313 bytes .../ioss/src/text_mesh/Iotm_DatabaseIO.C | 104 +- .../ioss/src/text_mesh/Iotm_DatabaseIO.h | 9 +- .../ioss/src/text_mesh/Iotm_TextMesh.C | 62 +- .../ioss/src/text_mesh/Iotm_TextMesh.h | 15 + .../ioss/src/text_mesh/Iotm_TextMeshUtils.h | 428 ++- .../unit_tests/UnitTestIotmTextMeshFixture.h | 103 + .../ioss/src/unit_tests/UnitTestTextMesh.C | 252 +- .../seacas/libraries/supes/ext_lib/excpus.c | 10 +- .../seacas/libraries/supes/ext_lib/extime.c | 3 +- .../seacas/libraries/suplib_cpp/GetLongOpt.h | 11 +- packages/seacas/libraries/suplib_cpp/glob.h | 1680 +++++++++++ .../libraries/suplib_cpp/smart_assert.h | 8 +- packages/seacas/libraries/svdi/cdr/cdrsrc.c | 118 +- packages/seacas/libraries/svdi/cgi/cgi.h | 142 +- packages/seacas/libraries/svdi/cgi/mdcgi.c | 10 +- packages/seacas/libraries/svdi/cgi/mdcgi.h | 5 +- .../seacas/libraries/svdi/cgi/met_metxlate.c | 16 +- .../seacas/libraries/svdi/cgi/pst_pstxlate.c | 23 +- packages/seacas/libraries/svdi/cgi/vdicgi.c | 254 +- .../seacas/libraries/svdi/cgi/x11_x11xlate.c | 16 +- packages/seacas/scripts/CMakeLists.txt | 24 +- packages/seacas/scripts/decomp | 74 +- packages/seacas/scripts/exodus2.in.py | 6 +- packages/seacas/scripts/exodus3.in.py | 14 +- 238 files changed, 7182 insertions(+), 4014 deletions(-) create mode 100644 packages/seacas/libraries/exodus/src/ex_get_block_id_map.c create mode 100644 packages/seacas/libraries/ioss/src/main/test/circle-square-2d.cgns create mode 100644 packages/seacas/libraries/suplib_cpp/glob.h diff --git a/packages/seacas/Jamfile b/packages/seacas/Jamfile index 7c3c2847a177..7ad5f977c87e 100644 --- a/packages/seacas/Jamfile +++ b/packages/seacas/Jamfile @@ -548,6 +548,7 @@ obj blot_main : $(seacas-root)/applications/blot/blot.f armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -563,6 +564,7 @@ obj fastq_main : $(seacas-root)/applications/fastq/fastq.f armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -619,6 +621,7 @@ obj addrwrap : $(seacas-root)/libraries/exodus_for/src/addrwrap.F armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -653,6 +656,7 @@ lib exodus_for armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -675,6 +679,7 @@ lib exodus_for armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -781,6 +786,7 @@ lib suplib armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -803,6 +809,7 @@ lib suplib armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -900,6 +907,7 @@ lib plt armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -922,6 +930,7 @@ lib plt armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -955,6 +964,7 @@ lib svdi_cdr armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -977,6 +987,7 @@ lib svdi_cdr armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1020,6 +1031,7 @@ lib svdi_cgi armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1042,6 +1054,7 @@ lib svdi_cgi armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1072,6 +1085,7 @@ obj vdx11cps : $(seacas-root)/libraries/svdi/vdi_drivers/vdx11cps.F armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1086,6 +1100,7 @@ obj vdicps_dual : $(seacas-root)/libraries/svdi/vdi_drivers/vdicps_dual.f armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1100,6 +1115,7 @@ obj svdi_cgi_cps : $(seacas-root)/libraries/svdi/vdi_drivers/vdicps.f armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1131,6 +1147,7 @@ lib blotlib armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1148,6 +1165,7 @@ lib blotlib armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1179,6 +1197,7 @@ lib fastqlib armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1196,6 +1215,7 @@ lib fastqlib armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1229,6 +1249,7 @@ lib mapvarlib armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1251,6 +1272,7 @@ lib mapvarlib armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1284,6 +1306,7 @@ lib supes armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1306,6 +1329,7 @@ lib supes armhpc,64:"-fdefault-real-8 -fdefault-integer-8" nvidia,64:"-fdefault-real-8 -fdefault-integer-8" intel,64:"-r8 -i8" + oneapi,64:"-r8 -i8" pgi,64:"-r8 -i8" pathscale,64:"-r8 -i8" open64,64:"-r8 -i8" @@ -1817,7 +1841,7 @@ exe Utst_textmesh /mpi//mpi : @sierra-exec-tag ; - + rule xcb-for_cray-rule ( properties * ) { if $(cray-system) = "yes" diff --git a/packages/seacas/applications/conjoin/CJ_SystemInterface.h b/packages/seacas/applications/conjoin/CJ_SystemInterface.h index d39efb445718..230fd0170d52 100644 --- a/packages/seacas/applications/conjoin/CJ_SystemInterface.h +++ b/packages/seacas/applications/conjoin/CJ_SystemInterface.h @@ -1,4 +1,4 @@ -// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -52,13 +52,13 @@ namespace Excn { static void show_version(); // Make this private eventually... - StringVector inputFiles_; - std::string outputName_; + StringVector inputFiles_{}; + std::string outputName_{}; private: void enroll_options(); - GetLongOption options_; //!< Options parsing + GetLongOption options_{}; //!< Options parsing int debugLevel_{0}; int screenWidth_{0}; @@ -75,17 +75,17 @@ namespace Excn { double aliveValue_{-1.0}; double interpartMinimumTimeDelta_{0.0}; - std::string elementStatusVariable_; - std::string nodalStatusVariable_; + std::string elementStatusVariable_{}; + std::string nodalStatusVariable_{}; // Mesh status variable to combine with elementStatusVariable_ - std::string meshCombineStatusVariable_; + std::string meshCombineStatusVariable_{}; - StringIdVector globalVarNames_; - StringIdVector nodeVarNames_; - StringIdVector elemVarNames_; - StringIdVector nsetVarNames_; - StringIdVector ssetVarNames_; + StringIdVector globalVarNames_{}; + StringIdVector nodeVarNames_{}; + StringIdVector elemVarNames_{}; + StringIdVector nsetVarNames_{}; + StringIdVector ssetVarNames_{}; }; } // namespace Excn #endif diff --git a/packages/seacas/applications/cpup/CP_SystemInterface.C b/packages/seacas/applications/cpup/CP_SystemInterface.C index 35faf7b2cd02..635b42cec285 100644 --- a/packages/seacas/applications/cpup/CP_SystemInterface.C +++ b/packages/seacas/applications/cpup/CP_SystemInterface.C @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -7,6 +7,7 @@ */ #include "CP_SystemInterface.h" #include "CP_Version.h" // for qainfo +#include "FileInfo.h" #include "GetLongOpt.h" // for GetLongOption, etc #include "Ioss_CodeTypes.h" #include "SL_tokenize.h" // for tokenize @@ -16,13 +17,25 @@ #include // for strtol, abs, exit, strtoul, etc #include // for strchr, strlen #include +#include #include #include #include // for string, char_traits, etc #include +#include #include // for pair, make_pair #include // for vector +#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \ + defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__) +#define __SUP_WINDOWS__ 1 +#include +#endif + +#if !defined(__SUP_WINDOWS__) +#include +#endif + namespace { bool is_path_absolute(const std::string &path) { @@ -40,7 +53,8 @@ namespace { [](char a, char b) { return std::tolower(a) == std::tolower(b); }); } - void parse_variable_names(const char *tokens, Cpup::StringVector *variable_list); + void parse_variable_names(const char *tokens, Cpup::StringVector *variable_list); + std::string find_matching_file(const std::string &path, const std::string &basename); } // namespace Cpup::SystemInterface::SystemInterface(int rank) : myRank_(rank) { enroll_options(); } @@ -309,7 +323,7 @@ bool Cpup::SystemInterface::parse_options(int argc, char **argv) if (options_.retrieve("copyright") != nullptr) { if (myRank_ == 0) { - fmt::print("{}", copyright("2010-2021")); + fmt::print("{}", copyright("2010-2022")); } return false; } @@ -322,17 +336,62 @@ bool Cpup::SystemInterface::parse_options(int argc, char **argv) // Determine Root, Proc, Extension, and Basename automatically // by parsing the basename_ entered by the user. Assumed to be // in the form: "/directory/sub/basename.ext.#proc.34" - bool success = decompose_filename(basename_); - if (!success) { + FileInfo file(basename_); + auto path = file.pathname(); + if (path.empty()) { + path = "."; + } +#if defined(__SUP_WINDOWS__) + rootDirectory_ = _fullpath(nullptr, path.c_str(), _MAX_PATH); +#else + char *tmp = ::realpath(path.c_str(), nullptr); + if (tmp != nullptr) { + rootDirectory_ = std::string(tmp); + free(tmp); + } +#endif + + basename_ = file.tailname(); + if (basename_.empty()) { std::ostringstream errmsg; fmt::print( errmsg, "\nERROR: (CPUP) If the '-auto' option is specified, the basename must specify an " - "existing filename.\n" - " The entered basename does not contain an extension or processor count.\n"); + "existing filename or portion of a base of a filename (no rank/proc count).\n" + " The entered basename ('{}') does not contain a filename.\n", + basename_); throw std::runtime_error(errmsg.str()); } + bool success = decompose_filename(basename_); + if (!success) { + // See if we can find files that match the basename and take the first match as the "new" + // basename... + std::string candidate = find_matching_file(rootDirectory_, basename_); + if (!candidate.empty()) { + basename_ = candidate; + success = decompose_filename(basename_); + if (!success) { + std::ostringstream errmsg; + fmt::print( + errmsg, + "\nERROR: (CPUP) If the '-auto' option is specified, the basename must specify an " + "existing filename or a basename (no rank/proc count).\n" + " The entered basename ('{}') does not contain an extension or processor " + "count.\n", + basename_); + throw std::runtime_error(errmsg.str()); + } + } + } auto_ = true; + if (myRank_ == 0) { + fmt::print("\nThe following options were determined automatically:\n" + "\t basename = '{}'\n" + "\t-processor_count {}\n" + "\t-extension {}\n" + "\t-Root_directory {}\n\n", + basename_, processorCount_, inExtension_, rootDirectory_); + } } } else { @@ -502,27 +561,9 @@ bool Cpup::SystemInterface::decompose_filename(const std::string &cs) s.erase(ind); } - // Remainder of 's' consists of the basename_ and the rootDirectory_ - // If there is no '/', then it is all basename_; otherwise the - // basename_ is the portion following the '/' and the rootDirectory_ - // is the portion preceding the '/' - ind = s.find_last_of('/', std::string::npos); - if (ind != std::string::npos) { - basename_ = s.substr(ind + 1, std::string::npos); - rootDirectory_ = s.substr(0, ind); - } - else { - basename_ = s; - } - - if (myRank_ == 0) { - fmt::print("\nThe following options were determined automatically:\n" - "\t basename = '{}'\n" - "\t-processor_count = {}\n" - "\t-extension = '{}'\n" - "\t-Root_directory = '{}'\n", - basename_, processorCount_, inExtension_, rootDirectory_); - } + // The directory path was stripped prior to entering this function, + // so remainder of 's' is just the new basename_ + basename_ = s; return true; } @@ -550,4 +591,26 @@ namespace { std::sort(variable_list->begin(), variable_list->end()); } } + + std::string find_matching_file(const std::string &path, const std::string &basename) + { + glob::glob g(basename + ".*.*"); +#if !defined(__SUP_WINDOWS__) + struct dirent *entry = nullptr; + DIR *dp = nullptr; + + dp = opendir(path.c_str()); + if (dp != nullptr) { + while ((entry = readdir(dp))) { + std::string filename = entry->d_name; + if (glob::glob_match(filename, g)) { + closedir(dp); + return filename; + } + } + } + closedir(dp); +#endif + return ""; + } } // namespace diff --git a/packages/seacas/applications/cpup/CP_Version.h b/packages/seacas/applications/cpup/CP_Version.h index 704b43ab9320..7d5ea58bb486 100644 --- a/packages/seacas/applications/cpup/CP_Version.h +++ b/packages/seacas/applications/cpup/CP_Version.h @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -10,8 +10,8 @@ static char const *qainfo[] = { "cpup", - "0.9 beta", - "2021/09/23", + "0.93 beta", + "2022/02/18", }; #endif // SEACAS_Version_h diff --git a/packages/seacas/applications/cpup/cpup.C b/packages/seacas/applications/cpup/cpup.C index b4b4f710feae..5cf91472bc78 100644 --- a/packages/seacas/applications/cpup/cpup.C +++ b/packages/seacas/applications/cpup/cpup.C @@ -11,6 +11,7 @@ #include #include "add_to_log.h" +#define FMT_DEPRECATED_OSTREAM #include "fmt/ostream.h" #include "format_time.h" #include "hwm.h" diff --git a/packages/seacas/applications/epu/EP_SystemInterface.C b/packages/seacas/applications/epu/EP_SystemInterface.C index 984c65a3a05e..b84743f56d33 100644 --- a/packages/seacas/applications/epu/EP_SystemInterface.C +++ b/packages/seacas/applications/epu/EP_SystemInterface.C @@ -6,7 +6,8 @@ * See packages/seacas/LICENSE for details */ #include "EP_SystemInterface.h" -#include "EP_Version.h" // for qainfo +#include "EP_Version.h" // for qainfo +#include "FileInfo.h" #include "GetLongOpt.h" // for GetLongOption, etc #include "SL_tokenize.h" // for tokenize #include // for sort, transform @@ -16,13 +17,25 @@ #include // for strtol, abs, exit, strtoul, etc #include // for strchr, strlen #include +#include #include #include #include // for string, char_traits, etc #include +#include #include // for pair, make_pair #include // for vector +#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \ + defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__) +#define __SUP_WINDOWS__ 1 +#include +#endif + +#if !defined(__SUP_WINDOWS__) +#include +#endif + namespace { bool str_equal(const std::string &s1, const std::string &s2) { @@ -31,7 +44,8 @@ namespace { [](char a, char b) { return std::tolower(a) == std::tolower(b); }); } - void parse_variable_names(const char *tokens, Excn::StringIdVector *variable_list); + void parse_variable_names(const char *tokens, Excn::StringIdVector *variable_list); + std::string find_matching_file(const std::string &path, const std::string &basename); } // namespace Excn::SystemInterface::SystemInterface(int rank) : myRank_(rank) { enroll_options(); } @@ -218,7 +232,8 @@ void Excn::SystemInterface::enroll_options() "0"); options_.enroll("sum_shared_nodes", GetLongOption::NoValue, - "[Rare, special case] The nodal results data on all shared nodes (nodes on processor boundaries)\n" + "[Rare, special case] The nodal results data on all shared nodes (nodes on " + "processor boundaries)\n" "\t\twill be the sum of the individual nodal results data on each shared node.\n" "\t\tThe default behavior assumes that the values are equal.", nullptr); @@ -383,7 +398,7 @@ bool Excn::SystemInterface::parse_options(int argc, char **argv) if (options_.retrieve("copyright") != nullptr) { if (myRank_ == 0) { - fmt::print("{}", copyright("2010-2021")); + fmt::print("{}", copyright("2010-2022")); } return false; } @@ -396,17 +411,62 @@ bool Excn::SystemInterface::parse_options(int argc, char **argv) // Determine Root, Proc, Extension, and Basename automatically // by parsing the basename_ entered by the user. Assumed to be // in the form: "/directory/sub/basename.ext.#proc.34" - bool success = decompose_filename(basename_); - if (!success) { + FileInfo file(basename_); + auto path = file.pathname(); + if (path.empty()) { + path = "."; + } +#if defined(__SUP_WINDOWS__) + rootDirectory_ = _fullpath(nullptr, path.c_str(), _MAX_PATH); +#else + char *tmp = ::realpath(path.c_str(), nullptr); + if (tmp != nullptr) { + rootDirectory_ = std::string(tmp); + free(tmp); + } +#endif + + basename_ = file.tailname(); + if (basename_.empty()) { std::ostringstream errmsg; fmt::print( errmsg, "\nERROR: (EPU) If the '-auto' option is specified, the basename must specify an " - "existing filename.\n" - " The entered basename does not contain an extension or processor count.\n"); + "existing filename or portion of a base of a filename (no rank/proc count).\n" + " The entered basename ('{}') does not contain a filename.\n", + basename_); throw std::runtime_error(errmsg.str()); } + bool success = decompose_filename(basename_); + if (!success) { + // See if we can find files that match the basename and take the first match as the "new" + // basename... + std::string candidate = find_matching_file(rootDirectory_, basename_); + if (!candidate.empty()) { + basename_ = candidate; + success = decompose_filename(basename_); + if (!success) { + std::ostringstream errmsg; + fmt::print( + errmsg, + "\nERROR: (EPU) If the '-auto' option is specified, the basename must specify an " + "existing filename or a basename (no rank/proc count).\n" + " The entered basename ('{}') does not contain an extension or processor " + "count.\n", + basename_); + throw std::runtime_error(errmsg.str()); + } + } + } auto_ = true; + if (myRank_ == 0) { + fmt::print("\nThe following options were determined automatically:\n" + "\t basename = '{}'\n" + "\t-processor_count {}\n" + "\t-extension {}\n" + "\t-Root_directory {}\n\n", + basename_, processorCount_, inExtension_, rootDirectory_); + } } } else { @@ -560,27 +620,9 @@ bool Excn::SystemInterface::decompose_filename(const std::string &cs) s.erase(ind); } - // Remainder of 's' consists of the basename_ and the rootDirectory_ - // If there is no '/', then it is all basename_; otherwise the - // basename_ is the portion following the '/' and the rootDirectory_ - // is the portion preceding the '/' - ind = s.find_last_of('/', std::string::npos); - if (ind != std::string::npos) { - basename_ = s.substr(ind + 1, std::string::npos); - rootDirectory_ = s.substr(0, ind); - } - else { - basename_ = s; - } - - if (myRank_ == 0) { - fmt::print("\nThe following options were determined automatically:\n" - "\t basename = '{}'\n" - "\t-processor_count {}\n" - "\t-extension {}\n" - "\t-Root_directory {}\n\n", - basename_, processorCount_, inExtension_, rootDirectory_); - } + // The directory path was stripped prior to entering this function, + // so remainder of 's' is just the new basename_ + basename_ = s; return true; } @@ -636,4 +678,26 @@ namespace { std::sort(variable_list->begin(), variable_list->end(), string_id_sort); } } + + std::string find_matching_file(const std::string &path, const std::string &basename) + { + glob::glob g(basename + ".*.*"); +#if !defined(__SUP_WINDOWS__) + struct dirent *entry = nullptr; + DIR *dp = nullptr; + + dp = opendir(path.c_str()); + if (dp != nullptr) { + while ((entry = readdir(dp))) { + std::string filename = entry->d_name; + if (glob::glob_match(filename, g)) { + closedir(dp); + return filename; + } + } + } + closedir(dp); +#endif + return ""; + } } // namespace diff --git a/packages/seacas/applications/epu/EP_SystemInterface.h b/packages/seacas/applications/epu/EP_SystemInterface.h index b7946d746697..5fba99aaef80 100644 --- a/packages/seacas/applications/epu/EP_SystemInterface.h +++ b/packages/seacas/applications/epu/EP_SystemInterface.h @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -163,13 +163,13 @@ namespace Excn { bool verifyValidFile_{false}; bool addNodalCommunicationMap_{false}; - StringIdVector globalVarNames_; - StringIdVector nodeVarNames_; - StringIdVector elemVarNames_; - StringIdVector nsetVarNames_; - StringIdVector ssetVarNames_; - StringIdVector edblkVarNames_; - StringIdVector fablkVarNames_; + StringIdVector globalVarNames_{}; + StringIdVector nodeVarNames_{}; + StringIdVector elemVarNames_{}; + StringIdVector nsetVarNames_{}; + StringIdVector ssetVarNames_{}; + StringIdVector edblkVarNames_{}; + StringIdVector fablkVarNames_{}; }; inline int SystemInterface::part_count() const diff --git a/packages/seacas/applications/epu/EP_Version.h b/packages/seacas/applications/epu/EP_Version.h index 8be969ef21c8..64a97322a51f 100644 --- a/packages/seacas/applications/epu/EP_Version.h +++ b/packages/seacas/applications/epu/EP_Version.h @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -10,8 +10,8 @@ static char const *qainfo[] = { "epu -- E Pluribus Unum", - "6.03", - "2021/08/18", + "6.05", + "2022/02/18", }; #endif // SEACAS_Version_h diff --git a/packages/seacas/applications/exodiff/ED_SystemInterface.h b/packages/seacas/applications/exodiff/ED_SystemInterface.h index c5764a6822c5..c0b12ded2dd1 100644 --- a/packages/seacas/applications/exodiff/ED_SystemInterface.h +++ b/packages/seacas/applications/exodiff/ED_SystemInterface.h @@ -1,4 +1,4 @@ -// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -42,49 +42,49 @@ class SystemInterface int time_step_stop{-1}; // Last step to compare int time_step_increment{1}; // Step increment - std::pair explicit_steps; // Only compare these two steps (db1:db2) if nonzero. + std::pair explicit_steps{}; // Only compare these two steps (db1:db2) if nonzero. int max_warnings{100}; - std::vector glob_var_names; + std::vector glob_var_names{}; Tolerance glob_var_default{ToleranceMode::RELATIVE_, 1.0e-6, 0.0}; - std::vector glob_var; + std::vector glob_var{}; - std::vector node_var_names; + std::vector node_var_names{}; Tolerance node_var_default{ToleranceMode::RELATIVE_, 1.0e-6, 0.0}; - std::vector node_var; + std::vector node_var{}; - std::vector elmt_var_names; + std::vector elmt_var_names{}; Tolerance elmt_var_default{ToleranceMode::RELATIVE_, 1.0e-6, 0.0}; - std::vector elmt_var; + std::vector elmt_var{}; - std::vector elmt_att_names; + std::vector elmt_att_names{}; Tolerance elmt_att_default{ToleranceMode::RELATIVE_, 1.0e-6, 0.0}; - std::vector elmt_att; + std::vector elmt_att{}; - std::vector ns_var_names; + std::vector ns_var_names{}; Tolerance ns_var_default{ToleranceMode::RELATIVE_, 1.0e-6, 0.0}; - std::vector ns_var; + std::vector ns_var{}; - std::vector ss_var_names; + std::vector ss_var_names{}; Tolerance ss_var_default{ToleranceMode::RELATIVE_, 1.0e-6, 0.0}; - std::vector ss_var; + std::vector ss_var{}; - std::vector eb_var_names; + std::vector eb_var_names{}; Tolerance eb_var_default{ToleranceMode::RELATIVE_, 1.0e-6, 0.0}; - std::vector eb_var; + std::vector eb_var{}; - std::vector fb_var_names; + std::vector fb_var_names{}; Tolerance fb_var_default{ToleranceMode::RELATIVE_, 1.0e-6, 0.0}; - std::vector fb_var; + std::vector fb_var{}; // time step exclusion data - std::vector exclude_steps; + std::vector exclude_steps{}; - std::string file1; - std::string file2; - std::string diff_file; - std::string command_file; + std::string file1{}; + std::string file2{}; + std::string diff_file{}; + std::string command_file{}; bool quiet_flag{false}; // By default, warnings and other info is produced bool show_all_diffs{false}; // Be default, show only maximum diff for each variable; @@ -137,7 +137,7 @@ class SystemInterface private: void enroll_options(); - GetLongOption options_; //!< Options parsing + GetLongOption options_{}; //!< Options parsing }; extern SystemInterface interFace; diff --git a/packages/seacas/applications/exodiff/edge_block.h b/packages/seacas/applications/exodiff/edge_block.h index 3ce1eeeaf2ab..94765fe87346 100644 --- a/packages/seacas/applications/exodiff/edge_block.h +++ b/packages/seacas/applications/exodiff/edge_block.h @@ -1,4 +1,4 @@ -// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -34,7 +34,7 @@ template class Edge_Block : public Exo_Entity const char *label() const override { return "Edgeblock"; } const char *short_label() const override { return "edgeblock"; } - std::string elmt_type; + std::string elmt_type{}; int num_edges_per_elmt{-1}; friend class ExoII_Read; diff --git a/packages/seacas/applications/exodiff/exoII_read.h b/packages/seacas/applications/exodiff/exoII_read.h index 6438c6f33918..d1a4863bc010 100644 --- a/packages/seacas/applications/exodiff/exoII_read.h +++ b/packages/seacas/applications/exodiff/exoII_read.h @@ -1,4 +1,4 @@ -// Copyright(C) 1999-2021 National Technology & Engineering Solutions +// Copyright(C) 1999-2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -184,13 +184,13 @@ template class ExoII_Read std::pair Global_to_Block_Local(size_t global_elmt_num) const; protected: - std::string file_name; + std::string file_name{}; int file_id{-1}; // Exodus file id; also used to determine if file is open. // GENESIS info: - std::string title; - std::vector coord_names; + std::string title{}; + std::vector coord_names{}; size_t num_nodes{0}; int dimension{0}; size_t num_elmts{0}; @@ -220,14 +220,14 @@ template class ExoII_Read // RESULTS info: - std::vector global_vars; - std::vector nodal_vars; - std::vector elmt_vars; - std::vector elmt_atts; - std::vector ns_vars; - std::vector ss_vars; - std::vector eb_vars; - std::vector fb_vars; + std::vector global_vars{}; + std::vector nodal_vars{}; + std::vector elmt_vars{}; + std::vector elmt_atts{}; + std::vector ns_vars{}; + std::vector ss_vars{}; + std::vector eb_vars{}; + std::vector fb_vars{}; int num_times{0}; double *times{nullptr}; diff --git a/packages/seacas/applications/exodiff/exo_block.h b/packages/seacas/applications/exodiff/exo_block.h index 1facf8af3832..af40f2cd2548 100644 --- a/packages/seacas/applications/exodiff/exo_block.h +++ b/packages/seacas/applications/exodiff/exo_block.h @@ -1,4 +1,4 @@ -// Copyright(C) 1999-2021 National Technology & Engineering Solutions +// Copyright(C) 1999-2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -48,10 +48,10 @@ template class Exo_Block : public Exo_Entity const char *label() const override { return "Element Block"; } const char *short_label() const override { return "block"; } - std::string elmt_type; + std::string elmt_type{}; int num_nodes_per_elmt{-1}; int64_t offset_{0}; - std::vector conn; // Array; holds a matrix, num_elmts by num_nodes_per_elmt. + std::vector conn{}; // Array; holds a matrix, num_elmts by num_nodes_per_elmt. friend class ExoII_Read; }; diff --git a/packages/seacas/applications/exodiff/exo_entity.h b/packages/seacas/applications/exodiff/exo_entity.h index f36b921dce06..798866c7bb87 100644 --- a/packages/seacas/applications/exodiff/exo_entity.h +++ b/packages/seacas/applications/exodiff/exo_entity.h @@ -1,4 +1,4 @@ -// Copyright(C) 1999-2021 National Technology & Engineering Solutions +// Copyright(C) 1999-2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -71,7 +71,7 @@ class Exo_Entity virtual EXOTYPE exodus_type() const = 0; protected: - std::string name_; + std::string name_{}; int fileId{-1}; ex_entity_id id_{EX_INVALID_ID}; size_t index_{0}; // 0-offset index into Exodus nodeset list. @@ -83,15 +83,15 @@ class Exo_Entity void get_truth_table() const; - mutable int *truth_{nullptr}; // Array; holds local truth table for this entity - int currentStep{0}; // Time step number of the current results. - int numVars{0}; // Total number of variables in the file. - double **results_{nullptr}; // Array of pointers (length numVars) - // to arrays of results (length num_entity). - int numAttr{0}; // Total number of attributes in the file. - std::vector attributes_; // Array of pointers (length numAttr) - // to arrays of attributes (length num_entity). - std::vector attributeNames; + mutable int *truth_{nullptr}; // Array; holds local truth table for this entity + int currentStep{0}; // Time step number of the current results. + int numVars{0}; // Total number of variables in the file. + double **results_{nullptr}; // Array of pointers (length numVars) + // to arrays of results (length num_entity). + int numAttr{0}; // Total number of attributes in the file. + std::vector attributes_{}; // Array of pointers (length numAttr) + // to arrays of attributes (length num_entity). + std::vector attributeNames{}; template friend class ExoII_Read; }; diff --git a/packages/seacas/applications/exodiff/face_block.h b/packages/seacas/applications/exodiff/face_block.h index 1148e1961896..c9eed0664fb2 100644 --- a/packages/seacas/applications/exodiff/face_block.h +++ b/packages/seacas/applications/exodiff/face_block.h @@ -1,4 +1,4 @@ -// Copyright(C) 1999-2021 National Technology & Engineering Solutions +// Copyright(C) 1999-2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -34,7 +34,7 @@ template class Face_Block : public Exo_Entity const char *label() const override { return "Faceblock"; } const char *short_label() const override { return "faceblock"; } - std::string elmt_type; + std::string elmt_type{}; int num_faces_per_elmt{-1}; friend class ExoII_Read; diff --git a/packages/seacas/applications/exodiff/util.C b/packages/seacas/applications/exodiff/util.C index f2e71b71f075..dafb1051bcb8 100644 --- a/packages/seacas/applications/exodiff/util.C +++ b/packages/seacas/applications/exodiff/util.C @@ -14,7 +14,8 @@ #include "ED_SystemInterface.h" // for SystemInterface, interFace -#if defined(_MSC_VER) +#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \ + defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__) #include #define isatty _isatty #endif diff --git a/packages/seacas/applications/exomatlab/EML_SystemInterface.C b/packages/seacas/applications/exomatlab/EML_SystemInterface.C index 2662d8007d6a..7f8e1355e0ef 100644 --- a/packages/seacas/applications/exomatlab/EML_SystemInterface.C +++ b/packages/seacas/applications/exomatlab/EML_SystemInterface.C @@ -181,7 +181,7 @@ bool SystemInterface::parse_options(int argc, char **argv) } if (options_.retrieve("copyright") != nullptr) { - fmt::print("{}", copyright("2011-2019")); + fmt::print("{}", copyright("2011-2021")); exit(EXIT_SUCCESS); } diff --git a/packages/seacas/applications/gjoin/gj_inigen.f b/packages/seacas/applications/gjoin/gj_inigen.f index 981112d65f68..ae0a31e83cd8 100644 --- a/packages/seacas/applications/gjoin/gj_inigen.f +++ b/packages/seacas/applications/gjoin/gj_inigen.f @@ -1,4 +1,4 @@ -C Copyright(C) 1999-2021 National Technology & Engineering Solutions +C Copyright(C) 1999-2022 National Technology & Engineering Solutions C of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with C NTESS, the U.S. Government retains certain rights in this software. C @@ -49,13 +49,14 @@ SUBROUTINE INIGEN (A, FIRST, C -- kltsnc - OUT - index of LTSSNC; the index of the first dist factor for each face. C -- KFACSS - OUT - index of FACESS; the distribution factors for all sets + include 'exodusII.inc' include 'gj_namlen.blk' DIMENSION A(*) LOGICAL FIRST if (FIRST) THEN - namlen = 0 + namlen = MXNAME end if IF (FIRST) THEN diff --git a/packages/seacas/applications/gjoin/gj_qainfo.blk b/packages/seacas/applications/gjoin/gj_qainfo.blk index 8d3f6245d6f0..ba66b6694a7c 100644 --- a/packages/seacas/applications/gjoin/gj_qainfo.blk +++ b/packages/seacas/applications/gjoin/gj_qainfo.blk @@ -1,4 +1,4 @@ -C Copyright(C) 1999-2021 National Technology & Engineering Solutions +C Copyright(C) 1999-2022 National Technology & Engineering Solutions C of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with C NTESS, the U.S. Government retains certain rights in this software. C @@ -6,8 +6,8 @@ C See packages/seacas/LICENSE for details C -*- Mode: fortran -*- QAINFO(1) = 'GJoin2 ' - QAINFO(2) = '2021/10/27 ' - QAINFO(3) = ' 1.38 ' + QAINFO(2) = '2022/02/02 ' + QAINFO(3) = ' 1.39 ' C - Added EXPXYZ - By material matching C - Fixes in expxyz, matxyz, comand, irennp @@ -74,4 +74,5 @@ c - fixing sideset df copy if no sideset df c - call mdfree() c - add basic support for named entities. c - don't mclong if adding zero bytes -c - remove warning about expxyz material matching routine \ No newline at end of file +c - remove warning about expxyz material matching routine +c - fix name length issues \ No newline at end of file diff --git a/packages/seacas/applications/gjoin/gj_rdgen.f b/packages/seacas/applications/gjoin/gj_rdgen.f index 2127400e26b5..8719a9108ea6 100644 --- a/packages/seacas/applications/gjoin/gj_rdgen.f +++ b/packages/seacas/applications/gjoin/gj_rdgen.f @@ -1,4 +1,4 @@ -C Copyright(C) 1999-2021 National Technology & Engineering Solutions +C Copyright(C) 1999-2022 National Technology & Engineering Solutions C of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with C NTESS, the U.S. Government retains certain rights in this software. C @@ -232,11 +232,6 @@ SUBROUTINE RDGEN (A, IA, C, FIRST, FILNAM, goto 960 endif -C --Determine size of entity names... - if (namlen .eq. 0) then - call exinq(netid, EXDBMXUSNM, namlen, dummy, cdummy, ierr) - if (namlen .lt. 32) namlen = 32 - end if call exmxnm(netid, namlen, ierr) C --Read the element blocks diff --git a/packages/seacas/applications/gjoin/gj_wrgen.f b/packages/seacas/applications/gjoin/gj_wrgen.f index 081acbd6736b..c20192b25e62 100644 --- a/packages/seacas/applications/gjoin/gj_wrgen.f +++ b/packages/seacas/applications/gjoin/gj_wrgen.f @@ -1,4 +1,4 @@ -C Copyright(C) 1999-2021 National Technology & Engineering Solutions +C Copyright(C) 1999-2022 National Technology & Engineering Solutions C of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with C NTESS, the U.S. Government retains certain rights in this software. C @@ -103,6 +103,9 @@ SUBROUTINE WRGEN (A,IA, FILNAM, TITLE, NDIM, NUMNP, NUMEL, NELBLK, go to 150 endif +C -- Set output name length + call exmxnm(idexo, namlen, ierr) + C --Write the QA records if (nqarec .gt. 0) then diff --git a/packages/seacas/applications/grepos/gp_munelb.f b/packages/seacas/applications/grepos/gp_munelb.f index 76e20a8b8377..f2393ff87975 100644 --- a/packages/seacas/applications/grepos/gp_munelb.f +++ b/packages/seacas/applications/grepos/gp_munelb.f @@ -1,4 +1,4 @@ -C Copyright(C) 1999-2020 National Technology & Engineering Solutions +C Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions C of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with C NTESS, the U.S. Government retains certain rights in this software. C @@ -55,7 +55,8 @@ SUBROUTINE MUNELB (NELBLK, ISTAT, NUMEL, INTEGER IXELB(*) INTEGER NELBX(*) INTEGER ISCR(*) - CHARACTER*(MXSTLN) BLKTYP(*), SCRSTR(*) + CHARACTER*(MXSTLN) BLKTYP(*) + CHARACTER*(maxnam) SCRSTR(*) CHARACTER*(maxnam) ATNAMES(*) CHARACTER*(maxnam) EBNAME(*) diff --git a/packages/seacas/applications/grepos/gp_muness.f b/packages/seacas/applications/grepos/gp_muness.f index f0afeb10acaf..75de47e69f5d 100644 --- a/packages/seacas/applications/grepos/gp_muness.f +++ b/packages/seacas/applications/grepos/gp_muness.f @@ -1,4 +1,4 @@ -C Copyright(C) 1999-2020 National Technology & Engineering Solutions +C Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions C of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with C NTESS, the U.S. Government retains certain rights in this software. C @@ -57,7 +57,7 @@ SUBROUTINE MUNESS (NUMESS, ISTAT, LESSEL, LESSDL, INTEGER ISCR(*) REAL FACSS(*), TDX(*) - CHARACTER*(MXSTLN) NAMSCR(*) + CHARACTER*(maxnam) NAMSCR(*) CHARACTER*(maxnam) NAME(*) IF (NUMESS .LE. 0) RETURN diff --git a/packages/seacas/applications/grepos/gp_munnps.f b/packages/seacas/applications/grepos/gp_munnps.f index e901f43bfc6f..b58c3e9ace16 100644 --- a/packages/seacas/applications/grepos/gp_munnps.f +++ b/packages/seacas/applications/grepos/gp_munnps.f @@ -1,4 +1,4 @@ -C Copyright(C) 1999-2020 National Technology & Engineering Solutions +C Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions C of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with C NTESS, the U.S. Government retains certain rights in this software. C @@ -47,7 +47,7 @@ SUBROUTINE MUNNPS (NUMNPS, ISTAT, LNPSNL, LNPSDF, INTEGER IXNPS(*) INTEGER NNX(*) INTEGER ISCR(*) - CHARACTER*(MXSTLN) NAMSCR(*) + CHARACTER*(maxnam) NAMSCR(*) CHARACTER*(maxnam) NAME(*) IF (NUMNPS .LE. 0) RETURN diff --git a/packages/seacas/applications/grepos/gp_qainfo.blk b/packages/seacas/applications/grepos/gp_qainfo.blk index a6ae29d77a53..d8454dfe8d7c 100644 --- a/packages/seacas/applications/grepos/gp_qainfo.blk +++ b/packages/seacas/applications/grepos/gp_qainfo.blk @@ -1,4 +1,4 @@ -C Copyright(C) 1999-2021 National Technology & Engineering Solutions +C Copyright(C) 1999-2022 National Technology & Engineering Solutions C of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with C NTESS, the U.S. Government retains certain rights in this software. C @@ -6,5 +6,5 @@ C See packages/seacas/LICENSE for details C -*- Mode: fortran -*- QAINFO(1) = 'Grepos ' - QAINFO(2) = '2021/03/31 ' - QAINFO(3) = ' 1.89 ' + QAINFO(2) = '2022/02/03 ' + QAINFO(3) = ' 1.90 ' diff --git a/packages/seacas/applications/grepos/grepos.f b/packages/seacas/applications/grepos/grepos.f index 7104287ec97a..9efd4a03a5ab 100644 --- a/packages/seacas/applications/grepos/grepos.f +++ b/packages/seacas/applications/grepos/grepos.f @@ -1,4 +1,4 @@ -C Copyright(C) 1999-2021 National Technology & Engineering Solutions +C Copyright(C) 1999-2022 National Technology & Engineering Solutions C of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with C NTESS, the U.S. Government retains certain rights in this software. C @@ -684,7 +684,7 @@ PROGRAM GREPOS CALL MDRSRV ('IXELB', KIXELB, NELBLK) CALL MDRSRV ('JNELB', KJNELB, NELBLK) CALL MDRSRV ('ISCR', KISCR, NELBLK) - CALL MCRSRV ('NAMSCR', KNMSC, MXSTLN*NELBLK) + CALL MCRSRV ('NAMSCR', KNMSC, maxnam*NELBLK) CALL MDSTAT (NERR, MEM) IF (NERR .GT. 0) GOTO 40 @@ -814,7 +814,7 @@ PROGRAM GREPOS CALL MDRSRV ('ISCR', KISCR, NUMNPS) CALL MDRSRV ('IDNS0', KIDNS0, NUMNPS0) CALL MDRSRV ('NNNPS0', KNNNS0, NUMNPS0) - CALL MCRSRV ('NAMSCR', KNMSC, MXSTLN*NUMNPS) + CALL MCRSRV ('NAMSCR', KNMSC, maxnam*NUMNPS) CALL MDSTAT (NERR, MEM) IF (NERR .GT. 0) GOTO 40 @@ -898,7 +898,7 @@ PROGRAM GREPOS CALL MDRSRV ('ISCR', KISCR, NUMESS) CALL MDRSRV ('IDSS0', KIDSS0, NUMESS0) CALL MDRSRV ('NEESS0', KNESS0, NUMESS0) - CALL MCRSRV ('NAMSCR', KNMSC, MXSTLN*NUMESS) + CALL MCRSRV ('NAMSCR', KNMSC, maxnam*NUMESS) CALL MDSTAT (NERR, MEM) IF (NERR .GT. 0) GOTO 40 diff --git a/packages/seacas/applications/mapvar-kd/optkd.c b/packages/seacas/applications/mapvar-kd/optkd.c index 795cb37d837f..025a3205689f 100644 --- a/packages/seacas/applications/mapvar-kd/optkd.c +++ b/packages/seacas/applications/mapvar-kd/optkd.c @@ -25,11 +25,11 @@ #if defined ADDC_ #define KDRECTQUERY kdrectquery_ -#define KDKILLTREE kdkilltree_ +#define KDKILLTREE kdkilltree_ #define KDBUILDTREE kdbuildtree_ #else #define KDRECTQUERY kdrectquery -#define KDKILLTREE kdkilltree +#define KDKILLTREE kdkilltree #define KDBUILDTREE kdbuildtree #endif @@ -59,9 +59,7 @@ } static optkdNode *Root = NULL; -static int * perm = NULL; /* permutation array */ - -extern double fabs(); +static int *perm = NULL; /* permutation array */ /***************************************************************************/ /* Makes the perm partition the array Values along the element k. */ @@ -69,7 +67,7 @@ extern double fabs(); /***************************************************************************/ #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) -#define sign(x) ((x) >= 0 ? 1 : -1) +#define sign(x) ((x) >= 0 ? 1 : -1) /* * Floyd and Rivest SELECT Algorithm (CACM Algorithm 489) @@ -277,7 +275,7 @@ void KillOptTree(optkdNode *P) free(P); } -void KDKILLTREE() +void KDKILLTREE(void) { if (perm != NULL) { free(perm); diff --git a/packages/seacas/applications/nas2exo/N2EDataTypes.h b/packages/seacas/applications/nas2exo/N2EDataTypes.h index 4a874e881dc2..b8d88acb82ab 100644 --- a/packages/seacas/applications/nas2exo/N2EDataTypes.h +++ b/packages/seacas/applications/nas2exo/N2EDataTypes.h @@ -4,7 +4,7 @@ * Created on: Oct 10, 2020 * Author: Ramon J. Moral(Contractor, STRA LLC) * John Niederhouse(ORG 1443, SNL, Coordinator) - * Copyright: Sandia National Labs, 2020, 2021 + * Copyright: Sandia National Labs, 2020, 2021, 2022 */ #ifndef INCLUDE_N2EDATATYPES_H_ @@ -24,12 +24,12 @@ namespace N2EModules { struct supportedElements { - ex_entity_type elementType; + ex_entity_type elementType{}; char elemDesc[MAX_STR_LENGTH]{'\0'}; - int64_t numNodesPerElem; - int64_t numEdgesPerElem; - int64_t numFacesPerElem; - int64_t numAttrPerElem; + int64_t numNodesPerElem{}; + int64_t numEdgesPerElem{}; + int64_t numFacesPerElem{}; + int64_t numAttrPerElem{}; supportedElements(ex_entity_type elType, std::string elDesc, int64_t nodesPer, int64_t edgesPer, int64_t facesPer, int64_t attrPer) @@ -55,7 +55,7 @@ namespace N2EModules { }; struct N2EGridPtList { - double v[8]; + int v[8]; }; using sectionType = std::tuple; using gridType = std::tuple; diff --git a/packages/seacas/applications/nas2exo/N2EExoWriter.h b/packages/seacas/applications/nas2exo/N2EExoWriter.h index 187301dd79f2..2e764ebdcdef 100644 --- a/packages/seacas/applications/nas2exo/N2EExoWriter.h +++ b/packages/seacas/applications/nas2exo/N2EExoWriter.h @@ -4,7 +4,7 @@ * Created on: Oct 10, 2020 * Author: Ramon J. Moral(Contractor, STRA LLC) * John Niederhouse(ORG 1443, SNL, Coordinator) - * Copyright: Sandia National Labs, OCT-2021 + * Copyright: Sandia National Labs, OCT-2022 */ #ifndef _EXOWRITER_H_ @@ -44,11 +44,11 @@ namespace ExoModules { inline size_t getHexesOut() { return this->writtenHexes; }; protected: - std::vector sections; - std::vector gridList; - std::vector elementList; + std::vector sections{}; + std::vector gridList{}; + std::vector elementList{}; - std::string modelTitle; + std::string modelTitle{}; int exoFileID{0}; diff --git a/packages/seacas/applications/nas2exo/N2ENasReader.h b/packages/seacas/applications/nas2exo/N2ENasReader.h index 2001c0860000..a0872651f705 100644 --- a/packages/seacas/applications/nas2exo/N2ENasReader.h +++ b/packages/seacas/applications/nas2exo/N2ENasReader.h @@ -2,7 +2,7 @@ // Name : testnas2exo.cpp // Author : Ramon J. Moral (STRA LLC), John Niederhaus (Coordinator, SNL) // Version : -// Copyright : (c) Sandia National Labs 2020, 2021 +// Copyright : (c) Sandia National Labs 2020, 2021, 2022 // Description : Testing nas2exo Library, C++ 14 //============================================================================ @@ -47,11 +47,11 @@ namespace NasModules { std::unique_ptr inStream{}; unsigned lineCount{0u}; - std::vector sections; - std::vector gridList; - std::vector elementList; + std::vector sections{}; + std::vector gridList{}; + std::vector elementList{}; - std::string modelTitle; + std::string modelTitle{}; bool doesFileExist(const std::string &fname); // Local buffer for reading faster diff --git a/packages/seacas/applications/nem_slice/elb.h b/packages/seacas/applications/nem_slice/elb.h index 1e9e742d8dbf..183f0c5f77b3 100644 --- a/packages/seacas/applications/nem_slice/elb.h +++ b/packages/seacas/applications/nem_slice/elb.h @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -83,19 +83,19 @@ template struct LB_Description int *vertex2proc{nullptr}; /* Nodal */ - std::vector> int_nodes; - std::vector> bor_nodes; - std::vector> ext_nodes; - std::vector> ext_procs; + std::vector> int_nodes{}; + std::vector> bor_nodes{}; + std::vector> ext_nodes{}; + std::vector> ext_procs{}; /* Elemental */ std::vector>> born_procs{}; - std::vector> int_elems; - std::vector> bor_elems; - std::vector> e_cmap_elems; - std::vector> e_cmap_sides; - std::vector> e_cmap_procs; - std::vector> e_cmap_neigh; + std::vector> int_elems{}; + std::vector> bor_elems{}; + std::vector> e_cmap_elems{}; + std::vector> e_cmap_sides{}; + std::vector> e_cmap_procs{}; + std::vector> e_cmap_neigh{}; LB_Description() = default; }; diff --git a/packages/seacas/applications/nem_spread/ps_pario_const.h b/packages/seacas/applications/nem_spread/ps_pario_const.h index 6c33c4891350..9890495127a3 100644 --- a/packages/seacas/applications/nem_spread/ps_pario_const.h +++ b/packages/seacas/applications/nem_spread/ps_pario_const.h @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -23,37 +23,37 @@ extern double PIO_Time_Array[]; /* Vector for timings */ struct Parallel_IO { - int Dsk_List_Cnt; + int Dsk_List_Cnt{}; - int *Dsk_List; - int **RDsk_List; + int *Dsk_List{nullptr}; + int **RDsk_List{nullptr}; - int Num_Dsk_Ctrlrs; /* The number of disk controllers. */ - int Num_Dsks_PCtrlr; /* The number of disks per controller. */ - int PDsk_Add_Fact; /* The offset from zero used by the */ - /* the target machine. */ + int Num_Dsk_Ctrlrs{}; /* The number of disk controllers. */ + int Num_Dsks_PCtrlr{}; /* The number of disks per controller. */ + int PDsk_Add_Fact{}; /* The offset from zero used by the */ + /* the target machine. */ - int Zeros; /* 1 - if the target machine uses leading zeros when */ - /* designating the disk number (eg - the paragon */ - /* uses /pfs/io_01) */ - /* 0 - if it does not (eg - the tflop uses */ - /* /pfs/tmp_1) */ + int Zeros{}; /* 1 - if the target machine uses leading zeros when */ + /* designating the disk number (eg - the paragon */ + /* uses /pfs/io_01) */ + /* 0 - if it does not (eg - the tflop uses */ + /* /pfs/tmp_1) */ /* 1 - don't create a subdirectory for the spread files; write * them in same directory as the mesh file */ - int NoSubdirectory; + int NoSubdirectory{}; /* The root location of the parallel disks */ - std::string Par_Dsk_Root; + std::string Par_Dsk_Root{}; /* The subdirectory to write files to */ - std::string Par_Dsk_SubDirec; + std::string Par_Dsk_SubDirec{}; /* The filename extension for the parallel files */ - std::string Exo_Extension; + std::string Exo_Extension{}; - bool Staged_Writes; + bool Staged_Writes{}; }; extern struct Parallel_IO PIO_Info; diff --git a/packages/seacas/applications/zellij/Decompose.C b/packages/seacas/applications/zellij/Decompose.C index 695d2dad95a1..6d91c371c018 100644 --- a/packages/seacas/applications/zellij/Decompose.C +++ b/packages/seacas/applications/zellij/Decompose.C @@ -1,4 +1,4 @@ -// Copyright(C) 2021 National Technology & Engineering Solutions +// Copyright(C) 2021, 2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -18,6 +18,7 @@ #include "Cell.h" #include "Grid.h" #include "Ioss_ElementBlock.h" +#include "Ioss_ParallelUtils.h" #include "Ioss_Sort.h" extern unsigned int debug_level; @@ -189,7 +190,7 @@ void decompose_grid(Grid &grid, int ranks, const std::string &method) int ierr = 0; float ver = 0.0; Zoltan_Initialize(argc, argv, &ver); - struct Zoltan_Struct *zz = Zoltan_Create(MPI_COMM_WORLD); + struct Zoltan_Struct *zz = Zoltan_Create(Ioss::ParallelUtils::comm_world()); /* Register Callback functions */ /* Using global Zoltan_Data; could register it here instead as data field. */ diff --git a/packages/seacas/cmake/FortranSettings.cmake b/packages/seacas/cmake/FortranSettings.cmake index 736dce60524a..a28a55910132 100644 --- a/packages/seacas/cmake/FortranSettings.cmake +++ b/packages/seacas/cmake/FortranSettings.cmake @@ -1,7 +1,10 @@ ADD_DEFINITIONS(-DBuild64) -IF ("${FC_FN_UNDERSCORE}" STREQUAL "UNDER") - ADD_DEFINITIONS(-DADDC_) +IF (${PROJECT_NAME}_ENABLE_Fortran) + include(FortranCInterface) + if ("${FortranCInterface_GLOBAL_SUFFIX}" STREQUAL "_") + ADD_DEFINITIONS(-DADDC_) + ENDIF() ENDIF() IF ("${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU") diff --git a/packages/seacas/libraries/aprepro_lib/aprepro.h b/packages/seacas/libraries/aprepro_lib/aprepro.h index 749aed5f5bd2..470736c29d73 100644 --- a/packages/seacas/libraries/aprepro_lib/aprepro.h +++ b/packages/seacas/libraries/aprepro_lib/aprepro.h @@ -1,4 +1,4 @@ -// Copyright(C) 1999-, 20212021, National Technology & Engineering Solutions +// Copyright(C) 1999-2022, National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -20,7 +20,8 @@ #include #include -#if defined(_MSC_VER) +#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \ + defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__) #include #define isatty _isatty #endif @@ -90,6 +91,8 @@ namespace SEAMS { /// construct a new parser aprepro context Aprepro(); ~Aprepro(); + Aprepro(const Aprepro &) = delete; + Aprepro &operator=(const Aprepro &) = delete; enum class SYMBOL_TYPE { VARIABLE = 1, diff --git a/packages/seacas/libraries/chaco/assign/median.c b/packages/seacas/libraries/chaco/assign/median.c index 8835a7c840d4..554b6f5f8499 100644 --- a/packages/seacas/libraries/chaco/assign/median.c +++ b/packages/seacas/libraries/chaco/assign/median.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -10,11 +10,11 @@ #include "structs.h" // for vtx_data void median_assign(struct vtx_data **graph, /* data structure with vertex weights */ - double * vals, /* values of which to find median */ + double *vals, /* values of which to find median */ int nvtxs, /* number of values I own */ - double * goal, /* desired sizes for sets */ + double *goal, /* desired sizes for sets */ int using_vwgts, /* are vertex weights being used? */ - int * sets, /* assigned set for each vertex */ + int *sets, /* assigned set for each vertex */ double wlow, /* sum of weights below guess */ double whigh, /* sum of weights above guess */ double guess /* median value */ @@ -58,38 +58,38 @@ void median_assign(struct vtx_data **graph, /* data structure with vertex /* values which are on the wrong side of the guess. */ void median(struct vtx_data **graph, /* data structure with vertex weights */ - double * vals, /* values of which to find median */ + double *vals, /* values of which to find median */ int nvtxs, /* number of values I own */ - int * active, /* space for list of nvtxs ints */ - double * goal, /* desired sizes for sets */ + int *active, /* space for list of nvtxs ints */ + double *goal, /* desired sizes for sets */ int using_vwgts, /* are vertex weights being used? */ - int * sets /* set each vertex gets assigned to */ + int *sets /* set each vertex gets assigned to */ ) { - double *vptr; /* loops through vals array */ - double val; /* value in vals array */ - double maxval; /* largest active value */ - double minval; /* smallest active value */ - double guess; /* approximate median value */ - double nearup; /* lowest guy above guess */ - double neardown; /* highest guy below guess */ - double whigh; /* total weight of values above maxval */ - double wlow; /* total weight of values below minval */ - double wabove; /* total weight of active values above guess */ - double wbelow; /* total weight of active values below guess */ - double wexact; /* weight of vertices exactly at guess */ - double lweight; /* desired weight of lower values in set */ - double uweight; /* desired weight of upper values in set */ - double frac; /* fraction of values I want less than guess */ - int * aptr; /* loops through active array */ - int * aptr2; /* helps update active array */ - int myactive; /* number of active values I own */ - double wfree; /* weight of vtxs not yet divided */ - int removed; /* number of my values eliminated */ - /*int npass = 0;*/ /* counts passes required to find median */ - int done; /* check for termination criteria */ - int vtx; /* vertex being considered */ - int i; /* loop counters */ + double *vptr; /* loops through vals array */ + double val; /* value in vals array */ + double maxval; /* largest active value */ + double minval; /* smallest active value */ + double guess = 0.0; /* approximate median value */ + double nearup; /* lowest guy above guess */ + double neardown; /* highest guy below guess */ + double whigh; /* total weight of values above maxval */ + double wlow; /* total weight of values below minval */ + double wabove; /* total weight of active values above guess */ + double wbelow; /* total weight of active values below guess */ + double wexact; /* weight of vertices exactly at guess */ + double lweight; /* desired weight of lower values in set */ + double uweight; /* desired weight of upper values in set */ + double frac; /* fraction of values I want less than guess */ + int *aptr; /* loops through active array */ + int *aptr2; /* helps update active array */ + int myactive; /* number of active values I own */ + double wfree; /* weight of vtxs not yet divided */ + int removed; /* number of my values eliminated */ + /*int npass = 0;*/ /* counts passes required to find median */ + int done; /* check for termination criteria */ + int vtx; /* vertex being considered */ + int i; /* loop counters */ /* Initialize. */ diff --git a/packages/seacas/libraries/chaco/bpmatch/movevtxs.c b/packages/seacas/libraries/chaco/bpmatch/movevtxs.c index e9ae249eae6c..3cdb9c90771d 100644 --- a/packages/seacas/libraries/chaco/bpmatch/movevtxs.c +++ b/packages/seacas/libraries/chaco/bpmatch/movevtxs.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -20,13 +20,13 @@ static void nextmove(), undo_coupling(), couple(); void movevtxs(struct vtx_data **graph, /* data structure with vertex weights */ int nvtxs, /* number of vertices in graph */ int nsets, /* how many sets am I dividing into? */ - double * dist, /* distances defining splitter */ - int * indices[][MAXSETS], /* indices that define order in sorted lists */ - double * vals[][MAXSETS], /* values in sorted lists */ + double *dist, /* distances defining splitter */ + int *indices[][MAXSETS], /* indices that define order in sorted lists */ + double *vals[][MAXSETS], /* values in sorted lists */ int startvtx[][MAXSETS], /* index values corresponding to splitter */ - int * sets, /* set assignment for each vertex */ - double * size, /* sizes of the different sets */ - double * goal, /* desired set sizes */ + int *sets, /* set assignment for each vertex */ + double *size, /* sizes of the different sets */ + double *goal, /* desired set sizes */ int vwgt_max /* largest vertex weight */ ) { @@ -157,14 +157,14 @@ void movevtxs(struct vtx_data **graph, /* data structure with vert static void nextmove(int nvtxs, /* number of vertices in graph */ int nsets, /* how many sets am I dividing into? */ double *vals[][MAXSETS], /* values in sorted lists */ - int * indices[][MAXSETS], /* indices that define order in sorted lists */ + int *indices[][MAXSETS], /* indices that define order in sorted lists */ int startvtx[][MAXSETS], /* index values corresponding to splitter */ double *dist, /* distances defining splitter */ - int * sets, /* set assignment for each vertex */ + int *sets, /* set assignment for each vertex */ int toobig, /* is bad set too big or too small? */ - int * active, /* flags sets trying to change size */ - int * next_vtx, /* vertex selected to move next */ - int * next_to, /* set vertex should be moved to */ + int *active, /* flags sets trying to change size */ + int *next_vtx, /* vertex selected to move next */ + int *next_to, /* set vertex should be moved to */ double *next_delta /* size of change in distances */ ) { @@ -178,7 +178,7 @@ static void nextmove(int nvtxs, /* number of vertices in graph int bestvtx = 0; /* vertex being moved between sets */ int from, to; /* sets vertex wants to move from and to */ int index; /* offset into indices array */ - int dir; /* direction to step through list */ + int dir = 0; /* direction to step through list */ int i, j; /* loop counter */ bestdelta = 0; @@ -277,7 +277,7 @@ static void couple(int nsets, /* number of sets being divided into */ } static void undo_coupling(struct vtx_data **graph, /* data structure with vertex weights */ - int * sets, /* sets each vertex is in */ + int *sets, /* sets each vertex is in */ int nsets, /* number of sets being divided into */ int from, int to, /* set final vertex moved from and to */ int toobig, /* are we shrinking or enlarging a set? */ diff --git a/packages/seacas/libraries/chaco/coarsen/coarsen.c b/packages/seacas/libraries/chaco/coarsen/coarsen.c index 523cda92c3ff..b0e89f1a0c7e 100644 --- a/packages/seacas/libraries/chaco/coarsen/coarsen.c +++ b/packages/seacas/libraries/chaco/coarsen/coarsen.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -20,10 +20,10 @@ void coarsen( int nedges, /* number of edges in graph */ int using_vwgts, /* are vertices weights being used? */ int using_ewgts, /* are edge weights being used? */ - float * term_wgts[], /* terminal weights */ + float *term_wgts[], /* terminal weights */ int igeom, /* dimension for geometric information */ - float ** coords, /* coordinates for vertices */ - double ** yvecs, /* eigenvectors returned */ + float **coords, /* coordinates for vertices */ + double **yvecs, /* eigenvectors returned */ int ndims, /* number of eigenvectors to calculate */ int solver_flag, /* which eigensolver to use */ int vmax, /* largest subgraph to stop coarsening */ @@ -33,7 +33,7 @@ void coarsen( int give_up /* has coarsening bogged down? */ ) { - extern FILE * Output_File; /* output file or null */ + extern FILE *Output_File; /* output file or null */ extern int DEBUG_COARSEN; /* debug flag for coarsening */ extern int PERTURB; /* was matrix perturbed in Lanczos? */ extern double COARSEN_RATIO_MIN; /* min vtx reduction for coarsening */ @@ -41,32 +41,32 @@ void coarsen( extern int COARSEN_EWGTS; /* use edge weights while coarsening? */ extern double refine_time; /* time for RQI/Symmlq iterative refinement */ struct vtx_data **cgraph; /* array of vtx data for coarsened graph */ - struct orthlink * orthlist; /* list of lower evecs to suppress */ - struct orthlink * newlink; /* lower evec to suppress */ - double * cyvecs[MAXDIMS + 1]; /* eigenvectors for subgraph */ + struct orthlink *orthlist; /* list of lower evecs to suppress */ + struct orthlink *newlink; /* lower evec to suppress */ + double *cyvecs[MAXDIMS + 1]; /* eigenvectors for subgraph */ double evals[MAXDIMS + 1]; /* eigenvalues returned */ double goal[MAXSETS]; /* needed for convergence mode = 1 */ - double * r1, *r2, *work; /* space needed by symmlq/RQI */ - double * v, *w, *x, *y; /* space needed by symmlq/RQI */ - double * gvec; /* rhs vector in extended eigenproblem */ + double *r1, *r2, *work; /* space needed by symmlq/RQI */ + double *v, *w, *x, *y; /* space needed by symmlq/RQI */ + double *gvec; /* rhs vector in extended eigenproblem */ double evalest; /* eigenvalue estimate returned by RQI */ double maxdeg; /* maximum weighted degree of a vertex */ - float ** ccoords; /* coordinates for coarsened graph */ - float * cterm_wgts[MAXSETS]; /* coarse graph terminal weights */ - float * new_term_wgts[MAXSETS]; /* terminal weights for Bui's method*/ - float ** real_term_wgts; /* one of the above */ - float * twptr = NULL; /* loops through term_wgts */ - float * twptr_save = NULL; /* copy of twptr */ - float * ctwptr; /* loops through cterm_wgts */ - double * vwsqrt = NULL; /* square root of vertex weights */ + float **ccoords; /* coordinates for coarsened graph */ + float *cterm_wgts[MAXSETS]; /* coarse graph terminal weights */ + float *new_term_wgts[MAXSETS]; /* terminal weights for Bui's method*/ + float **real_term_wgts; /* one of the above */ + float *twptr = NULL; /* loops through term_wgts */ + float *twptr_save = NULL; /* copy of twptr */ + float *ctwptr; /* loops through cterm_wgts */ + double *vwsqrt = NULL; /* square root of vertex weights */ double norm, alpha; /* values used for orthogonalization */ double initshift; /* initial shift for RQI */ double total_vwgt; /* sum of all the vertex weights */ double w1, w2; /* weights of two sets */ double term_tot; /* sum of all terminal weights */ - int * space; /* room for assignment in Lanczos */ - int * morespace; /* room for assignment in Lanczos */ - int * v2cv; /* mapping from vertices to coarse vtxs */ + int *space; /* room for assignment in Lanczos */ + int *morespace; /* room for assignment in Lanczos */ + int *v2cv; /* mapping from vertices to coarse vtxs */ int vwgt_max; /* largest vertex weight */ int oldperturb; /* saves PERTURB value */ int cnvtxs; /* number of vertices in coarsened graph */ @@ -76,7 +76,8 @@ void coarsen( int i, j; /* loop counters */ double time; /* time marker */ - double dot(), ch_normalize(), find_maxdeg(), seconds(); + double dot(double *vec1, int beg, int end, double *vec2), ch_normalize(), find_maxdeg(), + seconds(void); struct orthlink *makeorthlnk(); void makevwsqrt(), eigensolve(), coarsen1(), orthogvec(), rqi_ext(); void ch_interpolate(), orthog1(), rqi(), scadd(), free_graph(); diff --git a/packages/seacas/libraries/chaco/coarsen/coarsen1.c b/packages/seacas/libraries/chaco/coarsen/coarsen1.c index 09c55bf83b40..04e34a8b0fba 100644 --- a/packages/seacas/libraries/chaco/coarsen/coarsen1.c +++ b/packages/seacas/libraries/chaco/coarsen/coarsen1.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -9,27 +9,27 @@ #include "smalloc.h" // for smalloc, sfree #include "structs.h" -void coarsen1(struct vtx_data ** graph, /* array of vtx data for graph */ +void coarsen1(struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ struct vtx_data ***pcgraph, /* coarsened version of graph */ - int * pcnvtxs, /* number of vtxs in coarsened graph */ - int * pcnedges, /* number of edges in coarsened graph */ - int ** pv2cv, /* pointer to v2cv */ + int *pcnvtxs, /* number of vtxs in coarsened graph */ + int *pcnedges, /* number of edges in coarsened graph */ + int **pv2cv, /* pointer to v2cv */ int igeom, /* dimension for geometric information */ - float ** coords, /* coordinates for vertices */ - float ** ccoords, /* coordinates for coarsened vertices */ + float **coords, /* coordinates for vertices */ + float **ccoords, /* coordinates for coarsened vertices */ int using_ewgts /* are edge weights being used? */ ) { extern double coarsen_time; extern double match_time; double time; /* time routine is entered */ - int * v2cv; /* maps from vtxs to cvtxs */ - int * mflag; /* flag indicating vtx matched or not */ + int *v2cv; /* maps from vtxs to cvtxs */ + int *mflag; /* flag indicating vtx matched or not */ int cnvtxs; /* number of vtxs in coarse graph */ int nmerged; /* number of edges contracted */ - double seconds(); + double seconds(void); int maxmatch(); void makev2cv(), makefgraph(); diff --git a/packages/seacas/libraries/chaco/coarsen/makecgraph.c b/packages/seacas/libraries/chaco/coarsen/makecgraph.c index 42ff595c6eb2..2d4379c96464 100644 --- a/packages/seacas/libraries/chaco/coarsen/makecgraph.c +++ b/packages/seacas/libraries/chaco/coarsen/makecgraph.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -12,18 +12,18 @@ extern void makeccoords(); -void makecgraph(struct vtx_data ** graph, /* array of vtx data for graph */ +void makecgraph(struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ struct vtx_data ***pcgraph, /* coarsened version of graph */ - int * pcnvtxs, /* number of vtxs in coarsened graph */ - int * pcnedges, /* number of edges in coarsened graph */ - int * mflag, /* flag indicating vtx matched or not */ - int * v2cv, /* mapping from vtxs to coarsened vtxs */ + int *pcnvtxs, /* number of vtxs in coarsened graph */ + int *pcnedges, /* number of edges in coarsened graph */ + int *mflag, /* flag indicating vtx matched or not */ + int *v2cv, /* mapping from vtxs to coarsened vtxs */ int nmerged, /* number of merged vertices */ int using_ewgts, /* are edge weights being used? */ int igeom, /* dimensions of geometric data */ - float ** coords, /* coordinates for vertices */ - float ** ccoords /* coordinates for coarsened vertices */ + float **coords, /* coordinates for vertices */ + float **ccoords /* coordinates for coarsened vertices */ ) { extern double make_cgraph_time; @@ -31,15 +31,15 @@ void makecgraph(struct vtx_data ** graph, /* array of vtx data for graph * extern int COARSEN_VWGTS; /* turn off vertex weights in coarse graph? */ extern int COARSEN_EWGTS; /* turn off edge weights in coarse graph? */ struct vtx_data **cgraph = NULL; /* coarsened version of graph */ - struct vtx_data * links = NULL; /* space for all the vertex data */ + struct vtx_data *links = NULL; /* space for all the vertex data */ struct vtx_data **gptr = NULL; /* loops through cgraph */ - struct vtx_data * cgptr = NULL; /* loops through cgraph */ - int * start = NULL; /* start of edgevals list for each vertex */ - int * iptr = NULL; /* loops through integer arrays */ - int * seenflag = NULL; /* flags for vtxs already put in edge list */ - int * sptr = NULL; /* loops through seenflags */ - float * eweights = NULL; /* space for edge weights in coarsened graph */ - float * fptr = NULL; /* loops through eweights */ + struct vtx_data *cgptr = NULL; /* loops through cgraph */ + int *start = NULL; /* start of edgevals list for each vertex */ + int *iptr = NULL; /* loops through integer arrays */ + int *seenflag = NULL; /* flags for vtxs already put in edge list */ + int *sptr = NULL; /* loops through seenflags */ + float *eweights = NULL; /* space for edge weights in coarsened graph */ + float *fptr = NULL; /* loops through eweights */ float ewgt = 0.0; /* edge weight */ double ewgt_sum; /* sum of edge weights */ double time; /* timing parameters */ @@ -48,11 +48,11 @@ void makecgraph(struct vtx_data ** graph, /* array of vtx data for graph * int cnedges; /* twice number of edges in coarsened graph */ int neighbor; /* neighboring vertex */ int size; /* space needed for coarsened graph */ - int * edges = NULL; /* space for edges in coarsened graph */ + int *edges = NULL; /* space for edges in coarsened graph */ int cvtx; /* vertex number in coarsened graph */ int cneighbor; /* neighboring vertex number in coarsened graph */ int i, j; /* loop counters */ - double seconds(); + double seconds(void); void makev2cv(), countcedges(); diff --git a/packages/seacas/libraries/chaco/coarsen/makecgraph2.c b/packages/seacas/libraries/chaco/coarsen/makecgraph2.c index 319afe883af2..354cd899ccae 100644 --- a/packages/seacas/libraries/chaco/coarsen/makecgraph2.c +++ b/packages/seacas/libraries/chaco/coarsen/makecgraph2.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -10,19 +10,19 @@ #include "structs.h" // for vtx_data #include // for NULL, printf -void makecgraph2(struct vtx_data ** graph, /* array of vtx data for graph */ +void makecgraph2(struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ struct vtx_data ***pcgraph, /* coarsened version of graph */ - int * pcnvtxs, /* number of vtxs in coarsened graph */ - int * pcnedges, /* number of edges in coarsened graph */ - int * mflag, /* flag indicating vtx matched or not */ - int * v2cv, /* mapping from vtxs to coarsened vtxs */ + int *pcnvtxs, /* number of vtxs in coarsened graph */ + int *pcnedges, /* number of edges in coarsened graph */ + int *mflag, /* flag indicating vtx matched or not */ + int *v2cv, /* mapping from vtxs to coarsened vtxs */ int nmerged, /* number of merged vertices */ int using_ewgts, /* are edge weights being used? */ int igeom, /* dimensions of geometric data */ - float ** coords, /* coordinates for vertices */ - float ** ccoords /* coordinates for coarsened vertices */ + float **coords, /* coordinates for vertices */ + float **ccoords /* coordinates for coarsened vertices */ ) { extern double make_cgraph_time; @@ -30,15 +30,15 @@ void makecgraph2(struct vtx_data ** graph, /* array of vtx data for graph extern int COARSEN_VWGTS; /* turn off vertex weights in coarse graph? */ extern int COARSEN_EWGTS; /* turn off edge weights in coarse graph? */ struct vtx_data **cgraph; /* coarsened version of graph */ - struct vtx_data * links = NULL; /* space for all the vertex data */ + struct vtx_data *links = NULL; /* space for all the vertex data */ struct vtx_data **gptr = NULL; /* loops through cgraph */ - struct vtx_data * cgptr = NULL; /* loops through cgraph */ - int * iptr = NULL; /* loops through integer arrays */ - int * seenflag = NULL; /* flags for vtxs already put in edge list */ - int * sptr = NULL; /* loops through seenflags */ - float * eweights = NULL; /* space for edge weights in coarsened graph */ - float * ewptr = NULL; /* loops through eweights */ - float * fptr = NULL; /* loops through eweights */ + struct vtx_data *cgptr = NULL; /* loops through cgraph */ + int *iptr = NULL; /* loops through integer arrays */ + int *seenflag = NULL; /* flags for vtxs already put in edge list */ + int *sptr = NULL; /* loops through seenflags */ + float *eweights = NULL; /* space for edge weights in coarsened graph */ + float *ewptr = NULL; /* loops through eweights */ + float *fptr = NULL; /* loops through eweights */ float ewgt; /* edge weight */ double ewgt_sum; /* sum of edge weights */ double time; /* timing parameters */ @@ -47,14 +47,14 @@ void makecgraph2(struct vtx_data ** graph, /* array of vtx data for graph int cnedges; /* twice number of edges in coarsened graph */ int neighbor; /* neighboring vertex */ int size; /* space needed for coarsened graph */ - int * edges = NULL; /* space for edges in coarsened graph */ - int * eptr = NULL; /* loops through edges data structure */ + int *edges = NULL; /* space for edges in coarsened graph */ + int *eptr = NULL; /* loops through edges data structure */ int cvtx; /* vertex number in coarsened graph */ int cneighbor; /* neighboring vertex number in coarsened graph */ double m1, m2; /* vertex weights of vertices being merged */ int v1, v2; /* vertices being merged */ int i, j; /* loop counters */ - double seconds(); + double seconds(void); void makev2cv(); /* Compute the number of vertices and edges in the coarsened graph, */ diff --git a/packages/seacas/libraries/chaco/coarsen/makefgraph.c b/packages/seacas/libraries/chaco/coarsen/makefgraph.c index b187d939f479..ec2a94a30ce8 100644 --- a/packages/seacas/libraries/chaco/coarsen/makefgraph.c +++ b/packages/seacas/libraries/chaco/coarsen/makefgraph.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -12,17 +12,17 @@ static void makecv2v(); -void makefgraph(struct vtx_data ** graph, /* array of vtx data for graph */ +void makefgraph(struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ struct vtx_data ***pcgraph, /* coarsened version of graph */ int cnvtxs, /* number of vtxs in coarsened graph */ - int * pcnedges, /* number of edges in coarsened graph */ - int * v2cv, /* mapping from vtxs to coarsened vtxs */ + int *pcnedges, /* number of edges in coarsened graph */ + int *v2cv, /* mapping from vtxs to coarsened vtxs */ int using_ewgts, /* are edge weights being used? */ int igeom, /* dimensions of geometric data */ - float ** coords, /* coordinates for vertices */ - float ** ccoords /* coordinates for coarsened vertices */ + float **coords, /* coordinates for vertices */ + float **ccoords /* coordinates for coarsened vertices */ ) { extern double make_cgraph_time; @@ -30,17 +30,17 @@ void makefgraph(struct vtx_data ** graph, /* array of vtx data for graph * extern int COARSEN_VWGTS; /* turn off vertex weights in coarse graph? */ extern int COARSEN_EWGTS; /* turn off edge weights in coarse graph? */ struct vtx_data **cgraph = NULL; /* coarsened version of graph */ - struct vtx_data * links = NULL; /* space for all the vertex data */ + struct vtx_data *links = NULL; /* space for all the vertex data */ struct vtx_data **gptr = NULL; /* loops through cgraph */ - struct vtx_data * cgptr = NULL; /* loops through cgraph */ - int * iptr = NULL; /* loops through integer arrays */ - int * seenflag = NULL; /* flags for vtxs already put in edge list */ - int * sptr = NULL; /* loops through seenflags */ - int * cv2v_vals = NULL; /* vtxs corresponding to each cvtx */ - int * cv2v_ptrs = NULL; /* indices into cv2v_vals */ - float * eweights = NULL; /* space for edge weights in coarsened graph */ - float * ewptr = NULL; /* loops through eweights */ - float * fptr = NULL; /* loops through eweights */ + struct vtx_data *cgptr = NULL; /* loops through cgraph */ + int *iptr = NULL; /* loops through integer arrays */ + int *seenflag = NULL; /* flags for vtxs already put in edge list */ + int *sptr = NULL; /* loops through seenflags */ + int *cv2v_vals = NULL; /* vtxs corresponding to each cvtx */ + int *cv2v_ptrs = NULL; /* indices into cv2v_vals */ + float *eweights = NULL; /* space for edge weights in coarsened graph */ + float *ewptr = NULL; /* loops through eweights */ + float *fptr = NULL; /* loops through eweights */ float ewgt; /* edge weight */ double ewgt_sum; /* sum of edge weights */ double time; /* timing parameters */ @@ -50,11 +50,11 @@ void makefgraph(struct vtx_data ** graph, /* array of vtx data for graph * int cnedges; /* twice number of edges in coarsened graph */ int neighbor; /* neighboring vertex */ int size; /* space needed for coarsened graph */ - int * edges = NULL; /* space for edges in coarsened graph */ - int * eptr = NULL; /* loops through edges data structure */ + int *edges = NULL; /* space for edges in coarsened graph */ + int *eptr = NULL; /* loops through edges data structure */ int cneighbor; /* neighboring vertex number in coarsened graph */ int i, j; /* loop counters */ - double seconds(); + double seconds(void); void makeccoords(); /* Compute the number of vertices and edges in the coarsened graph, */ diff --git a/packages/seacas/libraries/chaco/coarsen/maxmatch1.c b/packages/seacas/libraries/chaco/coarsen/maxmatch1.c index 2bb3df7a4587..6086e7b3bf2e 100644 --- a/packages/seacas/libraries/chaco/coarsen/maxmatch1.c +++ b/packages/seacas/libraries/chaco/coarsen/maxmatch1.c @@ -15,20 +15,20 @@ int maxmatch1(struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ - int * mflag, /* flag indicating vtx selected or not */ + int *mflag, /* flag indicating vtx selected or not */ int using_ewgts /* are edge weights being used? */ ) { extern int HEAVY_MATCH; /* choose heavy edges in matching? */ float ewgt_max; /* largest edge weight seen so far */ - int * jptr; /* loops through integer arrays */ + int *jptr; /* loops through integer arrays */ int vtx; /* vertex to process next */ int neighbor; /* neighbor of a vertex */ int nmerged; /* number of edges in matching */ int matched; /* is a vertex matched yet? */ int jsave; /* best matching edge found so far */ int i, j; /* loop counters */ - double drandom(); + double drandom(void); /* Initialize mflag array. */ jptr = mflag; diff --git a/packages/seacas/libraries/chaco/coarsen/maxmatch2.c b/packages/seacas/libraries/chaco/coarsen/maxmatch2.c index 3f8f769b8aea..9556bf6288e1 100644 --- a/packages/seacas/libraries/chaco/coarsen/maxmatch2.c +++ b/packages/seacas/libraries/chaco/coarsen/maxmatch2.c @@ -16,12 +16,12 @@ int maxmatch2(struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ - int * mflag, /* flag indicating vtx selected or not */ + int *mflag, /* flag indicating vtx selected or not */ int using_ewgts /* are edge weights being used? */ ) { extern int HEAVY_MATCH; /* encourage heavy matching edges? */ - void randomize(); + void randomize(int *array, int n); /* First, randomly permute the vertices. */ int *order = smalloc((nvtxs + 1) * sizeof(int)); diff --git a/packages/seacas/libraries/chaco/coarsen/maxmatch3.c b/packages/seacas/libraries/chaco/coarsen/maxmatch3.c index eceb6e18ab5d..864ebe22826a 100644 --- a/packages/seacas/libraries/chaco/coarsen/maxmatch3.c +++ b/packages/seacas/libraries/chaco/coarsen/maxmatch3.c @@ -15,13 +15,13 @@ int maxmatch3(struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ - int * mflag, /* flag indicating vtx selected or not */ + int *mflag, /* flag indicating vtx selected or not */ int using_ewgts /* are edge weights being used? */ ) { extern int HEAVY_MATCH; /* pick heavy edges in matching? */ - int * order; /* random ordering of vertices */ - int * iptr, *jptr; /* loops through integer arrays */ + int *order; /* random ordering of vertices */ + int *iptr, *jptr; /* loops through integer arrays */ double prob_sum; /* sum of probabilities to select from */ double val; /* random value for selecting neighbor */ float ewgt; /* edge weight */ @@ -31,8 +31,8 @@ int maxmatch3(struct vtx_data **graph, /* array of vtx data for graph */ int nmerged; /* number of edges in matching */ int i, j; /* loop counters */ - double drandom(); - void randomize(); + double drandom(void); + void randomize(int *array, int n); /* First, randomly permute the vertices. */ iptr = order = smalloc((nvtxs + 1) * sizeof(int)); diff --git a/packages/seacas/libraries/chaco/coarsen/maxmatch4.c b/packages/seacas/libraries/chaco/coarsen/maxmatch4.c index 7c696af4b822..5d8c44d6a348 100644 --- a/packages/seacas/libraries/chaco/coarsen/maxmatch4.c +++ b/packages/seacas/libraries/chaco/coarsen/maxmatch4.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -19,21 +19,21 @@ int maxmatch4(struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ - int * mflag, /* flag indicating vtx selected or not */ + int *mflag, /* flag indicating vtx selected or not */ int using_ewgts) { extern int HEAVY_MATCH; /* try for heavy edges in matching? */ - int * iptr; /* loops through integer arrays */ - float * edgevals; /* random values for all edges */ - float * evptr; /* loops through edgevals */ + int *iptr; /* loops through integer arrays */ + float *edgevals; /* random values for all edges */ + float *evptr; /* loops through edgevals */ double maxval; /* largest edge value for a vertex */ int neighbor; /* neighbor of a vertex */ int nmerged; /* number of edges in matching */ int change; /* any new edges in matching? */ - int * start; /* start of edgevals list for each vertex */ + int *start; /* start of edgevals list for each vertex */ int i, j, k; /* loop counters */ - double drandom(); + double drandom(void); /* Allocate and initialize space. */ evptr = edgevals = smalloc(2 * nedges * sizeof(float)); diff --git a/packages/seacas/libraries/chaco/coarsen/maxmatch5.c b/packages/seacas/libraries/chaco/coarsen/maxmatch5.c index d81a25878bc6..5955e517ea0c 100644 --- a/packages/seacas/libraries/chaco/coarsen/maxmatch5.c +++ b/packages/seacas/libraries/chaco/coarsen/maxmatch5.c @@ -12,21 +12,21 @@ int maxmatch5(struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ - int * mflag, /* flag indicating vtx selected or not */ + int *mflag, /* flag indicating vtx selected or not */ int igeom, /* geometric dimensionality */ - float ** coords /* coordinates of each vertex */ + float **coords /* coordinates of each vertex */ ) { extern double DOUBLE_MAX; /* largest floating point value */ double dist; /* distance to free neighbor */ double min_dist; /* smallest distance to free neighbor */ - int * jptr; /* loops through integer arrays */ + int *jptr; /* loops through integer arrays */ int vtx; /* vertex to process next */ int neighbor; /* neighbor of a vertex */ int nmerged; /* number of edges in matching */ int jsave; /* best edge so far */ int i, j; /* loop counters */ - double drandom(); + double drandom(void); /* Initialize mflag array. */ jptr = mflag; diff --git a/packages/seacas/libraries/chaco/coarsen/maxmatch9.c b/packages/seacas/libraries/chaco/coarsen/maxmatch9.c index a855f09ab100..ba85d4a76651 100644 --- a/packages/seacas/libraries/chaco/coarsen/maxmatch9.c +++ b/packages/seacas/libraries/chaco/coarsen/maxmatch9.c @@ -16,14 +16,14 @@ int maxmatch9(struct vtx_data **graph, /* array of vtx data for graph */ int nvtxs, /* number of vertices in graph */ - int * mflag, /* flag indicating vtx selected or not */ + int *mflag, /* flag indicating vtx selected or not */ int using_ewgts /* are edge weights being used? */ ) { extern int HEAVY_MATCH; /* use heavy-edge matching? */ - int * order; /* random ordering of vertices */ - int * neighbors; /* scatter array for neighbor list */ - int * iptr, *jptr; /* loops through integer arrays */ + int *order; /* random ordering of vertices */ + int *neighbors; /* scatter array for neighbor list */ + int *iptr, *jptr; /* loops through integer arrays */ float ewgt; /* edge weight */ int save; /* neighbor vertex if only one active */ int vtx; /* vertex to process next */ @@ -34,7 +34,7 @@ int maxmatch9(struct vtx_data **graph, /* array of vtx data for graph */ int nmerged; /* number of edges in matching */ int i, j, k; /* loop counters */ - void randomize(); + void randomize(int *array, int n); /* First, randomly permute the vertices. */ neighbors = smalloc((nvtxs + 1) * sizeof(int)); diff --git a/packages/seacas/libraries/chaco/connect/find_comps.c b/packages/seacas/libraries/chaco/connect/find_comps.c index 4475728e67ae..c41510f377e2 100644 --- a/packages/seacas/libraries/chaco/connect/find_comps.c +++ b/packages/seacas/libraries/chaco/connect/find_comps.c @@ -15,15 +15,15 @@ static int bfsearch(); /* Breadth first search algorithm to find & mark connected components. */ int find_comps(struct vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices in graph */ - int * mark, /* space for nvtxs+1 ints */ - int * vtxlist /* space for nvtxs ints */ + int *mark, /* space for nvtxs+1 ints */ + int *vtxlist /* space for nvtxs ints */ ) { int root; /* vertex to start the dfs */ int count; /* number of vertices seen so far */ int ncomps; /* number of components found */ int i; /* loop counter */ - double drandom(); + double drandom(void); for (i = 1; i <= nvtxs; i++) { mark[i] = -1; @@ -52,10 +52,10 @@ int find_comps(struct vtx_data **graph, /* graph data structure */ /* Breadth first search algorithm to find & mark connected components. */ /* Returns list of edges to connect them together. */ -int find_edges(struct vtx_data ** graph, /* graph data structure */ +int find_edges(struct vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices in graph */ - int * mark, /* space for nvtxs+1 ints */ - int * vtxlist, /* space for nvtxs ints */ + int *mark, /* space for nvtxs+1 ints */ + int *vtxlist, /* space for nvtxs ints */ struct edgeslist **edges /* list of edges connecting graph */ ) { @@ -65,7 +65,7 @@ int find_edges(struct vtx_data ** graph, /* graph data structure */ int count; /* number of vertices seen so far */ int nadded; /* number of edges needed to be added */ int i; /* loop counter */ - double drandom(); + double drandom(void); for (i = 1; i <= nvtxs; i++) { mark[i] = -1; @@ -101,9 +101,9 @@ int find_edges(struct vtx_data ** graph, /* graph data structure */ /* BFS to find connected component */ static int bfsearch(struct vtx_data **graph, /* graph data structure */ int root, /* start vertex for DFS */ - int * count, /* number of vertices in component */ - int * mark, /* has vtx been seen? */ - int * vtxlist, /* space for storing vtxs to search */ + int *count, /* number of vertices in component */ + int *mark, /* has vtx been seen? */ + int *vtxlist, /* space for storing vtxs to search */ int comp_num /* current component number */ ) { diff --git a/packages/seacas/libraries/chaco/eigen/Tevec.c b/packages/seacas/libraries/chaco/eigen/Tevec.c index 595b0e89a416..a6ff79837fb3 100644 --- a/packages/seacas/libraries/chaco/eigen/Tevec.c +++ b/packages/seacas/libraries/chaco/eigen/Tevec.c @@ -48,7 +48,7 @@ double Tevec(double *alpha, /* vector of Lanczos scalars */ int i; /* index */ double residual = 0.0; /* how well recurrence gives eigenvector */ double temp; /* used to compute residual */ - double * work; /* temporary work vector allocated within if used */ + double *work; /* temporary work vector allocated within if used */ double w[MAXDIMS + 1]; /* holds eigenvalue for tinvit */ long index[MAXDIMS + 1]; /* index vector for tinvit */ long ierr; /* error flag for tinvit */ @@ -57,11 +57,11 @@ double Tevec(double *alpha, /* vector of Lanczos scalars */ double hurdle; /* hurdle for local maximum in recurrence */ double prev_resid; /* stores residual from previous computation */ - int tinvit(); /* eispack's tinvit for evecs of symmetric T */ - double *mkvec(); /* allocates double vectors */ - void frvec(); /* frees double vectors */ - double bidir(); /* bidirectional recurrence for evec of T */ - void cpvec(); /* vector copy routine */ + int tinvit(); /* eispack's tinvit for evecs of symmetric T */ + double *mkvec(int nl, int nh); /* allocates double vectors */ + void frvec(double *v, int nl); /* frees double vectors */ + double bidir(); /* bidirectional recurrence for evec of T */ + void cpvec(); /* vector copy routine */ s[1] = 1.0; diff --git a/packages/seacas/libraries/chaco/eigen/checkeig.c b/packages/seacas/libraries/chaco/eigen/checkeig.c index 92b0978fcbe3..5f6041c75d91 100644 --- a/packages/seacas/libraries/chaco/eigen/checkeig.c +++ b/packages/seacas/libraries/chaco/eigen/checkeig.c @@ -14,7 +14,7 @@ double checkeig(double *err, struct vtx_data **A, double *y, int n, double lambd { double resid; double normy; - double ch_norm(); + double ch_norm(double *vec, int beg, int end); void splarax(), scadd(); splarax(err, A, n, y, vwsqrt, work); diff --git a/packages/seacas/libraries/chaco/eigen/checkeig_ext.c b/packages/seacas/libraries/chaco/eigen/checkeig_ext.c index d53859c11131..fb06c710f595 100644 --- a/packages/seacas/libraries/chaco/eigen/checkeig_ext.c +++ b/packages/seacas/libraries/chaco/eigen/checkeig_ext.c @@ -19,15 +19,15 @@ double checkeig_ext(double *err, double *work, /* work vector of length n */ contexts this is called */ ) { - extern FILE *Output_File; /* output file or null */ - extern int DEBUG_EVECS; /* print debugging output? */ - extern int WARNING_EVECS; /* print warning messages? */ - double resid; /* the extended eigen residual */ - double ch_norm(); /* vector norm */ - void splarax(); /* sparse matrix vector mult */ - void scadd(); /* scaled vector add */ - void scale_diag(); /* scale vector by another's elements */ - void cpvec(); /* vector copy */ + extern FILE *Output_File; /* output file or null */ + extern int DEBUG_EVECS; /* print debugging output? */ + extern int WARNING_EVECS; /* print warning messages? */ + double resid; /* the extended eigen residual */ + double ch_norm(double *vec, int beg, int end); /* vector norm */ + void splarax(); /* sparse matrix vector mult */ + void scadd(); /* scaled vector add */ + void scale_diag(); /* scale vector by another's elements */ + void cpvec(); /* vector copy */ splarax(err, A, n, y, vwsqrt, work); scadd(err, 1, n, -extval, y); diff --git a/packages/seacas/libraries/chaco/eigen/checkorth.c b/packages/seacas/libraries/chaco/eigen/checkorth.c index 47db459013df..80745d8a175c 100644 --- a/packages/seacas/libraries/chaco/eigen/checkorth.c +++ b/packages/seacas/libraries/chaco/eigen/checkorth.c @@ -21,7 +21,7 @@ void checkorth(double **mat, int n, int dim) int screenlim; /* value of lim that will fit on screen */ int option; /* which option to use */ - double dot(); /* standard dot product routine */ + double dot(double *vec1, int beg, int end, double *vec2); /* standard dot product routine */ /* The T/F argument in the conditionals is just a convenient option: */ @@ -92,7 +92,7 @@ void checkorth_float(float **mat, int n, int dim) int screenlim; /* value of lim that will fit on screen */ int option; /* which option to use */ - double dot_float(); /* standard dot product routine */ + double dot_float(float *vec1, int beg, int end, float *vec2); /* standard dot product routine */ /* The T/F argument in the conditionals is just a convenient option: */ diff --git a/packages/seacas/libraries/chaco/eigen/eigensolve.c b/packages/seacas/libraries/chaco/eigen/eigensolve.c index e3fa5eaaf385..3ffec22dfcaf 100644 --- a/packages/seacas/libraries/chaco/eigen/eigensolve.c +++ b/packages/seacas/libraries/chaco/eigen/eigensolve.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -19,17 +19,17 @@ void eigensolve(struct vtx_data **graph, /* graph data structure */ int nedges, /* number of edges in graph */ double maxdeg, /* largest (weighted) degree of a vertex */ int vwgt_max, /* largest vertex weight */ - double * vwsqrt, /* sqrt of vertex weights (length nvtxs+1) */ + double *vwsqrt, /* sqrt of vertex weights (length nvtxs+1) */ int using_vwgts, /* are vertex weights being used? */ int using_ewgts, /* are edge weights being used? */ - float * term_wgts[], /* terminal propagation weight vector */ + float *term_wgts[], /* terminal propagation weight vector */ int igeom, /* geometric dimensionality if given coords */ - float ** coords, /* coordinates of vertices */ - double ** yvecs, /* space for pointing to eigenvectors */ - double * evals, /* eigenvalues associated with eigenvectors */ + float **coords, /* coordinates of vertices */ + double **yvecs, /* space for pointing to eigenvectors */ + double *evals, /* eigenvalues associated with eigenvectors */ int architecture, /* 0 => hypercube, d => d-dimensional mesh */ - int * assignment, /* set number of each vtx (length n+1) */ - double * goal, /* desired set sizes */ + int *assignment, /* set number of each vtx (length n+1) */ + double *goal, /* desired set sizes */ int solver_flag, /* flag indicating which solver to use */ int rqi_flag, /* use multi-level techniques? */ int vmax, /* if so, how many vtxs to coarsen down to? */ @@ -55,15 +55,15 @@ void eigensolve(struct vtx_data **graph, /* graph data structure */ extern int EXPERT; /* user type */ double bound[MAXDIMS + 1]; /* ritz approx bounds to eigenpairs */ double time; /* time marker */ - float * dummy_twgt[2]; /* turns off terminal propagation */ - float * twptr; /* terminal propagation weight vector */ - int * active; /* space for nvtxs values */ + float *dummy_twgt[2]; /* turns off terminal propagation */ + float *twptr; /* terminal propagation weight vector */ + int *active; /* space for nvtxs values */ int step; /* current step in RQI counting */ int nstep; /* number of uncoarsening levels between RQIs */ int version; /* which version of sel. orth. to use */ int nsets = 0; /* number of sets to divide into */ - double * g; /* rhs n-vector in the extended eigenproblem */ - double * ptr; /* loops through yvec */ + double *g; /* rhs n-vector in the extended eigenproblem */ + double *ptr; /* loops through yvec */ double w1, w2; /* desired weights of two sets */ double term_tot; /* sum of terminal weights */ double sigma; /* norm constraint on extended eigenvector */ @@ -74,9 +74,9 @@ void eigensolve(struct vtx_data **graph, /* graph data structure */ int autoset_srestol; /* set SRESTOL automatically? */ double prev_srestol = 0; /* SRESTOL value above this routine */ - double seconds(); + double seconds(void); void coarsen(), lanczos_FO(), lanczos_SO(), vecout(), vecnorm(); - void lanczos_SO_float(), strout(); + void lanczos_SO_float(), strout(char *msg); void perturb_init(), perturb_clear(), x2y(), y2x(); int lanczos_ext(), lanczos_ext_float(); diff --git a/packages/seacas/libraries/chaco/eigen/get_extval.c b/packages/seacas/libraries/chaco/eigen/get_extval.c index 0861724c68ee..a79f22d6d669 100644 --- a/packages/seacas/libraries/chaco/eigen/get_extval.c +++ b/packages/seacas/libraries/chaco/eigen/get_extval.c @@ -34,8 +34,8 @@ void get_extval(double *alpha, /* j-vector of Lanczos scalars (using elements double lambda; /* the parameter that iterates to extval */ int cnt; /* debug iteration counter */ double diff; /* distance between lambda limits */ - double ch_norm(), Tevec(); - void tri_solve(), cpvec(); + double ch_norm(double *vec, int beg, int end), Tevec(double *, double *, int, double, double *); + void tri_solve(), cpvec(); /* Compute the Ritz vector */ Tevec(alpha, beta - 1, j, ritzval, s); diff --git a/packages/seacas/libraries/chaco/eigen/get_ritzvals.c b/packages/seacas/libraries/chaco/eigen/get_ritzvals.c index 3ccbba83900b..4b812d89acbe 100644 --- a/packages/seacas/libraries/chaco/eigen/get_ritzvals.c +++ b/packages/seacas/libraries/chaco/eigen/get_ritzvals.c @@ -29,25 +29,25 @@ int get_ritzvals(double *alpha, /* vector of Lanczos scalars */ double bis_safety /* bisection tolerance function divisor */ ) { - extern int DEBUG_EVECS; /* debug flag for eigen computation */ - extern int WARNING_EVECS; /* warning flag for eigen computation */ - int nvals_left; /* numb. evals to find on left end of spectrum */ - int nvals_right; /* numb. evals to find on right end of spectrum */ - double bisection_tol; /* width of interval bisection should converge to */ - int pred_steps; /* predicts # of required bisection steps per eval */ - int tot_pred_steps; /* predicts total # of required bisection steps */ - double * ritz_sav = NULL; /* copy of ritzvals for debugging */ - int bisect_flag; /* return status of bisect() */ - int ql_flag; /* return status of ql() */ - int local_debug; /* whether to check bisection results with ql */ - int bisect(); /* locates eigvals using bisection on Sturm seq. */ - int ql(); /* computes eigenvalues of T using eispack algorithm */ - void shell_sort(); /* sorts vector of eigenvalues */ - double * mkvec(); /* to allocate a vector */ - void frvec(); /* free vector */ - void cpvec(); /* vector copy */ - void bail(); /* our exit routine */ - void strout(); /* string out to screen and output file */ + extern int DEBUG_EVECS; /* debug flag for eigen computation */ + extern int WARNING_EVECS; /* warning flag for eigen computation */ + int nvals_left; /* numb. evals to find on left end of spectrum */ + int nvals_right; /* numb. evals to find on right end of spectrum */ + double bisection_tol; /* width of interval bisection should converge to */ + int pred_steps; /* predicts # of required bisection steps per eval */ + int tot_pred_steps; /* predicts total # of required bisection steps */ + double *ritz_sav = NULL; /* copy of ritzvals for debugging */ + int bisect_flag; /* return status of bisect() */ + int ql_flag; /* return status of ql() */ + int local_debug; /* whether to check bisection results with ql */ + int bisect(); /* locates eigvals using bisection on Sturm seq. */ + int ql(); /* computes eigenvalues of T using eispack algorithm */ + void shell_sort(); /* sorts vector of eigenvalues */ + double *mkvec(int nl, int nh); /* to allocate a vector */ + void frvec(double *v, int nl); /* free vector */ + void cpvec(); /* vector copy */ + void bail(); /* our exit routine */ + void strout(char *msg); /* string out to screen and output file */ /* Determine number of ritzvals to find on left and right ends */ nvals_left = max(d, left_goodlim); diff --git a/packages/seacas/libraries/chaco/eigen/lanc_seconds.c b/packages/seacas/libraries/chaco/eigen/lanc_seconds.c index d7d9c9fa0e1f..582c237ccda7 100644 --- a/packages/seacas/libraries/chaco/eigen/lanc_seconds.c +++ b/packages/seacas/libraries/chaco/eigen/lanc_seconds.c @@ -10,7 +10,7 @@ double lanc_seconds(void) { extern int LANCZOS_TIME; /* perform detailed timing on Lanczos_SO? */ - double seconds(); + double seconds(void); if (LANCZOS_TIME) { return (seconds()); diff --git a/packages/seacas/libraries/chaco/eigen/lanczos_FO.c b/packages/seacas/libraries/chaco/eigen/lanczos_FO.c index 3525c0ec5084..f936d087e4e8 100644 --- a/packages/seacas/libraries/chaco/eigen/lanczos_FO.c +++ b/packages/seacas/libraries/chaco/eigen/lanczos_FO.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -66,17 +66,17 @@ void lanczos_FO(struct vtx_data **A, /* graph data structure */ int n, /* number of rows/columns in matrix */ int d, /* problem dimension = # evecs to find */ - double ** y, /* columns of y are eigenvectors of A */ - double * lambda, /* ritz approximation to eigenvals of A */ - double * bound, /* on ritz pair approximations to eig pairs of A */ + double **y, /* columns of y are eigenvectors of A */ + double *lambda, /* ritz approximation to eigenvals of A */ + double *bound, /* on ritz pair approximations to eig pairs of A */ double eigtol, /* tolerance on eigenvectors */ - double * vwsqrt, /* square root of vertex weights */ + double *vwsqrt, /* square root of vertex weights */ double maxdeg, /* maximum degree of graph */ int version /* 1 = standard mode, 2 = inverse operator mode */ ) { - extern FILE * Output_File; /* output file or NULL */ + extern FILE *Output_File; /* output file or NULL */ extern int DEBUG_EVECS; /* print debugging output? */ extern int DEBUG_TRACE; /* trace main execution path */ extern int WARNING_EVECS; /* print warning messages? */ @@ -95,28 +95,28 @@ void lanczos_FO(struct vtx_data **A, /* graph data structure */ extern double debug_time; /* time for debug computations and output */ int i, j; /* indices */ int maxj; /* maximum number of Lanczos iterations */ - double * u, *r; /* Lanczos vectors */ - double * Aq; /* sparse matrix-vector product vector */ - double * alpha, *beta; /* the Lanczos scalars from each step */ - double * ritz; /* copy of alpha for tqli */ - double * workj; /* work vector (eg. for tqli) */ - double * workn; /* work vector (eg. for checkeig) */ - double * s; /* eigenvector of T */ - double ** q; /* columns of q = Lanczos basis vectors */ - double * bj; /* beta(j)*(last element of evecs of T) */ + double *u, *r; /* Lanczos vectors */ + double *Aq; /* sparse matrix-vector product vector */ + double *alpha, *beta; /* the Lanczos scalars from each step */ + double *ritz; /* copy of alpha for tqli */ + double *workj; /* work vector (eg. for tqli) */ + double *workn; /* work vector (eg. for checkeig) */ + double *s; /* eigenvector of T */ + double **q; /* columns of q = Lanczos basis vectors */ + double *bj; /* beta(j)*(last element of evecs of T) */ double bis_safety; /* real safety factor for bisection algorithm */ double Sres; /* how well Tevec calculated eigvecs */ double Sres_max; /* Maximum value of Sres */ int inc_bis_safety; /* need to increase bisection safety */ - double * Ares; /* how well Lanczos calculated each eigpair */ - double * inv_lambda; /* eigenvalues of inverse operator */ - int * index; /* the Ritz index of an eigenpair */ + double *Ares; /* how well Lanczos calculated each eigpair */ + double *inv_lambda; /* eigenvalues of inverse operator */ + int *index; /* the Ritz index of an eigenpair */ struct orthlink *orthlist = NULL; /* vectors to orthogonalize against in Lanczos */ struct orthlink *orthlist2 = NULL; /* vectors to orthogonalize against in Symmlq */ struct orthlink *temp; /* for expanding orthogonalization list */ - double * ritzvec = NULL; /* ritz vector for current iteration */ - double * zeros = NULL; /* vector of all zeros */ - double * ones = NULL; /* vector of all ones */ + double *ritzvec = NULL; /* ritz vector for current iteration */ + double *zeros = NULL; /* vector of all zeros */ + double *ones = NULL; /* vector of all ones */ struct scanlink *scanlist; /* list of fields for min ritz vals */ struct scanlink *curlnk; /* for traversing the scanlist */ double bji_tol; /* tol on bji estimate of A e-residual */ @@ -132,26 +132,28 @@ void lanczos_FO(struct vtx_data **A, /* graph data structure */ double normxlim; /* a stopping criteria for symmlq */ long itnmin; /* enforce minimum number of iterations */ int symmlqitns = 0; /* # symmlq itns */ - double * wv1 = NULL, *wv2 = NULL, *wv3 = NULL; /* Symmlq work space */ - double * wv4 = NULL, *wv5 = NULL, *wv6 = NULL; /* Symmlq work space */ + double *wv1 = NULL, *wv2 = NULL, *wv3 = NULL; /* Symmlq work space */ + double *wv4 = NULL, *wv5 = NULL, *wv6 = NULL; /* Symmlq work space */ long long_n; /* long int copy of n for symmlq */ int ritzval_flag = 0; /* status flag for ql() */ double Anorm; /* Norm estimate of the Laplacian matrix */ int left, right; /* ranges on the search for ritzvals */ int memory_ok; /* TRUE as long as don't run out of memory */ - double * mkvec(); /* allocates space for a vector */ - double * mkvec_ret(); /* mkvec() which returns error code */ - double dot(); /* standard dot product routine */ - struct orthlink *makeorthlnk(); /* make space for entry in orthog. set */ - double ch_norm(); /* vector norm */ - double Tevec(); /* calc evec of T by linear recurrence */ - struct scanlink *mkscanlist(); /* make scan list for min ritz vecs */ - double lanc_seconds(); /* current clock timer */ + double *mkvec(int nl, int nh); /* allocates space for a vector */ + double *mkvec_ret(int nl, int nh); /* mkvec(int nl, int nh) which returns error code */ + double dot(double *vec1, int beg, int end, double *vec2); /* standard dot product routine */ + struct orthlink *makeorthlnk(); /* make space for entry in orthog. set */ + double ch_norm(double *vec, int beg, int end); /* vector norm */ + double Tevec(double *, double *, int, double, double *); /* calc evec of T by linear recurrence */ + struct scanlink *mkscanlist(); /* make scan list for min ritz vecs */ + double lanc_seconds(void); /* current clock timer */ int symmlq(), get_ritzvals(); - void setvec(), vecscale(), update(), vecran(), strout(); - void splarax(), scanmin(), scanmax(), frvec(), orthogonalize(); - void orthog1(), orthogvec(), bail(), warnings(), mkeigvecs(); + void setvec(), vecscale(), + update(double *vec1, int beg, int end, double *vec2, double fac, double *vec3), vecran(), + strout(char *msg); + void splarax(), scanmin(), scanmax(), frvec(double *v, int nl), orthogonalize(); + void orthog1(), orthogvec(), bail(), warnings(), mkeigvecs(); if (DEBUG_TRACE > 0) { printf("\n"); diff --git a/packages/seacas/libraries/chaco/eigen/lanczos_SO.c b/packages/seacas/libraries/chaco/eigen/lanczos_SO.c index aacdac956638..ee41e1d80313 100644 --- a/packages/seacas/libraries/chaco/eigen/lanczos_SO.c +++ b/packages/seacas/libraries/chaco/eigen/lanczos_SO.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -92,23 +92,23 @@ void lanczos_SO(struct vtx_data **A, /* sparse matrix in row linked list format */ int n, /* problem size */ int d, /* problem dimension = number of eigvecs to find */ - double ** y, /* columns of y are eigenvectors of A */ - double * lambda, /* ritz approximation to eigenvals of A */ - double * bound, /* on ritz pair approximations to eig pairs of A */ + double **y, /* columns of y are eigenvectors of A */ + double *lambda, /* ritz approximation to eigenvals of A */ + double *bound, /* on ritz pair approximations to eig pairs of A */ double eigtol, /* tolerance on eigenvectors */ - double * vwsqrt, /* square roots of vertex weights */ + double *vwsqrt, /* square roots of vertex weights */ double maxdeg, /* maximum degree of graph */ int version, /* flags which version of sel. orth. to use */ int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */ int nsets, /* number of sets to divide into */ - int * assignment, /* set number of each vtx (length n+1) */ - int * active, /* space for nvtxs integers */ + int *assignment, /* set number of each vtx (length n+1) */ + int *active, /* space for nvtxs integers */ int mediantype, /* which partitioning strategy to use */ - double * goal, /* desired set sizes */ + double *goal, /* desired set sizes */ int vwgt_max /* largest vertex weight */ ) { - extern FILE * Output_File; /* output file or null */ + extern FILE *Output_File; /* output file or null */ extern int LANCZOS_SO_INTERVAL; /* interval between orthogonalizations */ extern int LANCZOS_CONVERGENCE_MODE; /* type of Lanczos convergence test */ extern int LANCZOS_MAXITNS; /* maximum Lanczos iterations allowed */ @@ -132,22 +132,22 @@ void lanczos_SO(struct vtx_data **A, /* sparse matrix in row linked l double bis_safety; /* real safety factor for bisection alg. */ int i, j, k; /* indices */ int maxj; /* maximum number of Lanczos iterations */ - double * u, *r; /* Lanczos vectors */ - double * alpha, *beta; /* the Lanczos scalars from each step */ - double * ritz; /* copy of alpha for ql */ - double * workj; /* work vector, e.g. copy of beta for ql */ - double * workn; /* work vector, e.g. product Av for checkeig */ - double * s; /* eigenvector of T */ - double ** q; /* columns of q are Lanczos basis vectors */ - double * bj; /* beta(j)*(last el. of corr. eigvec s of T) */ + double *u, *r; /* Lanczos vectors */ + double *alpha, *beta; /* the Lanczos scalars from each step */ + double *ritz; /* copy of alpha for ql */ + double *workj; /* work vector, e.g. copy of beta for ql */ + double *workn; /* work vector, e.g. product Av for checkeig */ + double *s; /* eigenvector of T */ + double **q; /* columns of q are Lanczos basis vectors */ + double *bj; /* beta(j)*(last el. of corr. eigvec s of T) */ double Sres; /* how well Tevec calculated eigvec s */ double Sres_max; /* Max value of Sres */ int inc_bis_safety; /* need to increase bisection safety */ - double * Ares; /* how well Lanczos calc. eigpair lambda,y */ - int * index; /* the Ritz index of an eigenpair */ + double *Ares; /* how well Lanczos calc. eigpair lambda,y */ + int *index; /* the Ritz index of an eigenpair */ struct orthlink **solist; /* vec. of structs with vecs. to orthog. against */ - struct scanlink * scanlist; /* linked list of fields to do with min ritz vals */ - struct scanlink * curlnk; /* for traversing the scanlist */ + struct scanlink *scanlist; /* linked list of fields to do with min ritz vals */ + struct scanlink *curlnk; /* for traversing the scanlist */ double bji_tol; /* tol on bji est. of eigen residual of A */ int converged; /* has the iteration converged? */ double goodtol; /* error tolerance for a good Ritz vector */ @@ -166,44 +166,46 @@ void lanczos_SO(struct vtx_data **A, /* sparse matrix in row linked l int pausemode; /* which Lanczos pausing criterion to use */ int pause; /* whether to pause */ int temp; /* used to prevent redundant index computations */ - int * old_assignment = NULL; /* set # of each vtx on previous pause, length n+1 */ - int * assgn_pntr; /* pntr to assignment vector */ - int * old_assgn_pntr; /* pntr to previous assignment vector */ + int *old_assignment = NULL; /* set # of each vtx on previous pause, length n+1 */ + int *assgn_pntr; /* pntr to assignment vector */ + int *old_assgn_pntr; /* pntr to previous assignment vector */ int assigndiff; /* # of differences between old and new assignment */ int assigntol; /* tolerance on convergence of assignment vector */ int ritzval_flag; /* status flag for get_ritzvals() */ int memory_ok; /* True until lanczos runs out of memory */ - struct orthlink *makeorthlnk(); /* makes space for new entry in orthog. set */ - struct scanlink *mkscanlist(); /* makes initial scan list for min ritz vecs */ - double * mkvec(); /* allocates space for a vector, dies if problem */ - double * mkvec_ret(); /* allocates space for a vector, returns error code */ - double dot(); /* standard dot product routine */ - double ch_norm(); /* vector norm */ - double Tevec(); /* calc eigenvector of T by linear recurrence */ - double checkeig(); /* calculate residual of eigenvector of A */ - double lanc_seconds(); /* switcheable timer */ - /* free allocated memory safely */ - int lanpause(); /* figure when to pause Lanczos iteration */ - int get_ritzvals(); /* compute eigenvalues of T */ - void assign(); /* generate a set assignment from eigenvectors */ - void setvec(); /* initialize a vector */ - void vecscale(); /* scale a vector */ - void splarax(); /* matrix vector multiply */ - void update(); /* add a scalar multiple of a vector to another */ - void sorthog(); /* orthogonalize a vector against a list of others */ - void bail(); /* our exit routine */ - void scanmin(); /* find small values in vector, store in linked list */ - void frvec(); /* free vector */ - void scadd(); /* add scalar multiple of vector to another */ - void orthog1(); /* efficiently orthogonalize against vector of ones */ - void vecran(); /* fill vector with random entries */ - void solistout(); /* print out orthogonalization list */ - void doubleout(); /* print a double precision number */ - void orthogvec(); /* orthogonalize one vector against another */ - void warnings(); /* post various warnings about computation */ - void mkeigvecs(); /* assemble eigenvectors */ - void strout(); /* print string to screen and output file */ + struct orthlink *makeorthlnk(); /* makes space for new entry in orthog. set */ + struct scanlink *mkscanlist(); /* makes initial scan list for min ritz vecs */ + double *mkvec(int nl, int nh); /* allocates space for a vector, dies if problem */ + double *mkvec_ret(int nl, int nh); /* allocates space for a vector, returns error code */ + double dot(double *vec1, int beg, int end, double *vec2); /* standard dot product routine */ + double ch_norm(double *vec, int beg, int end); /* vector norm */ + double Tevec(double *, double *, int, double, + double *); /* calc eigenvector of T by linear recurrence */ + double checkeig(); /* calculate residual of eigenvector of A */ + double lanc_seconds(void); /* switcheable timer */ + /* free allocated memory safely */ + int lanpause(); /* figure when to pause Lanczos iteration */ + int get_ritzvals(); /* compute eigenvalues of T */ + void assign(); /* generate a set assignment from eigenvectors */ + void setvec(); /* initialize a vector */ + void vecscale(); /* scale a vector */ + void splarax(); /* matrix vector multiply */ + void update(double *vec1, int beg, int end, double *vec2, double fac, + double *vec3); /* add a scalar multiple of a vector to another */ + void sorthog(); /* orthogonalize a vector against a list of others */ + void bail(); /* our exit routine */ + void scanmin(); /* find small values in vector, store in linked list */ + void frvec(double *v, int nl); /* free vector */ + void scadd(); /* add scalar multiple of vector to another */ + void orthog1(); /* efficiently orthogonalize against vector of ones */ + void vecran(); /* fill vector with random entries */ + void solistout(); /* print out orthogonalization list */ + void doubleout(); /* print a double precision number */ + void orthogvec(); /* orthogonalize one vector against another */ + void warnings(); /* post various warnings about computation */ + void mkeigvecs(); /* assemble eigenvectors */ + void strout(char *msg); /* print string to screen and output file */ if (DEBUG_TRACE > 0) { printf("\n"); diff --git a/packages/seacas/libraries/chaco/eigen/lanczos_SO_float.c b/packages/seacas/libraries/chaco/eigen/lanczos_SO_float.c index dd943e9e3e0e..145bc6b33aa1 100644 --- a/packages/seacas/libraries/chaco/eigen/lanczos_SO_float.c +++ b/packages/seacas/libraries/chaco/eigen/lanczos_SO_float.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -17,23 +17,23 @@ void lanczos_SO_float(struct vtx_data **A, /* sparse matrix in row linked list format */ int n, /* problem size */ int d, /* problem dimension = number of eigvecs to find */ - double ** y, /* columns of y are eigenvectors of A */ - double * lambda, /* ritz approximation to eigenvals of A */ - double * bound, /* on ritz pair approximations to eig pairs of A */ + double **y, /* columns of y are eigenvectors of A */ + double *lambda, /* ritz approximation to eigenvals of A */ + double *bound, /* on ritz pair approximations to eig pairs of A */ double eigtol, /* tolerance on eigenvectors */ - double * vwsqrt, /* square roots of vertex weights */ + double *vwsqrt, /* square roots of vertex weights */ double maxdeg, /* maximum degree of graph */ int version, /* flags which version of sel. orth. to use */ int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */ int nsets, /* number of sets to divide into */ - int * assignment, /* set number of each vtx (length n+1) */ - int * active, /* space for nvtxs integers */ + int *assignment, /* set number of each vtx (length n+1) */ + int *active, /* space for nvtxs integers */ int mediantype, /* which partitioning strategy to use */ - double * goal, /* desired set sizes */ + double *goal, /* desired set sizes */ int vwgt_max /* largest vertex weight */ ) { - extern FILE * Output_File; /* output file or null */ + extern FILE *Output_File; /* output file or null */ extern int LANCZOS_SO_INTERVAL; /* interval between orthogonalizations */ extern int LANCZOS_CONVERGENCE_MODE; /* type of Lanczos convergence test */ extern int LANCZOS_MAXITNS; /* maximum Lanczos iterations allowed */ @@ -57,24 +57,24 @@ void lanczos_SO_float(struct vtx_data **A, /* sparse matrix in row linked double bis_safety; /* real safety factor for T bisection */ int i, j, k; /* indices */ int maxj; /* maximum number of Lanczos iterations */ - float * u, *r; /* Lanczos vectors */ - double * u_double; /* double version of u */ - double * alpha, *beta; /* the Lanczos scalars from each step */ - double * ritz; /* copy of alpha for ql */ - double * workj; /* work vector, e.g. copy of beta for ql */ - float * workn; /* work vector, e.g. product Av for checkeig */ - double * workn_double; /* work vector, e.g. product Av for checkeig */ - double * s; /* eigenvector of T */ - float ** q; /* columns of q are Lanczos basis vectors */ - double * bj; /* beta(j)*(last el. of corr. eigvec s of T) */ + float *u, *r; /* Lanczos vectors */ + double *u_double; /* double version of u */ + double *alpha, *beta; /* the Lanczos scalars from each step */ + double *ritz; /* copy of alpha for ql */ + double *workj; /* work vector, e.g. copy of beta for ql */ + float *workn; /* work vector, e.g. product Av for checkeig */ + double *workn_double; /* work vector, e.g. product Av for checkeig */ + double *s; /* eigenvector of T */ + float **q; /* columns of q are Lanczos basis vectors */ + double *bj; /* beta(j)*(last el. of corr. eigvec s of T) */ double Sres; /* how well Tevec calculated eigvec s */ double Sres_max; /* Max value of Sres */ int inc_bis_safety; /* need to increase bisection safety */ - double * Ares; /* how well Lanczos calc. eigpair lambda,y */ - int * index; /* the Ritz index of an eigenpair */ + double *Ares; /* how well Lanczos calc. eigpair lambda,y */ + int *index; /* the Ritz index of an eigenpair */ struct orthlink_float **solist; /* vec. of structs with vecs. to orthog. against */ - struct scanlink * scanlist; /* linked list of fields to do with min ritz vals */ - struct scanlink * curlnk; /* for traversing the scanlist */ + struct scanlink *scanlist; /* linked list of fields to do with min ritz vals */ + struct scanlink *curlnk; /* for traversing the scanlist */ double bji_tol; /* tol on bji est. of eigen residual of A */ int converged; /* has the iteration converged? */ double goodtol; /* error tolerance for a good Ritz vector */ @@ -93,50 +93,52 @@ void lanczos_SO_float(struct vtx_data **A, /* sparse matrix in row linked int pausemode; /* which Lanczos pausing criterion to use */ int pause; /* whether to pause */ int temp; /* used to prevent redundant index computations */ - int * old_assignment = NULL; /* set # of each vtx on previous pause, length n+1 */ - int * assgn_pntr; /* pntr to assignment vector */ - int * old_assgn_pntr; /* pntr to previous assignment vector */ + int *old_assignment = NULL; /* set # of each vtx on previous pause, length n+1 */ + int *assgn_pntr; /* pntr to assignment vector */ + int *old_assgn_pntr; /* pntr to previous assignment vector */ int assigndiff; /* # of differences between old and new assignment */ int assigntol; /* tolerance on convergence of assignment vector */ int ritzval_flag; /* status flag for get_ritzvals() */ int memory_ok; /* True until lanczos runs out of memory */ float *vwsqrt_float; /* float version of vwsqrt */ - struct orthlink_float *makeorthlnk_float(); /* makes space for new entry in orthog. set */ - struct scanlink * mkscanlist(); /* makes initial scan list for min ritz vecs */ - double * mkvec(); /* allocates space for a vector, dies if problem */ - float * mkvec_float(); /* allocates space for a vector, dies if problem */ - float * mkvec_ret_float(); /* allocates space for a vector, returns error code */ - double dot_float(); /* standard dot product routine */ - double norm_float(); /* vector norm */ - double Tevec(); /* calc eigenvector of T by linear recurrence */ - double checkeig(); /* calculate residual of eigenvector of A */ - double lanc_seconds(); /* switcheable timer */ - /* free allocated memory safely */ - int lanpause_float(); /* figure when to pause Lanczos iteration */ - int get_ritzvals(); /* compute eigenvalues of T */ - void assign(); /* generate a set assignment from eigenvectors */ - void setvec(); /* initialize a vector */ - void setvec_float(); /* initialize a vector */ - void vecscale_float(); /* scale a vector */ - void splarax_float(); /* matrix vector multiply */ - void update_float(); /* add a scalar multiple of a vector to another */ - void sorthog_float(); /* orthogonalize a vector against a list of others */ - void bail(); /* our exit routine */ - void scanmin(); /* find small values in vector, store in linked list */ - void frvec(); /* free vector */ - void frvec_float(); /* free vector */ - void scadd_float(); /* add scalar multiple of vector to another */ - void scadd_mixed(); /* add scalar multiple of vector to another */ - void orthog1_float(); /* efficiently orthogonalize against vector of ones */ - void vecran_float(); /* fill vector with random entries */ - void solistout_float(); /* print out orthogonalization list */ - void doubleout(); /* print a double precision number */ - void orthogvec_float(); /* orthogonalize one vector against another */ - void double_to_float(); /* copy a double vector to a float vector */ - void float_to_double(); /* convert float to double vector */ - void warnings(); /* post various warnings about computation */ - void strout(); /* print string to screen and output file */ + struct orthlink_float *makeorthlnk_float(); /* makes space for new entry in orthog. set */ + struct scanlink *mkscanlist(); /* makes initial scan list for min ritz vecs */ + double *mkvec(int nl, int nh); /* allocates space for a vector, dies if problem */ + float *mkvec_float(int nl, int nh); /* allocates space for a vector, dies if problem */ + float *mkvec_ret_float(int nl, int nh); /* allocates space for a vector, returns error code */ + double dot_float(float *vec1, int beg, int end, float *vec2); /* standard dot product routine */ + double norm_float(); /* vector norm */ + double Tevec(double *, double *, int, double, + double *); /* calc eigenvector of T by linear recurrence */ + double checkeig(); /* calculate residual of eigenvector of A */ + double lanc_seconds(void); /* switcheable timer */ + /* free allocated memory safely */ + int lanpause_float(); /* figure when to pause Lanczos iteration */ + int get_ritzvals(); /* compute eigenvalues of T */ + void assign(); /* generate a set assignment from eigenvectors */ + void setvec(); /* initialize a vector */ + void setvec_float(); /* initialize a vector */ + void vecscale_float(); /* scale a vector */ + void splarax_float(); /* matrix vector multiply */ + void update_float(float *vec1, int beg, int end, float *vec2, float fac, + float *vec3); /* add a scalar multiple of a vector to another */ + void sorthog_float(); /* orthogonalize a vector against a list of others */ + void bail(); /* our exit routine */ + void scanmin(); /* find small values in vector, store in linked list */ + void frvec(double *v, int nl); /* free vector */ + void frvec_float(float *v, int nl); /* free vector */ + void scadd_float(); /* add scalar multiple of vector to another */ + void scadd_mixed(); /* add scalar multiple of vector to another */ + void orthog1_float(); /* efficiently orthogonalize against vector of ones */ + void vecran_float(); /* fill vector with random entries */ + void solistout_float(); /* print out orthogonalization list */ + void doubleout(); /* print a double precision number */ + void orthogvec_float(); /* orthogonalize one vector against another */ + void double_to_float(); /* copy a double vector to a float vector */ + void float_to_double(); /* convert float to double vector */ + void warnings(); /* post various warnings about computation */ + void strout(char *msg); /* print string to screen and output file */ if (DEBUG_TRACE > 0) { printf("\n"); diff --git a/packages/seacas/libraries/chaco/eigen/lanczos_ext.c b/packages/seacas/libraries/chaco/eigen/lanczos_ext.c index b0362d4c71b0..adcce2444335 100644 --- a/packages/seacas/libraries/chaco/eigen/lanczos_ext.c +++ b/packages/seacas/libraries/chaco/eigen/lanczos_ext.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -22,17 +22,17 @@ int lanczos_ext(struct vtx_data **A, /* sparse matrix in row linked list format */ int n, /* problem size */ int d, /* problem dimension = number of eigvecs to find */ - double ** y, /* columns of y are eigenvectors of A */ + double **y, /* columns of y are eigenvectors of A */ double eigtol, /* tolerance on eigenvectors */ - double * vwsqrt, /* square roots of vertex weights */ + double *vwsqrt, /* square roots of vertex weights */ double maxdeg, /* maximum degree of graph */ int version, /* flags which version of sel. orth. to use */ - double * gvec, /* the rhs n-vector in the extended eigen problem */ + double *gvec, /* the rhs n-vector in the extended eigen problem */ double sigma /* specifies the norm constraint on extended eigenvector */ ) { - extern FILE * Output_File; /* output file or null */ + extern FILE *Output_File; /* output file or null */ extern int LANCZOS_SO_INTERVAL; /* interval between orthogonalizations */ extern int LANCZOS_MAXITNS; /* maximum Lanczos iterations allowed */ extern int DEBUG_EVECS; /* print debugging output? */ @@ -54,22 +54,22 @@ int lanczos_ext(struct vtx_data **A, /* sparse matrix in row linked list f extern double pause_time; /* time to compute whether to pause */ int i, j, k; /* indices */ int maxj; /* maximum number of Lanczos iterations */ - double * u, *r; /* Lanczos vectors */ - double * alpha, *beta; /* the Lanczos scalars from each step */ - double * ritz; /* copy of alpha for ql */ - double * workj; /* work vector, e.g. copy of beta for ql */ - double * workn; /* work vector, e.g. product Av for checkeig */ - double * s; /* eigenvector of T */ - double ** q; /* columns of q are Lanczos basis vectors */ - double * bj; /* beta(j)*(last el. of corr. eigvec s of T) */ + double *u, *r; /* Lanczos vectors */ + double *alpha, *beta; /* the Lanczos scalars from each step */ + double *ritz; /* copy of alpha for ql */ + double *workj; /* work vector, e.g. copy of beta for ql */ + double *workn; /* work vector, e.g. product Av for checkeig */ + double *s; /* eigenvector of T */ + double **q; /* columns of q are Lanczos basis vectors */ + double *bj; /* beta(j)*(last el. of corr. eigvec s of T) */ double Sres; /* how well Tevec calculated eigvec s */ double Sres_max; /* Max value of Sres */ int inc_bis_safety; /* has Sres increased? */ - double * Ares; /* how well Lanczos calc. eigpair lambda,y */ - int * index; /* the Ritz index of an eigenpair */ + double *Ares; /* how well Lanczos calc. eigpair lambda,y */ + int *index; /* the Ritz index of an eigenpair */ struct orthlink **solist; /* vec. of structs with vecs. to orthog. against */ - struct scanlink * scanlist; /* linked list of fields to do with min ritz vals */ - struct scanlink * curlnk; /* for traversing the scanlist */ + struct scanlink *scanlist; /* linked list of fields to do with min ritz vals */ + struct scanlink *curlnk; /* for traversing the scanlist */ double bis_safety; /* real safety for T bisection algorithm */ int converged; /* has the iteration converged? */ double goodtol; /* error tolerance for a good Ritz vector */ @@ -85,34 +85,36 @@ int lanczos_ext(struct vtx_data **A, /* sparse matrix in row linked list f int pausemode; /* which Lanczos pausing criterion to use */ int pause; /* whether to pause */ int temp; /* used to prevent redundant index computations */ - double * extvec; /* n-vector solving the extended A eigenproblem */ - double * v; /* j-vector solving the extended T eigenproblem */ + double *extvec; /* n-vector solving the extended A eigenproblem */ + double *v; /* j-vector solving the extended T eigenproblem */ double extval = 0.0; /* computed extended eigenvalue (of both A and T) */ - double * work1, *work2; /* work vectors */ + double *work1, *work2; /* work vectors */ double check; /* to check an orthogonality condition */ double numerical_zero; /* used for zero in presence of round-off */ int ritzval_flag; /* status flag for get_ritzvals() */ int memory_ok; /* TRUE until memory runs out */ - double * mkvec(); /* allocates space for a vector */ - double * mkvec_ret(); /* mkvec() which returns error code */ - double dot(); /* standard dot product routine */ - struct orthlink *makeorthlnk(); /* makes space for new entry in orthog. set */ - double ch_norm(); /* vector norm */ - double Tevec(); /* calc eigenvector of T by linear recurrence */ - struct scanlink *mkscanlist(); /* init scan list for min ritz vecs */ - double lanc_seconds(); /* switcheable timer */ - /* free allocated memory safely */ - int lanpause(); /* figure when to pause Lanczos iteration */ - int get_ritzvals(); /* compute eigenvalues of T */ - void setvec(); /* initialize a vector */ - void vecscale(); /* scale a vector */ - void splarax(); /* matrix vector multiply */ - void update(); /* add scalar multiple of a vector to another */ + double *mkvec(int nl, int nh); /* allocates space for a vector */ + double *mkvec_ret(int nl, int nh); /* mkvec(int nl, int nh) which returns error code */ + double dot(double *vec1, int beg, int end, double *vec2); /* standard dot product routine */ + struct orthlink *makeorthlnk(); /* makes space for new entry in orthog. set */ + double ch_norm(double *vec, int beg, int end); /* vector norm */ + double Tevec(double *, double *, int, double, + double *); /* calc eigenvector of T by linear recurrence */ + struct scanlink *mkscanlist(); /* init scan list for min ritz vecs */ + double lanc_seconds(void); /* switcheable timer */ + /* free allocated memory safely */ + int lanpause(); /* figure when to pause Lanczos iteration */ + int get_ritzvals(); /* compute eigenvalues of T */ + void setvec(); /* initialize a vector */ + void vecscale(); /* scale a vector */ + void splarax(); /* matrix vector multiply */ + void update(double *vec1, int beg, int end, double *vec2, double fac, + double *vec3); /* add scalar multiple of a vector to another */ void sorthog(); /* orthogonalize vector against list of others */ void bail(); /* our exit routine */ void scanmin(); /* store small values of vector in linked list */ - void frvec(); /* free vector */ + void frvec(double *v, int nl); /* free vector */ void scadd(); /* add scalar multiple of vector to another */ void cpvec(); /* copy a vector */ void orthog1(); /* efficiently orthog. against vector of ones */ @@ -121,7 +123,7 @@ int lanczos_ext(struct vtx_data **A, /* sparse matrix in row linked list f void orthogvec(); /* orthogonalize one vector against another */ void get_extval(); /* find extended Ritz values */ void scale_diag(); /* scale vector by diagonal matrix */ - void strout(); /* print string to screen and file */ + void strout(char *msg); /* print string to screen and file */ double checkeig_ext(); /* check extended eigenpair residual directly */ if (DEBUG_TRACE > 0) { diff --git a/packages/seacas/libraries/chaco/eigen/lanczos_ext_float.c b/packages/seacas/libraries/chaco/eigen/lanczos_ext_float.c index 656fd44964c4..1c47581443c8 100644 --- a/packages/seacas/libraries/chaco/eigen/lanczos_ext_float.c +++ b/packages/seacas/libraries/chaco/eigen/lanczos_ext_float.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -17,17 +17,17 @@ int lanczos_ext_float(struct vtx_data **A, /* sparse matrix in row linked list format */ int n, /* problem size */ int d, /* problem dimension = number of eigvecs to find */ - double ** y, /* columns of y are eigenvectors of A */ + double **y, /* columns of y are eigenvectors of A */ double eigtol, /* tolerance on eigenvectors */ - double * vwsqrt, /* square roots of vertex weights */ + double *vwsqrt, /* square roots of vertex weights */ double maxdeg, /* maximum degree of graph */ int version, /* flags which version of sel. orth. to use */ - double * gvec, /* the rhs n-vector in the extended eigen problem */ + double *gvec, /* the rhs n-vector in the extended eigen problem */ double sigma /* specifies the norm constraint on extended eigenvector */ ) { - extern FILE * Output_File; /* output file or null */ + extern FILE *Output_File; /* output file or null */ extern int LANCZOS_SO_INTERVAL; /* interval between orthogonalizations */ extern int LANCZOS_MAXITNS; /* maximum Lanczos iterations allowed */ extern int DEBUG_EVECS; /* print debugging output? */ @@ -49,25 +49,25 @@ int lanczos_ext_float(struct vtx_data **A, /* sparse matrix in row linked extern double pause_time; /* time to compute whether to pause */ int i, j, k; /* indices */ int maxj; /* maximum number of Lanczos iterations */ - float * u, *r; /* Lanczos vectors */ - double * u_double; /* double version of u */ - double * alpha, *beta; /* the Lanczos scalars from each step */ - double * ritz; /* copy of alpha for ql */ - double * workj; /* work vector, e.g. copy of beta for ql */ - float * workn; /* work vector, e.g. product Av for checkeig */ - double * workn_double; /* work vector, e.g. product Av for checkeig */ - double * s; /* eigenvector of T */ - float ** q; /* columns of q are Lanczos basis vectors */ - double * bj; /* beta(j)*(last el. of corr. eigvec s of T) */ + float *u, *r; /* Lanczos vectors */ + double *u_double; /* double version of u */ + double *alpha, *beta; /* the Lanczos scalars from each step */ + double *ritz; /* copy of alpha for ql */ + double *workj; /* work vector, e.g. copy of beta for ql */ + float *workn; /* work vector, e.g. product Av for checkeig */ + double *workn_double; /* work vector, e.g. product Av for checkeig */ + double *s; /* eigenvector of T */ + float **q; /* columns of q are Lanczos basis vectors */ + double *bj; /* beta(j)*(last el. of corr. eigvec s of T) */ double bis_safety; /* real safety factor for T bisection */ double Sres; /* how well Tevec calculated eigvec s */ double Sres_max; /* Max value of Sres */ int inc_bis_safety; /* need to increase bisection safety */ - double * Ares; /* how well Lanczos calc. eigpair lambda,y */ - int * index; /* the Ritz index of an eigenpair */ + double *Ares; /* how well Lanczos calc. eigpair lambda,y */ + int *index; /* the Ritz index of an eigenpair */ struct orthlink_float **solist; /* vec. of structs with vecs. to orthog. against */ - struct scanlink * scanlist; /* linked list of fields to do with min ritz vals */ - struct scanlink * curlnk; /* for traversing the scanlist */ + struct scanlink *scanlist; /* linked list of fields to do with min ritz vals */ + struct scanlink *curlnk; /* for traversing the scanlist */ double bji_tol; /* tol on bji est. of eigen residual of A */ int converged; /* has the iteration converged? */ double goodtol; /* error tolerance for a good Ritz vector */ @@ -83,53 +83,55 @@ int lanczos_ext_float(struct vtx_data **A, /* sparse matrix in row linked int pausemode; /* which Lanczos pausing criterion to use */ int pause; /* whether to pause */ int temp; /* used to prevent redundant index computations */ - double * extvec; /* n-vector solving the extended A eigenproblem */ - double * v; /* j-vector solving the extended T eigenproblem */ + double *extvec; /* n-vector solving the extended A eigenproblem */ + double *v; /* j-vector solving the extended T eigenproblem */ double extval = 0.0; /* computed extended eigenvalue (of both A and T) */ - double * work1, *work2; /* work vectors */ + double *work1, *work2; /* work vectors */ double check; /* to check an orthogonality condition */ double numerical_zero; /* used for zero in presence of round-off */ int ritzval_flag; /* status flag for get_ritzvals() */ double resid; /* residual */ int memory_ok; /* TRUE until memory runs out */ - float * vwsqrt_float = NULL; /* float version of vwsqrt */ - - struct orthlink_float *makeorthlnk_float(); /* makes space for new entry in orthog. set */ - struct scanlink * mkscanlist(); /* init scan list for min ritz vecs */ - double * mkvec(); /* allocates space for a vector */ - float * mkvec_float(); /* allocates space for a vector */ - float * mkvec_ret_float(); /* mkvec() which returns error code */ - double dot_float(); /* standard dot product routine */ - double ch_norm(); /* vector norm */ - double norm_float(); /* vector norm */ - double Tevec(); /* calc eigenvector of T by linear recurrence */ - double lanc_seconds(); /* switcheable timer */ - /* free allocated memory safely */ - int lanpause_float(); /* figure when to pause Lanczos iteration */ - int get_ritzvals(); /* compute eigenvalues of T */ - void setvec(); /* initialize a vector */ - void setvec_float(); /* initialize a vector */ - void vecscale_float(); /* scale a vector */ - void splarax(); /* matrix vector multiply */ - void splarax_float(); /* matrix vector multiply */ - void update_float(); /* add scalar multiple of a vector to another */ - void sorthog_float(); /* orthogonalize vector against list of others */ - void bail(); /* our exit routine */ - void scanmin(); /* store small values of vector in linked list */ - void frvec(); /* free vector */ - void frvec_float(); /* free vector */ - void scadd(); /* add scalar multiple of vector to another */ - void scadd_float(); /* add scalar multiple of vector to another */ - void scadd_mixed(); /* add scalar multiple of vector to another */ - void orthog1_float(); /* efficiently orthog. against vector of ones */ - void solistout_float(); /* print out orthogonalization list */ - void doubleout(); /* print a double precision number */ - void orthogvec_float(); /* orthogonalize one vector against another */ - void double_to_float(); /* copy a double vector to a float vector */ - void get_extval(); /* find extended Ritz values */ - void scale_diag(); /* scale vector by diagonal matrix */ - void scale_diag_float(); /* scale vector by diagonal matrix */ - void strout(); /* print string to screen and file */ + float *vwsqrt_float = NULL; /* float version of vwsqrt */ + + struct orthlink_float *makeorthlnk_float(); /* makes space for new entry in orthog. set */ + struct scanlink *mkscanlist(); /* init scan list for min ritz vecs */ + double *mkvec(int nl, int nh); /* allocates space for a vector */ + float *mkvec_float(int nl, int nh); /* allocates space for a vector */ + float *mkvec_ret_float(int nl, int nh); /* mkvec(int nl, int nh) which returns error code */ + double dot_float(float *vec1, int beg, int end, float *vec2); /* standard dot product routine */ + double ch_norm(double *vec, int beg, int end); /* vector norm */ + double norm_float(); /* vector norm */ + double Tevec(double *, double *, int, double, + double *); /* calc eigenvector of T by linear recurrence */ + double lanc_seconds(void); /* switcheable timer */ + /* free allocated memory safely */ + int lanpause_float(); /* figure when to pause Lanczos iteration */ + int get_ritzvals(); /* compute eigenvalues of T */ + void setvec(); /* initialize a vector */ + void setvec_float(); /* initialize a vector */ + void vecscale_float(); /* scale a vector */ + void splarax(); /* matrix vector multiply */ + void splarax_float(); /* matrix vector multiply */ + void update_float(float *vec1, int beg, int end, float *vec2, float fac, + float *vec3); /* add scalar multiple of a vector to another */ + void sorthog_float(); /* orthogonalize vector against list of others */ + void bail(); /* our exit routine */ + void scanmin(); /* store small values of vector in linked list */ + void frvec(double *v, int nl); /* free vector */ + void frvec_float(float *v, int nl); /* free vector */ + void scadd(); /* add scalar multiple of vector to another */ + void scadd_float(); /* add scalar multiple of vector to another */ + void scadd_mixed(); /* add scalar multiple of vector to another */ + void orthog1_float(); /* efficiently orthog. against vector of ones */ + void solistout_float(); /* print out orthogonalization list */ + void doubleout(); /* print a double precision number */ + void orthogvec_float(); /* orthogonalize one vector against another */ + void double_to_float(); /* copy a double vector to a float vector */ + void get_extval(); /* find extended Ritz values */ + void scale_diag(); /* scale vector by diagonal matrix */ + void scale_diag_float(); /* scale vector by diagonal matrix */ + void strout(char *msg); /* print string to screen and file */ if (DEBUG_TRACE > 0) { printf("\n"); diff --git a/packages/seacas/libraries/chaco/eigen/lanpause.c b/packages/seacas/libraries/chaco/eigen/lanpause.c index 9ab1818e79f8..540a7824417c 100644 --- a/packages/seacas/libraries/chaco/eigen/lanpause.c +++ b/packages/seacas/libraries/chaco/eigen/lanpause.c @@ -16,7 +16,7 @@ int lanpause(int j, /* current step */ int interval, /* interval between pauses */ double **q, /* the Lanczos vectors */ int n, /* length of Lanczos vectors */ - int * pausemode, /* which pausing criterion to use */ + int *pausemode, /* which pausing criterion to use */ int version, /* which version of sel. orth. we are using */ double beta /* current off-diagonal value */ ) @@ -25,7 +25,7 @@ int lanpause(int j, /* current step */ extern double DOUBLE_EPSILON; /* machine precision */ double paige_dot; /* q[j]^T q[1] */ double paigetol; /* pause if paigedot > paigetol */ - double dot(); /* standard dot product */ + double dot(double *vec1, int beg, int end, double *vec2); /* standard dot product */ void checkorth(); /* Check orthogonality of last Lanczos vector against previous ones */ @@ -76,7 +76,7 @@ int lanpause_float(int j, /* current step */ int interval, /* interval between pauses */ float **q, /* the Lanczos vectors */ int n, /* length of Lanczos vectors */ - int * pausemode, /* which pausing criterion to use */ + int *pausemode, /* which pausing criterion to use */ int version, /* which version of sel. orth. we are using */ double beta /* current off-diagonal value */ ) @@ -85,7 +85,7 @@ int lanpause_float(int j, /* current step */ extern double DOUBLE_EPSILON; /* machine precision */ double paige_dot; /* q[j]^T q[1] */ double paigetol; /* pause if paigedot > paigetol */ - double dot_float(); /* standard dot product */ + double dot_float(float *vec1, int beg, int end, float *vec2); /* standard dot product */ void checkorth_float(); /* Check orthogonality of last Lanczos vector against previous ones */ diff --git a/packages/seacas/libraries/chaco/eigen/mkeigvecs.c b/packages/seacas/libraries/chaco/eigen/mkeigvecs.c index 01e2571e1127..b14494ba55fb 100644 --- a/packages/seacas/libraries/chaco/eigen/mkeigvecs.c +++ b/packages/seacas/libraries/chaco/eigen/mkeigvecs.c @@ -11,19 +11,19 @@ /* Assemble eigenvectors, return bounds, etc. */ void mkeigvecs(struct scanlink *scanlist, /* linked list of fields to do with min ritz vals */ - double * lambda, /* ritz approximation to eigenvals of A */ - double * bound, /* on ritz pair approximations to eig pairs of A */ - int * index, /* the Ritz index of an eigenpair */ - double * bj, /* beta(j)*(last el. of corr. eigvec s of T) */ + double *lambda, /* ritz approximation to eigenvals of A */ + double *bound, /* on ritz pair approximations to eig pairs of A */ + int *index, /* the Ritz index of an eigenpair */ + double *bj, /* beta(j)*(last el. of corr. eigvec s of T) */ int d, /* problem dimension = number of eigvecs to find */ - double * Sres_max, /* Max value of Sres */ - double * alpha, /* vector of Lanczos scalars */ - double * beta, /* vector of Lanczos scalars */ + double *Sres_max, /* Max value of Sres */ + double *alpha, /* vector of Lanczos scalars */ + double *beta, /* vector of Lanczos scalars */ int j, /* number of Lanczos iterations taken */ - double * s, /* approximate eigenvector of T */ - double ** y, /* columns of y are eigenvectors of A */ + double *s, /* approximate eigenvector of T */ + double **y, /* columns of y are eigenvectors of A */ int n, /* problem size */ - double ** q /* columns of q are Lanczos basis vectors */ + double **q /* columns of q are Lanczos basis vectors */ ) { @@ -32,7 +32,8 @@ void mkeigvecs(struct scanlink *scanlist, /* linked list of fields to do with mi struct scanlink *curlnk; /* for traversing the scanlist */ void setvec(); /* initialize a vector */ void scadd(); /* add scalar multiple of vector to another */ - double Tevec(); /* calc eigenvector of T by linear recurrence */ + double Tevec(double *, double *, int, double, + double *); /* calc eigenvector of T by linear recurrence */ /* Scan for some data which is used here or later */ i = d; diff --git a/packages/seacas/libraries/chaco/eigen/orthogvec.c b/packages/seacas/libraries/chaco/eigen/orthogvec.c index 316b48f9f9ce..0fefdbc6813e 100644 --- a/packages/seacas/libraries/chaco/eigen/orthogvec.c +++ b/packages/seacas/libraries/chaco/eigen/orthogvec.c @@ -12,7 +12,7 @@ void orthogvec(double *vec1, /* vector to be orthogonalized */ ) { double alpha; - double dot(); + double dot(double *vec1, int beg, int end, double *vec2); void scadd(); alpha = -dot(vec1, beg, end, vec2) / dot(vec2, beg, end, vec2); @@ -25,7 +25,7 @@ void orthogvec_float(float *vec1, /* vector to be orthogonalized */ ) { float alpha; - double dot_float(); + double dot_float(float *vec1, int beg, int end, float *vec2); void scadd_float(); alpha = -dot_float(vec1, beg, end, vec2) / dot_float(vec2, beg, end, vec2); diff --git a/packages/seacas/libraries/chaco/eigen/rqi.c b/packages/seacas/libraries/chaco/eigen/rqi.c index 4358b1b991a4..6d59290c62af 100644 --- a/packages/seacas/libraries/chaco/eigen/rqi.c +++ b/packages/seacas/libraries/chaco/eigen/rqi.c @@ -14,22 +14,22 @@ /* Perform Rayleigh Quotient Iteration */ void rqi(struct vtx_data **A, /* matrix/graph being analyzed */ - double ** yvecs, /* eigenvectors to be refined */ + double **yvecs, /* eigenvectors to be refined */ int index, /* index of vector in yvecs to be refined */ int n, /* number of rows/columns in matrix */ double *r1, double *r2, double *v, double *w, double *x, double *y, - double * work, /* work space for symmlq */ + double *work, /* work space for symmlq */ double tol, /* error tolerance in eigenpair */ double initshift, /* initial shift */ - double * evalest, /* returned eigenvalue */ - double * vwsqrt, /* square roots of vertex weights */ + double *evalest, /* returned eigenvalue */ + double *vwsqrt, /* square roots of vertex weights */ struct orthlink *orthlist, /* lower evecs to orthogonalize against */ int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */ int nsets, /* number of sets to divide into */ - int * assignment, /* set number of each vtx (length n+1) */ - int * active, /* space for nvtxs integers */ + int *assignment, /* set number of each vtx (length n+1) */ + int *active, /* space for nvtxs integers */ int mediantype, /* which partitioning strategy to use */ - double * goal, /* desired set sizes */ + double *goal, /* desired set sizes */ int vwgt_max, /* largest vertex weight */ int ndims /* dimensionality of partition */ ) @@ -58,18 +58,18 @@ void rqi(struct vtx_data **A, /* matrix/graph being analyzed */ double factor; /* ratio between previous res and new tol */ double minfactor; /* minimum acceptable value of factor */ int converged; /* has process converged yet? */ - double * u; /* name of vector being refined */ - int * old_assignment = NULL; /* previous assignment vector */ - int * assgn_pntr; /* pntr to assignment vector */ - int * old_assgn_pntr; /* pntr to previous assignment vector */ + double *u; /* name of vector being refined */ + int *old_assignment = NULL; /* previous assignment vector */ + int *assgn_pntr; /* pntr to assignment vector */ + int *old_assgn_pntr; /* pntr to previous assignment vector */ int assigndiff = 0; /* discrepancies between old and new assignment */ int assigntol = 0; /* tolerance on convergence of assignment vector */ int first; /* is this the first RQI step? */ int i; /* loop index */ - double dot(), ch_norm(); + double dot(double *vec1, int beg, int end, double *vec2), ch_norm(double *vec, int beg, int end); int symmlq(); - void splarax(), scadd(), vecscale(), doubleout(), assign(), x2y(), strout(); + void splarax(), scadd(), vecscale(), doubleout(), assign(), x2y(), strout(char *msg); if (DEBUG_TRACE > 0) { printf("\n"); diff --git a/packages/seacas/libraries/chaco/eigen/sorthog.c b/packages/seacas/libraries/chaco/eigen/sorthog.c index 7d8795efcc41..35a17b2c250e 100644 --- a/packages/seacas/libraries/chaco/eigen/sorthog.c +++ b/packages/seacas/libraries/chaco/eigen/sorthog.c @@ -8,7 +8,7 @@ #include "structs.h" // for orthlink, orthlink_float -void sorthog(double * vec, /* vector to be orthogonalized */ +void sorthog(double *vec, /* vector to be orthogonalized */ int n, /* length of the columns of orth */ struct orthlink **solist, /* set of vecs to orth. against */ int ngood /* number of vecs in solist */ @@ -16,7 +16,7 @@ void sorthog(double * vec, /* vector to be orthogonalized */ { double alpha; double *dir; - double dot(); + double dot(double *vec1, int beg, int end, double *vec2); void scadd(); int i; @@ -27,7 +27,7 @@ void sorthog(double * vec, /* vector to be orthogonalized */ } } -void sorthog_float(float * vec, /* vector to be orthogonalized */ +void sorthog_float(float *vec, /* vector to be orthogonalized */ int n, /* length of the columns of orth */ struct orthlink_float **solist, /* set of vecs to orth. against */ int ngood /* number of vecs in solist */ @@ -35,7 +35,7 @@ void sorthog_float(float * vec, /* vector to be orthogonalize { float alpha; float *dir; - double dot_float(); + double dot_float(float *vec1, int beg, int end, float *vec2); void scadd_float(); int i; diff --git a/packages/seacas/libraries/chaco/inertial/inertial.c b/packages/seacas/libraries/chaco/inertial/inertial.c index 535820b7b31c..1a92d8e2a8fe 100644 --- a/packages/seacas/libraries/chaco/inertial/inertial.c +++ b/packages/seacas/libraries/chaco/inertial/inertial.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -17,9 +17,9 @@ void inertial(struct vtx_data **graph, /* graph data structure */ int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */ int nsets, /* number of sets to cut into */ int igeom, /* 1, 2 or 3 dimensional geometry? */ - float ** coords, /* x, y and z coordinates of vertices */ - int * sets, /* set each vertex gets assigned to */ - double * goal, /* desired set sizes */ + float **coords, /* x, y and z coordinates of vertices */ + int *sets, /* set each vertex gets assigned to */ + double *goal, /* desired set sizes */ int using_vwgts /* are vertex weights being used? */ ) { @@ -27,9 +27,9 @@ void inertial(struct vtx_data **graph, /* graph data structure */ extern int PROJECTION_AXIS; /* axis to project out geometry */ extern double inertial_time; /* time spend in inertial calculations */ double time; /* timing parameter */ - float * inert_coords[3]; /* coord arrays passed down */ + float *inert_coords[3]; /* coord arrays passed down */ int i, j; /* loop counters */ - double seconds(); + double seconds(void); void inertial1d(), inertial2d(), inertial3d(); time = seconds(); diff --git a/packages/seacas/libraries/chaco/inertial/inertial1d.c b/packages/seacas/libraries/chaco/inertial/inertial1d.c index ad295eabb731..3fcd77314c15 100644 --- a/packages/seacas/libraries/chaco/inertial/inertial1d.c +++ b/packages/seacas/libraries/chaco/inertial/inertial1d.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -14,19 +14,19 @@ void inertial1d(struct vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vtxs in graph */ int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */ int nsets, /* number of sets to divide into */ - float * x, /* x coordinates of vertices */ - int * sets, /* set each vertex gets assigned to */ - double * goal, /* desired set sizes */ + float *x, /* x coordinates of vertices */ + int *sets, /* set each vertex gets assigned to */ + double *goal, /* desired set sizes */ int using_vwgts /* are vertex weights being used? */ ) { extern double median_time; /* time to find medians */ - double * value; /* values passed to median routine */ + double *value; /* values passed to median routine */ double time; /* timing variables */ - int * space; /* space required by median routine */ + int *space; /* space required by median routine */ int i; /* loop counter */ void rec_median_1(); - double seconds(); + double seconds(void); value = smalloc((nvtxs + 1) * sizeof(double)); diff --git a/packages/seacas/libraries/chaco/inertial/inertial2d.c b/packages/seacas/libraries/chaco/inertial/inertial2d.c index b80392860c50..86cd976cecbf 100644 --- a/packages/seacas/libraries/chaco/inertial/inertial2d.c +++ b/packages/seacas/libraries/chaco/inertial/inertial2d.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -16,7 +16,7 @@ void inertial2d(struct vtx_data **graph, /* graph data structure for weig int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */ int nsets, /* number of sets to divide into */ float *x, float *y, /* x and y coordinates of vertices */ - int * sets, /* set each vertex gets assigned to */ + int *sets, /* set each vertex gets assigned to */ double *goal, /* desired set sizes */ int using_vwgts /* are vertex weights being used? */ ) @@ -26,16 +26,16 @@ void inertial2d(struct vtx_data **graph, /* graph data structure for weig extern double median_time; /* time spent computing medians */ double tensor[2][2]; /* inertial tensor */ double evec[2]; /* eigenvector of tensor */ - double * value; /* values along selected direction to sort */ + double *value; /* values along selected direction to sort */ double xcm, ycm; /* center of mass in each direction */ double xx, yy, xy; /* elements of inertial tensor */ double xdif, ydif; /* deviation from center of mass */ double eval, res; /* eigenvalue and error in eval calculation */ double vwgt_sum; /* sum of all the vertex weights */ double time; /* timing parameters */ - int * space; /* space required by median routine */ + int *space; /* space required by median routine */ int i; /* loop counter */ - double seconds(); + double seconds(void); void evals2(), eigenvec2(), rec_median_1(); diff --git a/packages/seacas/libraries/chaco/inertial/inertial3d.c b/packages/seacas/libraries/chaco/inertial/inertial3d.c index af51643be661..3a4152fa27e3 100644 --- a/packages/seacas/libraries/chaco/inertial/inertial3d.c +++ b/packages/seacas/libraries/chaco/inertial/inertial3d.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -16,7 +16,7 @@ void inertial3d(struct vtx_data **graph, /* graph data structure */ int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */ int nsets, /* number of sets to divide into */ float *x, float *y, float *z, /* x, y and z coordinates of vertices */ - int * sets, /* set each vertex gets assigned to */ + int *sets, /* set each vertex gets assigned to */ double *goal, /* desired set sizes */ int using_vwgts /* are vertex weights being used? */ ) @@ -26,7 +26,7 @@ void inertial3d(struct vtx_data **graph, /* graph data structure */ extern double median_time; /* time spent finding medians */ double tensor[3][3]; /* inertia tensor */ double evec[3]; /* eigenvector */ - double * value; /* values along selected direction to sort */ + double *value; /* values along selected direction to sort */ double xcm, ycm, zcm; /* center of mass in each direction */ double xx, yy, zz; /* elements of inertial tensor */ double xy, xz, yz; /* elements of inertial tensor */ @@ -35,9 +35,9 @@ void inertial3d(struct vtx_data **graph, /* graph data structure */ double eval, res; /* eigenvalue and error in eval calculation */ double vwgt_sum; /* sum of all the vertex weights */ double time; /* timing parameter */ - int * space; /* space required by median routine */ + int *space; /* space required by median routine */ int i; /* loop counter */ - double seconds(); + double seconds(void); void ch_eigenvec3(), ch_evals3(), rec_median_1(); diff --git a/packages/seacas/libraries/chaco/input/read_params.c b/packages/seacas/libraries/chaco/input/read_params.c index 8c0889533ed5..4d9a5a7ed540 100644 --- a/packages/seacas/libraries/chaco/input/read_params.c +++ b/packages/seacas/libraries/chaco/input/read_params.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -100,7 +100,7 @@ void read_params(FILE *pfile /* file with new user parameters */ extern int NSQRTS; /* # square roots to precompute if coarsening */ extern int MAKE_VWGTS; /* impose vertex weights = vertex degree */ extern int FREE_GRAPH; /* free data after reformatting? */ - extern char * PARAMS_FILENAME; /* name of parameters file */ + extern char *PARAMS_FILENAME; /* name of parameters file */ extern int DEBUG_EVECS; /* debug flag for eigenvector generation */ extern int DEBUG_KL; /* debug flag for Kernighan-Lin */ @@ -312,14 +312,14 @@ void read_params(FILE *pfile /* file with new user parameters */ &STARTUP_COST, &CUT_TO_HOP_COST, &KL_IMBALANCE}; char line[LINE_LENGTH + 1]; /* line from parameters file */ - char * ptr, *idptr; /* loops through input line */ + char *ptr, *idptr; /* loops through input line */ char id[25]; /* parameter identifier being modified */ static int linenum = 0; /* line number within parameter file */ int flag; /* return flag for number scanning routines */ int matched; /* has character string been matched? */ int comment; /* should input line be ignored? */ int i; /* loop counters */ - char * true_or_false(); + char *true_or_false(int flag); if (DEBUG_TRACE) { printf("\n"); @@ -511,7 +511,7 @@ void read_params(FILE *pfile /* file with new user parameters */ } static int read_intTF(char *ptr, /* pointer to string to parse */ - int * val /* value returned */ + int *val /* value returned */ ) { int nvals; /* number of values successfully read */ @@ -536,7 +536,7 @@ static int read_intTF(char *ptr, /* pointer to string to parse */ return (TRUE); } -static int read_double(char * ptr, /* pointer to string to parse */ +static int read_double(char *ptr, /* pointer to string to parse */ double *val /* value returned */ ) { diff --git a/packages/seacas/libraries/chaco/input/reflect_input.c b/packages/seacas/libraries/chaco/input/reflect_input.c index acead48d33d7..6286cd39a029 100644 --- a/packages/seacas/libraries/chaco/input/reflect_input.c +++ b/packages/seacas/libraries/chaco/input/reflect_input.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -14,11 +14,11 @@ static void reflect_params(); void reflect_input(int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ int igeom, /* geometric dimension for inertial method */ - char * graphname, /* name of graph input file */ - char * geomname, /* name of geometry input file */ - char * inassignname, /* name of assignment input file */ - char * outassignname, /* name of assignment output file */ - char * outfilename, /* name of information output file */ + char *graphname, /* name of graph input file */ + char *geomname, /* name of geometry input file */ + char *inassignname, /* name of assignment input file */ + char *outassignname, /* name of assignment output file */ + char *outfilename, /* name of information output file */ int architecture, /* 0=> hypercube, d=> d-dimensional mesh */ int ndims_tot, /* total number of cuts to make */ int mesh_dims[3], /* size of mesh */ @@ -29,14 +29,14 @@ void reflect_input(int nvtxs, /* number of vertices in graph */ int ndims, /* partitioning level */ double eigtol, /* tolerance on eigenvectors */ long seed, /* random number seed */ - FILE * outfile) /* file to write output to */ + FILE *outfile) /* file to write output to */ { extern int DEBUG_TRACE; /* trace main execution path? */ extern int ECHO; /* copy input parameters back to screen? */ extern int OUT_ASSIGN_INV; /* assignment output in inverted format? */ extern int IN_ASSIGN_INV; /* assignment input in inverted format? */ extern int PRINT_HEADERS; /* print section headers for output */ - FILE * tempfile; /* file or stdout */ + FILE *tempfile; /* file or stdout */ int i; /* loop counter */ if (DEBUG_TRACE > 0) { @@ -262,7 +262,7 @@ static void reflect_params(FILE *tempfile, /* file or stdout */ extern int EXPERT; /* Expert user? */ - char *true_or_false(); + char *true_or_false(int flag); fprintf(tempfile, "Active Parameters:\n"); diff --git a/packages/seacas/libraries/chaco/internal/force_internal.c b/packages/seacas/libraries/chaco/internal/force_internal.c index 11aaf08bdc70..e6865f172071 100644 --- a/packages/seacas/libraries/chaco/internal/force_internal.c +++ b/packages/seacas/libraries/chaco/internal/force_internal.c @@ -16,8 +16,8 @@ void force_internal(struct vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices in graph */ int using_ewgts, /* are edge weights being used? */ - int * assign, /* current assignment */ - double * goal, /* desired set sizes */ + int *assign, /* current assignment */ + double *goal, /* desired set sizes */ int nsets_tot, /* total number of sets */ int npasses_max /* number of passes to make */ ) @@ -28,12 +28,12 @@ void force_internal(struct vtx_data **graph, /* graph data structure */ struct bidint *int_list = NULL; /* internal vwgt in each set */ struct bidint *vtx_elems = NULL; /* linked lists of vtxs in each set */ struct bidint *set_list = NULL; /* headers for vtx_elems lists */ - double * internal_vwgt = NULL; /* total internal vwgt in each set */ - int * total_vwgt = NULL; /* total vertex weight in each set */ - int * indices = NULL; /* orders sets by internal vwgt */ - int * locked = NULL; /* is vertex allowed to switch sets? */ + double *internal_vwgt = NULL; /* total internal vwgt in each set */ + int *total_vwgt = NULL; /* total vertex weight in each set */ + int *indices = NULL; /* orders sets by internal vwgt */ + int *locked = NULL; /* is vertex allowed to switch sets? */ int internal; /* is a vertex internal or not? */ - int * space = NULL; /* space for mergesort */ + int *space = NULL; /* space for mergesort */ int npasses; /* number of callse to improve_internal */ int nlocked; /* number of vertices that can't move */ int set, set2; /* sets two vertices belong to */ @@ -46,7 +46,7 @@ void force_internal(struct vtx_data **graph, /* graph data structure */ int i, j; /* loop counters */ int improve_internal(); void ch_mergesort(double *vals, int nvals, int *indices, int *space); - void check_internal(), strout(); + void check_internal(), strout(char *msg); error = 1; diff --git a/packages/seacas/libraries/chaco/klspiff/buckets.c b/packages/seacas/libraries/chaco/klspiff/buckets.c index 77308b12867b..1433521c151f 100644 --- a/packages/seacas/libraries/chaco/klspiff/buckets.c +++ b/packages/seacas/libraries/chaco/klspiff/buckets.c @@ -21,10 +21,10 @@ void bucketsorts(struct vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices */ struct bilist ****buckets, /* array of lists for bucket sort */ - struct bilist ** listspace, /* list data structure for each vertex */ - int ** dvals, /* d-values for each vertex for removing */ - int * sets, /* processor each vertex is assigned to */ - float * term_wgts[], /* weights for terminal prapogation */ + struct bilist **listspace, /* list data structure for each vertex */ + int **dvals, /* d-values for each vertex for removing */ + int *sets, /* processor each vertex is assigned to */ + float *term_wgts[], /* weights for terminal prapogation */ int maxdval, /* maximum possible dvalue for a vertex */ int nsets, /* number of sets being divided into */ int parity, /* work in forward or backward direction? */ @@ -39,10 +39,10 @@ void bucketsorts(struct vtx_data **graph, /* graph data structure */ extern int KL_UNDO_LIST; /* only sort vertices who have moved. */ extern double CUT_TO_HOP_COST; /* if term_prop, cut/hop importance */ struct bilist **bptr = NULL; /* loops through set of buckets */ - struct bilist * lptr = NULL; /* pointer to an element in listspace */ - float * ewptr = NULL; /* loops through edge weights */ - int * bsptr = NULL; /* loops through bspace */ - int * edges = NULL; /* edge list for a vertex */ + struct bilist *lptr = NULL; /* pointer to an element in listspace */ + float *ewptr = NULL; /* loops through edge weights */ + int *bsptr = NULL; /* loops through bspace */ + int *edges = NULL; /* edge list for a vertex */ int myset; /* set that current vertex belongs to */ int newset; /* set current vertex could move to */ int set; /* set that neighboring vertex belongs to */ @@ -54,7 +54,7 @@ void bucketsorts(struct vtx_data **graph, /* graph data structure */ double hop_cost; /* relative hop/cut importance */ int myhop; /* hops associated with current vertex */ int i, j, l; /* loop counters */ - void randomize(), add2bilist(); + void randomize(int *array, int n), add2bilist(); /* For each vertex, compute d-values for each possible transition. */ /* Then store them in each appropriate bucket. */ diff --git a/packages/seacas/libraries/chaco/klspiff/buckets_bi.c b/packages/seacas/libraries/chaco/klspiff/buckets_bi.c index 39d4568261d1..f6e5dc1c10dc 100644 --- a/packages/seacas/libraries/chaco/klspiff/buckets_bi.c +++ b/packages/seacas/libraries/chaco/klspiff/buckets_bi.c @@ -23,10 +23,10 @@ void bucketsorts_bi(struct vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices */ struct bilist ****buckets, /* array of lists for bucket sort */ - struct bilist ** listspace, /* list data structure for each vertex */ - int ** dvals, /* d-values for each vertex for removing */ - int * sets, /* processor each vertex is assigned to */ - float * term_wgts[], /* weights for terminal propagation */ + struct bilist **listspace, /* list data structure for each vertex */ + int **dvals, /* d-values for each vertex for removing */ + int *sets, /* processor each vertex is assigned to */ + float *term_wgts[], /* weights for terminal propagation */ int maxdval, /* maximum possible dvalue for a vertex */ int nsets, /* number of sets being divided into */ int parity, /* work in forward or backward direction? */ @@ -41,11 +41,11 @@ void bucketsorts_bi(struct vtx_data **graph, /* graph data structure */ extern int KL_UNDO_LIST; /* only sort vertices who have moved. */ extern double CUT_TO_HOP_COST; /* ..if so, relative cut/hop importance */ struct bilist **bptr = NULL; /* loops through set of buckets */ - struct bilist * lptr = NULL; /* pointer to an element in listspace */ - float * ewptr = NULL; /* loops through edge weights */ - float * twptr = NULL; /* weights for terminal propagation */ - int * bsptr = NULL; /* loops through bspace */ - int * edges = NULL; /* edge list for a vertex */ + struct bilist *lptr = NULL; /* pointer to an element in listspace */ + float *ewptr = NULL; /* loops through edge weights */ + float *twptr = NULL; /* weights for terminal propagation */ + int *bsptr = NULL; /* loops through bspace */ + int *edges = NULL; /* edge list for a vertex */ int myset; /* set current vertex belongs to */ int other_set; /* set current vertex doesn't belong to */ int set; /* set that neighboring vertex belongs to */ @@ -56,7 +56,7 @@ void bucketsorts_bi(struct vtx_data **graph, /* graph data structure */ double hop_cost; /* relative hop/cut importance */ int myhop; /* hops associated with current vertex */ int i, j; /* loop counters */ - void randomize(), add2bilist(); + void randomize(int *array, int n), add2bilist(); /* For each vertex, compute d-values for each possible transition. */ /* Then store them in each appropriate bucket. */ diff --git a/packages/seacas/libraries/chaco/klspiff/klspiff.c b/packages/seacas/libraries/chaco/klspiff/klspiff.c index abe9f5375de3..5302ae954b74 100644 --- a/packages/seacas/libraries/chaco/klspiff/klspiff.c +++ b/packages/seacas/libraries/chaco/klspiff/klspiff.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -23,19 +23,19 @@ static void free_kl(); void klspiff(struct vtx_data **graph, /* list of graph info for each vertex */ int nvtxs, /* number of vertices in graph */ - int * sets, /* local partitioning of vtxs */ + int *sets, /* local partitioning of vtxs */ int nsets, /* number of sets at each level */ int (*hops)[MAXSETS], /* hop cost between sets */ double *goal, /* desired set sizes */ - float * term_wgts[], /* weights for terminal propagation */ + float *term_wgts[], /* weights for terminal propagation */ int max_dev, /* largest deviation from balance allowed */ double maxdeg, /* largest weighted vertex degree */ int using_ewgts, /* are edge weights being used? */ - int ** bndy_list, /* list of vertices on boundary (0 ends) */ + int **bndy_list, /* list of vertices on boundary (0 ends) */ double *weights /* vertex weights in each set */ ) { - extern FILE * Output_File; /* output file or null */ + extern FILE *Output_File; /* output file or null */ extern double CUT_TO_HOP_COST; /* relative importance of cuts/hops */ extern int DEBUG_TRACE; /* debug flag for Kernighan-Lin */ extern int DEBUG_KL; /* debug flag for Kernighan-Lin */ @@ -43,10 +43,10 @@ void klspiff(struct vtx_data **graph, /* list of graph info for each vertex */ extern double kl_init_time; extern double nway_kl_time; struct bilist ****buckets; /* space for bucket sorts */ - struct bilist ** listspace; /* space for all bidirectional elements */ - float * twptr; /* loops through term_wgts */ - int ** dvals; /* change in penalty for each possible move */ - int ** tops; /* starting dval for each type of move */ + struct bilist **listspace; /* space for all bidirectional elements */ + float *twptr; /* loops through term_wgts */ + int **dvals; /* change in penalty for each possible move */ + int **tops; /* starting dval for each type of move */ double time, time1; /* timing variables */ float maxterm; /* largest terminal propagation preference */ int maxhop; /* maximum hops between sets */ @@ -55,7 +55,7 @@ void klspiff(struct vtx_data **graph, /* list of graph info for each vertex */ double hop_cost; /* relative importance of hops/cuts */ int error; /* out of space? */ int i, j; /* loop counters */ - double seconds(); + double seconds(void); int kl_init(), nway_kl(); void count(); @@ -140,9 +140,9 @@ void klspiff(struct vtx_data **graph, /* list of graph info for each vertex */ static void free_kl( /* Free everything malloc'd for KL. */ struct bilist ****buckets, /* space for bucket sorts */ - struct bilist ** listspace, /* space for all bidirectional elements */ - int ** dvals, /* change in penalty for each possible move */ - int ** tops /* starting dval for each type of move */ + struct bilist **listspace, /* space for all bidirectional elements */ + int **dvals, /* change in penalty for each possible move */ + int **tops /* starting dval for each type of move */ ) { diff --git a/packages/seacas/libraries/chaco/klspiff/nway_kl.c b/packages/seacas/libraries/chaco/klspiff/nway_kl.c index e0c4efe4da9b..e33534a258f6 100644 --- a/packages/seacas/libraries/chaco/klspiff/nway_kl.c +++ b/packages/seacas/libraries/chaco/klspiff/nway_kl.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -26,18 +26,18 @@ int KL_MAX_PASS = -1; /* max KL passes; infinite if <= 0 */ int nway_kl(struct vtx_data **graph, /* data structure for graph */ int nvtxs, /* number of vtxs in graph */ struct bilist ****buckets, /* array of lists for bucket sort */ - struct bilist ** listspace, /* list data structure for each vertex */ - int ** tops, /* 2-D array of top of each set of buckets */ - int ** dvals, /* d-values for each transition */ - int * sets, /* processor each vertex is assigned to */ + struct bilist **listspace, /* list data structure for each vertex */ + int **tops, /* 2-D array of top of each set of buckets */ + int **dvals, /* d-values for each transition */ + int *sets, /* processor each vertex is assigned to */ int maxdval, /* maximum d-value for a vertex */ int nsets, /* number of sets divided into */ - double * goal, /* desired set sizes */ - float * term_wgts[], /* weights for terminal propagation */ + double *goal, /* desired set sizes */ + float *term_wgts[], /* weights for terminal propagation */ int (*hops)[MAXSETS], /* cost of set transitions */ int max_dev, /* largest allowed deviation from balance */ int using_ewgts, /* are edge weights being used? */ - int ** bndy_list, /* list of vertices on boundary (0 ends) */ + int **bndy_list, /* list of vertices on boundary (0 ends) */ double *startweight /* sum of vweights in each set (in and out) */ ) @@ -55,17 +55,17 @@ int nway_kl(struct vtx_data **graph, /* data structure for graph */ extern int KL_UNDO_LIST; /* should I back out of changes or start over? */ extern int KL_MAX_PASS; /* maximum number of outer KL loops */ extern double CUT_TO_HOP_COST; /* if term_prop; cut/hop importance */ - struct bilist * movelist; /* list of vtxs to be moved */ + struct bilist *movelist; /* list of vtxs to be moved */ struct bilist **endlist; /* end of movelists */ - struct bilist * bestptr; /* best vertex in linked list */ - struct bilist * bptr; /* loops through bucket list */ - float * ewptr = NULL; /* loops through edge weights */ - double * locked = NULL; /* weight of vertices locked in a set */ - double * loose = NULL; /* weight of vtxs that can move from a set */ - int * bspace = NULL; /* list of active vertices for bucketsort */ - double * weightsum = NULL; /* sum of vweights for each partition */ - int * edges = NULL; /* edge list for a vertex */ - int * bdy_ptr = NULL; /* loops through bndy_list */ + struct bilist *bestptr; /* best vertex in linked list */ + struct bilist *bptr; /* loops through bucket list */ + float *ewptr = NULL; /* loops through edge weights */ + double *locked = NULL; /* weight of vertices locked in a set */ + double *loose = NULL; /* weight of vtxs that can move from a set */ + int *bspace = NULL; /* list of active vertices for bucketsort */ + double *weightsum = NULL; /* sum of vweights for each partition */ + int *edges = NULL; /* edge list for a vertex */ + int *bdy_ptr = NULL; /* loops through bndy_list */ double time; /* timing parameter */ double delta; /* desire of sets to change size */ double bestdelta = -1; /* strongest delta value */ @@ -113,7 +113,7 @@ int nway_kl(struct vtx_data **graph, /* data structure for graph */ int size; /* array spacing */ int i, j, k, l; /* loop counters */ - double drandom(), seconds(); + double drandom(), seconds(void); int make_kl_list(); void bucketsorts(), bucketsorts_bi(), bucketsort1(); void pbuckets(), removebilist(), movebilist(), make_bndy_list(); diff --git a/packages/seacas/libraries/chaco/klvspiff/bucketsv.c b/packages/seacas/libraries/chaco/klvspiff/bucketsv.c index d3e8f98c63a9..48249f329a7e 100644 --- a/packages/seacas/libraries/chaco/klvspiff/bucketsv.c +++ b/packages/seacas/libraries/chaco/klvspiff/bucketsv.c @@ -11,16 +11,16 @@ void bucketsortsv(struct vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices */ - struct bilist ** lbuckets, /* array of lists for bucket sort */ - struct bilist ** rbuckets, /* array of lists for bucket sort */ - struct bilist * llistspace, /* list data structure for each vertex */ - struct bilist * rlistspace, /* list data structure for each vertex */ - int * ldvals, /* d-values for each vertex for removing */ - int * rdvals, /* d-values for each vertex for removing */ - int * sets, /* processor each vertex is assigned to */ + struct bilist **lbuckets, /* array of lists for bucket sort */ + struct bilist **rbuckets, /* array of lists for bucket sort */ + struct bilist *llistspace, /* list data structure for each vertex */ + struct bilist *rlistspace, /* list data structure for each vertex */ + int *ldvals, /* d-values for each vertex for removing */ + int *rdvals, /* d-values for each vertex for removing */ + int *sets, /* processor each vertex is assigned to */ int maxdval, /* maximum possible dvalue for a vertex */ int parity, /* work in forward or backward direction? */ - int * bspace, /* indices for randomly ordering vtxs */ + int *bspace, /* indices for randomly ordering vtxs */ int list_length /* number of values in bspace to work with */ ) { @@ -28,15 +28,15 @@ void bucketsortsv(struct vtx_data **graph, /* graph data structure */ extern int KL_UNDO_LIST; /* only sort vertices who have moved. */ struct bilist **lbptr; /* loops through set of buckets */ struct bilist **rbptr; /* loops through set of buckets */ - int * bsptr; /* loops through bspace */ - int * edges; /* edge list for a vertex */ + int *bsptr; /* loops through bspace */ + int *edges; /* edge list for a vertex */ int left_weight; /* my neighbors in 0 set */ int right_weight; /* my neighbors in 1 set */ int vtx; /* vertex in graph */ int neighbor; /* neighbor of vertex */ int set; /* set that neighboring vertex belongs to */ int i, j; /* loop counters */ - void randomize(), add2bilist(); + void randomize(int *array, int n), add2bilist(); /* For each vertex, compute d-values and store in buckets. */ diff --git a/packages/seacas/libraries/chaco/klvspiff/klvspiff.c b/packages/seacas/libraries/chaco/klvspiff/klvspiff.c index e1491c1affb0..cc6c95cd4be8 100644 --- a/packages/seacas/libraries/chaco/klvspiff/klvspiff.c +++ b/packages/seacas/libraries/chaco/klvspiff/klvspiff.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -19,14 +19,14 @@ static void free_klv(); void klvspiff(struct vtx_data **graph, /* list of graph info for each vertex */ int nvtxs, /* number of vertices in graph */ - int * sets, /* local partitioning of vtxs */ - double * goal, /* desired set sizes */ + int *sets, /* local partitioning of vtxs */ + double *goal, /* desired set sizes */ int max_dev, /* largest deviation from balance allowed */ - int ** bndy_list, /* list of vertices on boundary (0 ends) */ - double * weights /* vertex weights in each set */ + int **bndy_list, /* list of vertices on boundary (0 ends) */ + double *weights /* vertex weights in each set */ ) { - extern FILE * Output_File; /* output file or null */ + extern FILE *Output_File; /* output file or null */ extern int DEBUG_TRACE; /* debug flag for Kernighan-Lin */ extern int DEBUG_KL; /* debug flag for Kernighan-Lin */ extern double kl_total_time; @@ -34,17 +34,17 @@ void klvspiff(struct vtx_data **graph, /* list of graph info for each vertex extern double nway_kl_time; struct bilist **lbuckets; /* space for bucket sorts for left moves */ struct bilist **rbuckets; /* space for bucket sorts for right moves */ - struct bilist * llistspace; /* space for all left bidirectional elements */ - struct bilist * rlistspace; /* space for all right bidirectional elements */ - int * ldvals; /* change in penalty for each possible move */ - int * rdvals; /* change in penalty for each possible move */ - int * edges; /* loops through neighbor lists */ + struct bilist *llistspace; /* space for all left bidirectional elements */ + struct bilist *rlistspace; /* space for all right bidirectional elements */ + int *ldvals; /* change in penalty for each possible move */ + int *rdvals; /* change in penalty for each possible move */ + int *edges; /* loops through neighbor lists */ double time, time1; /* timing variables */ int dval; /* largest transition cost for a vertex */ int maxdval; /* largest transition cost for all vertices */ int error; /* out of space? */ int i, j; /* loop counters */ - double seconds(); + double seconds(void); int klv_init(), nway_klv(); void countup_vtx_sep(); @@ -113,10 +113,10 @@ static void free_klv( /* Free everything malloc'd for KLV. */ struct bilist **lbuckets, /* space for bucket sorts */ struct bilist **rbuckets, /* space for bucket sorts */ - struct bilist * llistspace, /* space for all bidirectional elements */ - struct bilist * rlistspace, /* space for all bidirectional elements */ - int * ldvals, /* change in penalty for each possible move */ - int * rdvals /* change in penalty for each possible move */ + struct bilist *llistspace, /* space for all bidirectional elements */ + struct bilist *rlistspace, /* space for all bidirectional elements */ + int *ldvals, /* change in penalty for each possible move */ + int *rdvals /* change in penalty for each possible move */ ) { sfree(rlistspace); diff --git a/packages/seacas/libraries/chaco/klvspiff/nway_klv.c b/packages/seacas/libraries/chaco/klvspiff/nway_klv.c index ef83ae32eef1..367fcb38509d 100644 --- a/packages/seacas/libraries/chaco/klvspiff/nway_klv.c +++ b/packages/seacas/libraries/chaco/klvspiff/nway_klv.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -48,7 +48,7 @@ int nway_klv(struct vtx_data **graph, /* data structure for graph */ extern int KL_NTRIES_BAD; /* number of unhelpful passes before quitting */ extern int KL_MAX_PASS; /* maximum # outer KL loops */ - double seconds(), drandom(); + double seconds(), drandom(void); int make_sep_list(); void bucketsortsv(), clear_dvals(), p1bucket(); void removebilist(), movebilist(), add2bilist(); diff --git a/packages/seacas/libraries/chaco/main/interface.c b/packages/seacas/libraries/chaco/main/interface.c index f1bc68ba26ff..c32e73470354 100644 --- a/packages/seacas/libraries/chaco/main/interface.c +++ b/packages/seacas/libraries/chaco/main/interface.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -22,14 +22,14 @@ extern int submain(struct vtx_data **graph, int nvtxs, int nedges, int using_vwg int Using_Main = FALSE; /* Is main routine being called? */ int INTER_FACE(int nvtxs, /* number of vertices in full graph */ - int * start, /* start of edge list for each vertex */ - int * adjacency, /* edge list data */ - int * vwgts, /* weights for all vertices */ + int *start, /* start of edge list for each vertex */ + int *adjacency, /* edge list data */ + int *vwgts, /* weights for all vertices */ float *ewgts, /* weights for all edges */ float *x, float *y, float *z, /* coordinates for inertial method */ - char * outassignname, /* name of assignment output file */ - char * outfilename, /* output file name */ - int * assignment, /* set number of each vtx (length n) */ + char *outassignname, /* name of assignment output file */ + char *outfilename, /* output file name */ + int *assignment, /* set number of each vtx (length n) */ int architecture, /* 0 => hypercube, d => d-dimensional mesh */ int ndims_tot, /* total number of cube dimensions to divide */ int mesh_dims[3], /* dimensions of mesh of processors */ @@ -43,7 +43,7 @@ int INTER_FACE(int nvtxs, /* number of vertices in full graph long seed /* for random graph mutations */ ) { - extern char * PARAMS_FILENAME; /* name of file with parameter updates */ + extern char *PARAMS_FILENAME; /* name of file with parameter updates */ extern int MAKE_VWGTS; /* make vertex weights equal to degrees? */ extern int MATCH_TYPE; /* matching routine to use */ extern int FREE_GRAPH; /* free graph data structure after reformat? */ @@ -51,12 +51,12 @@ int INTER_FACE(int nvtxs, /* number of vertices in full graph extern int DEBUG_TRACE; /* trace main execution path */ extern double start_time; /* time routine is entered */ extern double reformat_time; /* time spent reformatting graph */ - FILE * params_file = NULL; /* file for reading new parameters */ + FILE *params_file = NULL; /* file for reading new parameters */ struct vtx_data **graph; /* graph data structure */ double vwgt_sum; /* sum of vertex weights */ double time; /* timing variable */ - float ** coords; /* coordinates for vertices if used */ - int * vptr; /* loops through vertex weights */ + float **coords; /* coordinates for vertices if used */ + int *vptr; /* loops through vertex weights */ int flag; /* return code from balance */ int nedges; /* number of edges in graph */ int using_vwgts; /* are vertex weights being used? */ @@ -65,9 +65,9 @@ int INTER_FACE(int nvtxs, /* number of vertices in full graph int igeom; /* geometric dimension for inertial method */ int default_goal; /* using default goals? */ int i; /* loop counter */ - double seconds(); + double seconds(void); int reformat(); - void free_graph(), read_params(), strout(); + void free_graph(), read_params(), strout(char *msg); if (DEBUG_TRACE > 0) { printf("\n"); @@ -216,8 +216,8 @@ int INTER_FACE(int nvtxs, /* number of vertices in full graph /* Subtract from assignment to allow code to index from 1. */ assignment = assignment - 1; flag = submain(graph, nvtxs, nedges, using_vwgts, using_ewgts, igeom, coords, outassignname, - outfilename, assignment, goal, architecture, ndims_tot, mesh_dims, global_method, - local_method, rqi_flag, vmax, ndims, eigtol, seed); + outfilename, assignment, goal, architecture, ndims_tot, mesh_dims, global_method, + local_method, rqi_flag, vmax, ndims, eigtol, seed); skip: sfree(coords); diff --git a/packages/seacas/libraries/chaco/main/main.c b/packages/seacas/libraries/chaco/main/main.c index 11be6a934379..1aae4b5c9ee5 100644 --- a/packages/seacas/libraries/chaco/main/main.c +++ b/packages/seacas/libraries/chaco/main/main.c @@ -15,10 +15,10 @@ int main(void) { extern int Using_Main; /* is main routine being called? */ - extern char * Graph_File_Name; /* name of graph input file */ - extern char * Geometry_File_Name; /* name of coordinate input file */ - extern char * Assign_In_File_Name; /* name of assignment input input file */ - extern char * PARAMS_FILENAME; /* name of file with parameter updates */ + extern char *Graph_File_Name; /* name of graph input file */ + extern char *Geometry_File_Name; /* name of coordinate input file */ + extern char *Assign_In_File_Name; /* name of assignment input input file */ + extern char *PARAMS_FILENAME; /* name of file with parameter updates */ extern double EIGEN_TOLERANCE; /* tolerance for eigen calculations */ extern int OUTPUT_ASSIGN; /* whether to write assignment to file */ extern int DEBUG_MEMORY; /* debug memory allocation and freeing? */ @@ -31,19 +31,19 @@ int main(void) extern int MATCH_TYPE; /* matching routine to call */ extern double input_time; /* times data file input */ extern double start_time; /* time partitioning starts */ - FILE * fin; /* input file */ - FILE * fingeom; /* geometry input file (for inertial method) */ - FILE * finassign; /* assignment file if reading in */ - FILE * params_file; /* file with parameter value updates */ - double * goal; /* desired set sizes */ - float * x, *y, *z; /* coordinates for inertial method */ - int * start; /* start of edge list for each vertex */ - int * adjacency; /* edge list data */ - float * ewgts; /* weights for all edges */ - int * vwgts; /* weights for all vertices */ + FILE *fin; /* input file */ + FILE *fingeom; /* geometry input file (for inertial method) */ + FILE *finassign; /* assignment file if reading in */ + FILE *params_file; /* file with parameter value updates */ + double *goal; /* desired set sizes */ + float *x, *y, *z; /* coordinates for inertial method */ + int *start; /* start of edge list for each vertex */ + int *adjacency; /* edge list data */ + float *ewgts; /* weights for all edges */ + int *vwgts; /* weights for all vertices */ int global_method; /* global partitioning method */ int local_method; /* local partitioning method */ - int * assignment; /* set number of each vtx (length nvtxs+1) */ + int *assignment; /* set number of each vtx (length nvtxs+1) */ double eigtol; /* tolerance in eigenvector calculation */ int nvtxs; /* number of vertices in graph */ int ndims; /* dimension of recursive partitioning */ @@ -59,12 +59,12 @@ int main(void) char inassignname[NAME_LENGTH]; /* assignment input file name */ char outassignname[NAME_LENGTH]; /* assignment output file name */ char outfilename[NAME_LENGTH]; /* name of output file */ - char * outassignptr; /* name or null pointer for output assignment */ - char * outfileptr; /* name or null pointer for output file */ + char *outassignptr; /* name or null pointer for output assignment */ + char *outfileptr; /* name or null pointer for output file */ int another; /* run another problem? */ double time; /* timing marker */ int flag; /* return code from input routines */ - double seconds(); /* returns elapsed time in seconds */ + double seconds(void); /* returns elapsed time in seconds */ int affirm(); int input_graph(), input_geom(); void input_queries(), read_params(), clear_timing(); @@ -89,7 +89,7 @@ int main(void) while (another) { - start_time = time = seconds(); + start_time = time = seconds(void); x = y = z = NULL; goal = NULL; diff --git a/packages/seacas/libraries/chaco/misc/perturb.c b/packages/seacas/libraries/chaco/misc/perturb.c index f870aeb3e2b2..5303e29f3b3a 100644 --- a/packages/seacas/libraries/chaco/misc/perturb.c +++ b/packages/seacas/libraries/chaco/misc/perturb.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -11,7 +11,7 @@ #include // for NULL static struct ipairs *pedges; /* perturbed edges */ -static double * pvals; /* perturbed values */ +static double *pvals; /* perturbed values */ /* Inititialize the perturbation */ void perturb_init(int n /* graph size at this level */ @@ -20,7 +20,7 @@ void perturb_init(int n /* graph size at this level */ extern int NPERTURB; /* number of edges to perturb */ extern double PERTURB_MAX; /* maximum perturbation */ int i, j; /* loop counter */ - double drandom(); + double drandom(void); /* Initialize the diagonal perturbation weights */ pedges = smalloc(NPERTURB * sizeof(struct ipairs)); diff --git a/packages/seacas/libraries/chaco/misc/sequence.c b/packages/seacas/libraries/chaco/misc/sequence.c index 2fc2448a0541..243738465c57 100644 --- a/packages/seacas/libraries/chaco/misc/sequence.c +++ b/packages/seacas/libraries/chaco/misc/sequence.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -15,7 +15,7 @@ void sequence(struct vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ int using_ewgts, /* are edge weights being used? */ - double * vwsqrt, /* sqrt of vertex weights (length nvtxs+1) */ + double *vwsqrt, /* sqrt of vertex weights (length nvtxs+1) */ int solver_flag, /* which eigensolver should I use? */ int rqi_flag, /* use multilevel eigensolver? */ int vmax, /* if so, how many vtxs to coarsen down to? */ @@ -28,18 +28,18 @@ void sequence(struct vtx_data **graph, /* graph data structure */ extern double sequence_time; /* time spent sequencing */ struct vtx_data **subgraph = NULL; /* subgraph data structure */ struct edgeslist *edge_list = NULL; /* edges added for connectivity */ - double * yvecs[MAXDIMS + 1]; /* space for pointing to eigenvectors */ + double *yvecs[MAXDIMS + 1]; /* space for pointing to eigenvectors */ double evals[MAXDIMS + 1]; /* corresponding eigenvalues */ - double * subvwsqrt = NULL; /* vwsqrt vector for subgraphs */ - double * subvals = NULL; /* values for one connected component */ + double *subvwsqrt = NULL; /* vwsqrt vector for subgraphs */ + double *subvals = NULL; /* values for one connected component */ double goal[2]; /* needed for eigen convergence mode = 1 */ double total_vwgt; /* sum of all vertex weights */ - float * term_wgts[2]; /* dummy vector for terminal weights */ - int * setsize = NULL; /* size of each connected component */ - int * glob2loc = NULL; /* maps graph vtxs to subgraph vtxs */ - int * loc2glob = NULL; /* maps subgraph vtxs to graph vtxs */ - int * subperm = NULL; /* partial permutation */ - int * degree = NULL; /* degrees of vertices in subgraph */ + float *term_wgts[2]; /* dummy vector for terminal weights */ + int *setsize = NULL; /* size of each connected component */ + int *glob2loc = NULL; /* maps graph vtxs to subgraph vtxs */ + int *loc2glob = NULL; /* maps subgraph vtxs to graph vtxs */ + int *subperm = NULL; /* partial permutation */ + int *degree = NULL; /* degrees of vertices in subgraph */ double maxdeg; /* maximum weighted degree of a vertex */ int subnvtxs; /* number of vertices in subgraph */ int subnedges; /* number of edges in subgraph */ @@ -50,20 +50,20 @@ void sequence(struct vtx_data **graph, /* graph data structure */ int old_rqi_conv_mode; /* value of RQI_CONVERGENCE_MODE */ int old_lan_conv_mode; /* value of LANCZOS_CONVERGENCE_MODE */ int i; /* loop counters */ - FILE * orderfile = NULL; + FILE *orderfile = NULL; void ch_mergesort(double *vals, int nvals, int *indices, int *space); void eigensolve(), free_edgeslist(), y2x(); void make_subvector(), make_subgraph(), remake_graph(); void make_maps2(); - double find_maxdeg(), seconds(); + double find_maxdeg(), seconds(void); int find_edges(); double time = seconds(); int using_vwgts = (vwsqrt != NULL); /* Sort each connected component separately. */ - int * compnum = smalloc((nvtxs + 1) * sizeof(int)); - int * permutation = smalloc(nvtxs * sizeof(int)); + int *compnum = smalloc((nvtxs + 1) * sizeof(int)); + int *permutation = smalloc(nvtxs * sizeof(int)); double *values = smalloc((nvtxs + 1) * sizeof(double)); int *space = smalloc(nvtxs * sizeof(int)); diff --git a/packages/seacas/libraries/chaco/misc/simple_part.c b/packages/seacas/libraries/chaco/misc/simple_part.c index 305f751d2822..d550882b418b 100644 --- a/packages/seacas/libraries/chaco/misc/simple_part.c +++ b/packages/seacas/libraries/chaco/misc/simple_part.c @@ -14,10 +14,10 @@ /* Partition vertices into sets in one of several simplistic ways. */ void simple_part(struct vtx_data **graph, /* data structure for graph */ int nvtxs, /* total number of vtxs in graph */ - int * sets, /* sets vertices get assigned to */ + int *sets, /* sets vertices get assigned to */ int nsets, /* number of sets at each division */ int simple_type, /* type of decomposition */ - double * goal /* desired set sizes */ + double *goal /* desired set sizes */ ) { extern int DEBUG_TRACE; /* trace the execution of the code */ @@ -27,13 +27,13 @@ void simple_part(struct vtx_data **graph, /* data structure for graph */ double sum; /* sum of vwgts in a set */ double vwgt; /* vertex weight */ int using_vwgts; /* are vertex weights active? */ - int * order; /* random ordering of vertices */ + int *order; /* random ordering of vertices */ int weight; /* sum of vertex weights in a partition */ int wgts[MAXSETS]; /* weight assigned to given set so far */ int set = 0; /* set vertex is assigned to */ int i, j; /* loop counters */ - void randomize(); + void randomize(int *array, int n); using_vwgts = (graph != NULL); diff --git a/packages/seacas/libraries/chaco/misc/time_kernels.c b/packages/seacas/libraries/chaco/misc/time_kernels.c index 7fcddde2b72e..b9f65c2f6178 100644 --- a/packages/seacas/libraries/chaco/misc/time_kernels.c +++ b/packages/seacas/libraries/chaco/misc/time_kernels.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -15,7 +15,7 @@ static double checkvec(); /* Benchmark certain kernel operations */ void time_kernels(struct vtx_data **A, /* matrix/graph being analyzed */ int n, /* number of rows/columns in matrix */ - double * vwsqrt /* square roots of vertex weights */ + double *vwsqrt /* square roots of vertex weights */ ) { extern int DEBUG_PERTURB; /* debug flag for matrix perturbation */ @@ -24,8 +24,8 @@ void time_kernels(struct vtx_data **A, /* matrix/graph being analyzed */ extern int DEBUG_TRACE; /* trace main execution path */ extern double PERTURB_MAX; /* maximum size of perturbation */ int i, beg, end; - double * dvec1, *dvec2, *dvec3; - float * svec1, *svec2, *svec3, *vwsqrt_float; + double *dvec1, *dvec2, *dvec3; + float *svec1, *svec2, *svec3, *vwsqrt_float; double norm_dvec, norm_svec; double dot_dvec, dot_svec; double time, time_dvec, time_svec; @@ -35,16 +35,18 @@ void time_kernels(struct vtx_data **A, /* matrix/graph being analyzed */ int loops; double min_time, target_time; - double *mkvec(); - float * mkvec_float(); - void frvec(), frvec_float(); + double *mkvec(int nl, int nh); + float *mkvec_float(int nl, int nh); + void frvec(double *v, int nl), frvec_float(float *v, int nl); void vecran(); - double ch_norm(), dot(); - double norm_float(), dot_float(); - double seconds(); - void scadd(), scadd_float(), update(), update_float(); - void splarax(), splarax_float(); - void perturb_init(), perturb_clear(); + double ch_norm(double *vec, int beg, int end), dot(double *vec1, int beg, int end, double *vec2); + double norm_float(), dot_float(float *vec1, int beg, int end, float *vec2); + double seconds(void); + void scadd(), scadd_float(), + update(double *vec1, int beg, int end, double *vec2, double fac, double *vec3), + update_float(float *vec1, int beg, int end, float *vec2, float fac, float *vec3); + void splarax(), splarax_float(); + void perturb_init(), perturb_clear(); if (DEBUG_TRACE > 0) { printf("\n"); @@ -79,8 +81,8 @@ void time_kernels(struct vtx_data **A, /* matrix/graph being analyzed */ svec3[i] = dvec3[i]; } - /* Set number of loops so that ch_norm() takes about one second. This should - insulate against inaccurate timings on faster machines. */ + /* Set number of loops so that ch_norm(double *vec, int beg, int end) takes about one second. This + should insulate against inaccurate timings on faster machines. */ loops = 1; time_dvec = 0; diff --git a/packages/seacas/libraries/chaco/optimize/opt3d.c b/packages/seacas/libraries/chaco/optimize/opt3d.c index a1338b68a4c5..acf79e8c1a29 100644 --- a/packages/seacas/libraries/chaco/optimize/opt3d.c +++ b/packages/seacas/libraries/chaco/optimize/opt3d.c @@ -12,10 +12,10 @@ #include void opt3d(struct vtx_data **graph, /* data structure containing vertex weights */ - double ** yvecs, /* eigenvectors */ + double **yvecs, /* eigenvectors */ int nvtxs, /* total number of vertices */ int nmyvtxs, /* number of vertices I own */ - double * vwsqrt, /* square root of vertex weights */ + double *vwsqrt, /* square root of vertex weights */ double *ptheta, double *pphi, double *pgamma, /* return optimal angles */ int using_vwgts /* are vertex weights being used? */ ) @@ -24,8 +24,8 @@ void opt3d(struct vtx_data **graph, /* data structure containing vertex weight { extern int DEBUG_OPTIMIZE; /* debug flag for optimization */ extern int OPT3D_NTRIES; /* number of local opts to find global min */ - double * aptr, *bptr, *cptr; /* loop through yvecs */ - double * wsptr; /* loops through vwsqrt */ + double *aptr, *bptr, *cptr; /* loop through yvecs */ + double *wsptr; /* loops through vwsqrt */ double coeffs[25]; /* various products of yvecs */ double vars[3]; /* angular variables */ double best[3]; /* best minimizer found so far */ @@ -62,7 +62,7 @@ void opt3d(struct vtx_data **graph, /* data structure containing vertex weight int ntries, maxtries; /* number of local minimizations */ int i, j; /* loop counter */ double func3d(), constraint(); - double drandom(); + double drandom(void); void grad3d(), hess3d(), gradcon(), hesscon(), kramer3(), ch_eigenvec3(); void ch_evals3(); diff --git a/packages/seacas/libraries/chaco/refine_map/refine_map.c b/packages/seacas/libraries/chaco/refine_map/refine_map.c index 5e688d868264..bfd3b08fb285 100644 --- a/packages/seacas/libraries/chaco/refine_map/refine_map.c +++ b/packages/seacas/libraries/chaco/refine_map/refine_map.c @@ -16,7 +16,7 @@ void refine_map(struct vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices in graph */ int using_ewgts, /* are edge weights being used? */ - int * assign, /* current assignment */ + int *assign, /* current assignment */ int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */ int ndims_tot, /* if hypercube, number of dimensions */ int mesh_dims[3] /* if mesh, dimensions of mesh */ @@ -24,14 +24,14 @@ void refine_map(struct vtx_data **graph, /* graph data structure */ { struct vtx_data **comm_graph; /* graph for communication requirements */ int nsets_tot = 0; /* total number of sets */ - int * vtx2node = NULL; /* mapping of comm_graph vtxs to processors */ - int * node2vtx = NULL; /* mapping of sets to comm_graph vtxs */ + int *vtx2node = NULL; /* mapping of comm_graph vtxs to processors */ + int *node2vtx = NULL; /* mapping of sets to comm_graph vtxs */ double maxdesire = 0.0; /* largest possible desire to flip an edge */ int error = 0; /* out of space? */ int i; /* loop counter */ double find_maxdeg(); - void free_graph(), strout(); + void free_graph(), strout(char *msg); int make_comm_graph(), refine_mesh(), refine_cube(); if (cube_or_mesh == 0) { diff --git a/packages/seacas/libraries/chaco/refine_part/refine_part.c b/packages/seacas/libraries/chaco/refine_part/refine_part.c index 884822413904..e27e63282637 100644 --- a/packages/seacas/libraries/chaco/refine_part/refine_part.c +++ b/packages/seacas/libraries/chaco/refine_part/refine_part.c @@ -17,40 +17,40 @@ int refine_part(struct vtx_data **graph, /* graph data structure */ int nvtxs, /* number of vertices in graph */ int using_ewgts, /* are edge weights being used? */ - int * assign, /* current assignment */ + int *assign, /* current assignment */ int architecture, /* 0 => hypercube, d => d-dimensional mesh */ int ndims_tot, /* if hypercube, number of dimensions */ int mesh_dims[3], /* if mesh, size in each direction */ - double * goal /* desired set sizes */ + double *goal /* desired set sizes */ ) { extern int TERM_PROP; /* perform terminal propagation? */ - struct bilist * set_list = NULL; /* lists of vtxs in each set */ - struct bilist * vtx_elems = NULL; /* space for all vtxs in set_lists */ - struct bilist * ptr = NULL; /* loops through set_lists */ - struct ipairs * pairs = NULL; /* ordered list of edges in comm graph */ - double * comm_vals = NULL; /* edge wgts of comm graph for sorting */ - float * term_wgts[2]; /* terminal propagation vector */ + struct bilist *set_list = NULL; /* lists of vtxs in each set */ + struct bilist *vtx_elems = NULL; /* space for all vtxs in set_lists */ + struct bilist *ptr = NULL; /* loops through set_lists */ + struct ipairs *pairs = NULL; /* ordered list of edges in comm graph */ + double *comm_vals = NULL; /* edge wgts of comm graph for sorting */ + float *term_wgts[2]; /* terminal propagation vector */ int hops[MAXSETS][MAXSETS]; /* preference weighting */ - void * temp = NULL; /* return argument from srealloc_ret() */ - int * indices = NULL; /* sorted order for communication edges */ - int * space = NULL; /* space for mergesort */ - int * sizes = NULL; /* sizes of the different sets */ - int * sub_assign = NULL; /* new assignment for subgraph */ - int * old_sub_assign = NULL; /* room for current sub assignment */ - int ** edges_list = NULL; /* lists of comm graph edges */ - int ** ewgts_list = NULL; /* lists of comm graph edge wgts */ - int * ewgts = NULL; /* loops through ewgts_list */ - int * edges = NULL; /* edges in communication graph */ - int * adj_sets = NULL; /* weights connecting sets */ - int * eptr = NULL; /* loop through edges and edge weights */ - int * ewptr = NULL; /* loop through edges and edge weights */ + void *temp = NULL; /* return argument from srealloc_ret() */ + int *indices = NULL; /* sorted order for communication edges */ + int *space = NULL; /* space for mergesort */ + int *sizes = NULL; /* sizes of the different sets */ + int *sub_assign = NULL; /* new assignment for subgraph */ + int *old_sub_assign = NULL; /* room for current sub assignment */ + int **edges_list = NULL; /* lists of comm graph edges */ + int **ewgts_list = NULL; /* lists of comm graph edge wgts */ + int *ewgts = NULL; /* loops through ewgts_list */ + int *edges = NULL; /* edges in communication graph */ + int *adj_sets = NULL; /* weights connecting sets */ + int *eptr = NULL; /* loop through edges and edge weights */ + int *ewptr = NULL; /* loop through edges and edge weights */ int ewgt; /* weight of an edge */ struct vtx_data **subgraph = NULL; /* subgraph data structure */ - int * nedges = NULL; /* space for saving graph data */ - int * degrees = NULL; /* # neighbors of vertices */ - int * glob2loc = NULL; /* maps full to reduced numbering */ - int * loc2glob = NULL; /* maps reduced to full numbering */ + int *nedges = NULL; /* space for saving graph data */ + int *degrees = NULL; /* # neighbors of vertices */ + int *glob2loc = NULL; /* maps full to reduced numbering */ + int *loc2glob = NULL; /* maps reduced to full numbering */ int nmax; /* largest subgraph I expect to encounter */ int set, set1, set2; /* sets vertices belong to */ int vertex; /* vertex in graph */ @@ -63,7 +63,7 @@ int refine_part(struct vtx_data **graph, /* graph data structure */ int size; /* array spacing */ int i, j, k; /* loop counters */ int kl_refine(); - void strout(); + void strout(char *msg); void ch_mergesort(double *vals, int nvals, int *indices, int *space); error = 1; diff --git a/packages/seacas/libraries/chaco/submain/submain.c b/packages/seacas/libraries/chaco/submain/submain.c index c2ba1caa9221..4a21cce9453f 100644 --- a/packages/seacas/libraries/chaco/submain/submain.c +++ b/packages/seacas/libraries/chaco/submain/submain.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -16,11 +16,11 @@ extern void reflect_input(int nvtxs, /* number of vertices in graph */ int nedges, /* number of edges in graph */ int igeom, /* geometric dimension for inertial method */ - char * graphname, /* name of graph input file */ - char * geomname, /* name of geometry input file */ - char * inassignname, /* name of assignment input file */ - char * outassignname, /* name of assignment output file */ - char * outfilename, /* name of information output file */ + char *graphname, /* name of graph input file */ + char *geomname, /* name of geometry input file */ + char *inassignname, /* name of assignment input file */ + char *outassignname, /* name of assignment output file */ + char *outfilename, /* name of information output file */ int architecture, /* 0=> hypercube, d=> d-dimensional mesh */ int ndims_tot, /* total number of cuts to make */ int mesh_dims[3], /* size of mesh */ @@ -31,7 +31,7 @@ extern void reflect_input(int nvtxs, /* number of vertices in graph * int ndims, /* partitioning level */ double eigtol, /* tolerance on eigenvectors */ long seed, /* random number seed */ - FILE * outfile); /* file to write output to */ + FILE *outfile); /* file to write output to */ double *SQRTS; /* precomputed square roots for efficiency */ @@ -52,11 +52,11 @@ int submain(struct vtx_data **graph, /* data structure for graph */ int using_vwgts, /* are vertex weights being used? */ int using_ewgts, /* are edge weights being used? */ int igeom, /* geometry dimension if using inertial method */ - float ** coords, /* coordinates of vertices if used */ - char * outassignname, /* name of assignment output file */ - char * outfilename, /* in which to print output metrics */ - int * assignment, /* set number of each vtx (length n) */ - double * goal, /* desired sizes for each set */ + float **coords, /* coordinates of vertices if used */ + char *outassignname, /* name of assignment output file */ + char *outfilename, /* in which to print output metrics */ + int *assignment, /* set number of each vtx (length n) */ + double *goal, /* desired sizes for each set */ int architecture, /* 0=> hypercube, d=> d-dimensional mesh */ int ndims_tot, /* total number hypercube dimensions */ int mesh_dims[3], /* extent of mesh in 3 directions */ @@ -97,13 +97,13 @@ int submain(struct vtx_data **graph, /* data structure for graph */ extern double kernel_time; /* time spent benchmarking kernels */ extern double count_time; /* time spent evaluating the answer */ extern double print_assign_time; /* time spent writing output file */ - FILE * outfile; /* output file */ + FILE *outfile; /* output file */ struct vtx_data **graph2; /* data structure for graph */ int hop_mtx[MAXSETS][MAXSETS]; /* between-set hop cost for KL */ - double * vwsqrt; /* sqrt of vertex weights (length nvtxs+1) */ + double *vwsqrt; /* sqrt of vertex weights (length nvtxs+1) */ double time, time1; /* timing variables */ - char * graphname, *geomname; /* names of input files */ - char * inassignname; /* name of assignment input file */ + char *graphname, *geomname; /* names of input files */ + char *inassignname; /* name of assignment input file */ int old_nsqrts; /* old value of NSQRTS */ int append; /* append output to existing file? */ int nsets; /* number of sets created by each divide */ @@ -112,14 +112,14 @@ int submain(struct vtx_data **graph, /* data structure for graph */ int flag; /* return code from check_input */ int old_perturb = 0; /* saves original perturbation flag */ int i, j, k; /* loop counters */ - double seconds(); + double seconds(void); void setrandom(long int seed); int check_input(), refine_part(); void connect_enforce(); void makevwsqrt(), balance(), countup(); void force_internal(), sequence(), reflect_input(); void machine_params(), assign_out(), refine_map(); - void time_out(), time_kernels(), strout(); + void time_out(), time_kernels(), strout(char *msg); if (DEBUG_TRACE > 0) { printf("\n"); diff --git a/packages/seacas/libraries/chaco/symmlq/msolve.c b/packages/seacas/libraries/chaco/symmlq/msolve.c index 456e7bc00a8d..d6a909a6f9c6 100644 --- a/packages/seacas/libraries/chaco/symmlq/msolve.c +++ b/packages/seacas/libraries/chaco/symmlq/msolve.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -8,12 +8,12 @@ #include "structs.h" -int msolve(int nvtxs, double *x, double *y) +int msolve(long int *nvtxs, double *x, double *y) { int i; /* Just do a copy for now. */ - for (i = 0; i < nvtxs; i++) { + for (i = 0; i < *nvtxs; i++) { y[i] = x[i]; } diff --git a/packages/seacas/libraries/chaco/symmlq/symmlq.c b/packages/seacas/libraries/chaco/symmlq/symmlq.c index 6fd95aa02b7c..0af0ac6f96b7 100644 --- a/packages/seacas/libraries/chaco/symmlq/symmlq.c +++ b/packages/seacas/libraries/chaco/symmlq/symmlq.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -28,19 +28,20 @@ int symmlq(long int *n, double *b, double *r1, double *r2, double *v, double *w, double d__1, d__2; /* Local variables */ - static double alfa, diag, dbar, beta, gbar, oldb, epsa; - extern double ch_ddot(); - static double gmin, gmax, zbar, epsr, epsx, beta1; - extern double chdnrm2(); - static long int i; - static double gamma, s, t, delta, z, denom; - extern /* Subroutine */ int aprod(); - static double bstep; + static double alfa, diag, dbar, beta, gbar, oldb, epsa; + extern double ch_ddot(long int *n, double *dx, long int *incx, double *dy, long int *incy); + static double gmin, gmax, zbar, epsr, epsx, beta1; + extern double chdnrm2(long int *n, double *dx, long int *incx); + static long int i; + static double gamma, s, t, delta, z, denom; + extern int aprod(long *lnvtxs, double *x, double *y, double *dA, double *vwsqrt, double *work, + double *dorthlist /* vectors to orthogonalize against */); + static double bstep; extern /* Subroutine */ int chdcopy(); static double epsln; extern /* Subroutine */ int chdaxpy(); static double tnorm, cs, ynorm2, sn, cgnorm; - extern /* Subroutine */ int msolve(); + extern /* Subroutine */ int msolve(long int *nvtxs, double *x, double *y); static double snprod, lqnorm, qrnorm, eps, rhs1, rhs2; /* ------------------------------------------------------------------ diff --git a/packages/seacas/libraries/chaco/symmlq/symmlqblas.c b/packages/seacas/libraries/chaco/symmlq/symmlqblas.c index 7fa49670ee46..1744a2c217be 100644 --- a/packages/seacas/libraries/chaco/symmlq/symmlqblas.c +++ b/packages/seacas/libraries/chaco/symmlq/symmlqblas.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -275,9 +275,6 @@ double chdnrm2(long int *n, double *dx, long int *incx) long int i__1, i__2; double ret_val, d__1; - /* Builtin functions */ - double sqrt(); - /* Local variables */ static double xmax; static long int next, i, j, nn; diff --git a/packages/seacas/libraries/chaco/util/randomize.c b/packages/seacas/libraries/chaco/util/randomize.c index 052e9a901d12..2d2a132564f2 100644 --- a/packages/seacas/libraries/chaco/util/randomize.c +++ b/packages/seacas/libraries/chaco/util/randomize.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2020 National Technology & Engineering Solutions + * Copyright(C) 1999-2020, 2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * diff --git a/packages/seacas/libraries/exoIIv2for32/src/exo_jack_32.c b/packages/seacas/libraries/exoIIv2for32/src/exo_jack_32.c index fe2d62969a4a..cc612aaafc62 100644 --- a/packages/seacas/libraries/exoIIv2for32/src/exo_jack_32.c +++ b/packages/seacas/libraries/exoIIv2for32/src/exo_jack_32.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -46,7 +46,7 @@ #if defined(Build64) && !defined(DEFAULT_REAL_INT) /* 64-bit */ -#define real double +#define real double #define entity_id ex_entity_id #ifdef ADDC_ @@ -61,7 +61,7 @@ #else /* 32-bit */ -#define real float +#define real float #define entity_id int #ifdef ADDC_ #define F2C(name, NAME) name##_ @@ -2421,7 +2421,7 @@ void F2C(expfrm, EXPFRM)(int *idexo, int *nframe, void_int *cfids, real *coord, * Routine to return floating point word size * \sa ex__get_cpu_ws() */ -int F2C(excpws, EXCPWS)() { return (ex__get_cpu_ws()); } +int F2C(excpws, EXCPWS)(void) { return (ex__get_cpu_ws()); } /*! * Routine to return large model setting diff --git a/packages/seacas/libraries/exoIIv2for32/test/test.dmp b/packages/seacas/libraries/exoIIv2for32/test/test.dmp index 61f4f9b31147..b8be6a6f953a 100644 --- a/packages/seacas/libraries/exoIIv2for32/test/test.dmp +++ b/packages/seacas/libraries/exoIIv2for32/test/test.dmp @@ -131,7 +131,6 @@ variables: int elem_var_tab(num_el_blk, num_elem_var) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; @@ -151,13 +150,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0 ; eb_names = @@ -306,55 +305,55 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6 ; name_elem_var = diff --git a/packages/seacas/libraries/exoIIv2for32/test/testall.in b/packages/seacas/libraries/exoIIv2for32/test/testall.in index 4ff8560c50ce..cfb531d9e354 100644 --- a/packages/seacas/libraries/exoIIv2for32/test/testall.in +++ b/packages/seacas/libraries/exoIIv2for32/test/testall.in @@ -41,17 +41,17 @@ echo "begin testwt" > test.output ${PREFIX} ${BINDIR}/f32_testwt${SUFFIX} >> test.output ret_status=$((ret_status+$?)) echo "end testwt" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/test.dmp | tee testwt.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v "word_size" | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/test.dmp | tee testwt.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[4]})) # testrd - single precision read test echo "testrd ..." -${PREFIX} ${BINDIR}/f32_testrd${SUFFIX} | grep -v version | grep -v "word size" |${DIFF} - ${SRCDIR}/testrd.dmp | tee testrd.res +${PREFIX} ${BINDIR}/f32_testrd${SUFFIX} | grep -v version | grep -v "word_size" |${DIFF} - ${SRCDIR}/testrd.dmp | tee testrd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) # testrdd - double precision read of single precision file echo "testrdd ..." -${PREFIX} ${BINDIR}/f32_testrdd${SUFFIX} | grep -v version | grep -v "word size" | ${DIFF} - ${SRCDIR}/testrdd.dmp | tee testrdd.res +${PREFIX} ${BINDIR}/f32_testrdd${SUFFIX} | grep -v version | grep -v "word_size" | ${DIFF} - ${SRCDIR}/testrdd.dmp | tee testrdd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) # testwtd - double precision write test @@ -59,17 +59,17 @@ echo "testwtd ..." echo "begin testwtd" >> test.output ${PREFIX} ${BINDIR}/f32_testwtd${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testd.dmp | tee testwtd.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v "word_size" | grep -v _FillValue | ${DIFF} - ${SRCDIR}/testd.dmp | tee testwtd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[4]})) # testrdd - double precision read test echo "testrdd ..." -${PREFIX} ${BINDIR}/f32_testrdd${SUFFIX} | grep -v version | grep -v "word size" | ${DIFF} - ${SRCDIR}/testrdd.dmp | tee testrdd.res +${PREFIX} ${BINDIR}/f32_testrdd${SUFFIX} | grep -v version | grep -v "word_size" | ${DIFF} - ${SRCDIR}/testrdd.dmp | tee testrdd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) # testrd - single precision read of double precision file echo "testrd ..." -${PREFIX} ${BINDIR}/f32_testrd${SUFFIX} | grep -v version | grep -v "word size" | ${DIFF} - ${SRCDIR}/testrd.dmp | tee testrd.res +${PREFIX} ${BINDIR}/f32_testrd${SUFFIX} | grep -v version | grep -v "word_size" | ${DIFF} - ${SRCDIR}/testrd.dmp | tee testrd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "************************************************************************" diff --git a/packages/seacas/libraries/exoIIv2for32/test/testall_i64.in b/packages/seacas/libraries/exoIIv2for32/test/testall_i64.in index d977804319df..c1d11c62dbcb 100644 --- a/packages/seacas/libraries/exoIIv2for32/test/testall_i64.in +++ b/packages/seacas/libraries/exoIIv2for32/test/testall_i64.in @@ -32,13 +32,13 @@ echo "testwt ..." echo "begin testwt" > test.output ${PREFIX} ${BINDIR}/f32_testwt${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/test.dmp | tee testwt.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word_size" | ${DIFF} - ${SRCDIR}/test.dmp | tee testwt.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[4]})) echo "end testwt, status = $ret_status" >> test.output # testrdd - double precision read test with 64-bit integers echo "testrddi64 ..." -${PREFIX} ${BINDIR}/f32_testrddi64${SUFFIX} | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word size" | ${DIFF} - ${SRCDIR}/testrddi64.dmp | tee testrddi64.res +${PREFIX} ${BINDIR}/f32_testrddi64${SUFFIX} | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word_size" | ${DIFF} - ${SRCDIR}/testrddi64.dmp | tee testrddi64.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) # testwtd - double precision write test @@ -46,13 +46,13 @@ echo "testwtd ..." echo "begin testwtd" >> test.output ${PREFIX} ${BINDIR}/f32_testwtd${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testd.dmp | tee testwtd.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word_size" | ${DIFF} - ${SRCDIR}/testd.dmp | tee testwtd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[4]})) echo "end testwtd, status = $ret_status" >> test.output # testrdd - double precision read test with 64-bit integers echo "testrddi64 ..." -${PREFIX} ${BINDIR}/f32_testrddi64${SUFFIX} | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word size" | ${DIFF} - ${SRCDIR}/testrddi64.dmp | tee testrddi64.res +${PREFIX} ${BINDIR}/f32_testrddi64${SUFFIX} | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word_size" | ${DIFF} - ${SRCDIR}/testrddi64.dmp | tee testrddi64.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) # testwtdi64 - double precision write test with 64-bit integers @@ -60,23 +60,23 @@ echo "testwtdi64 ..." echo "begin testwtdi64" >> test.output ${PREFIX} ${BINDIR}/f32_testwtdi64${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testdi64.dmp | tee testwtd.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word_size" | ${DIFF} - ${SRCDIR}/testdi64.dmp | tee testwtd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[4]})) echo "end testwtdi64, status = $ret_status" >> test.output # testrdd - double precision read test with 64-bit integers echo "testrddi64 ..." -${PREFIX} ${BINDIR}/f32_testrddi64${SUFFIX} | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word size" | ${DIFF} - ${SRCDIR}/testrddi64.dmp | tee testrddi64.res +${PREFIX} ${BINDIR}/f32_testrddi64${SUFFIX} | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word_size" | ${DIFF} - ${SRCDIR}/testrddi64.dmp | tee testrddi64.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) # testrdd - double precision read test echo "testrdd ..." -${PREFIX} ${BINDIR}/f32_testrdd${SUFFIX} | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word size" | ${DIFF} - ${SRCDIR}/testrdd.dmp | tee testrdd.res +${PREFIX} ${BINDIR}/f32_testrdd${SUFFIX} | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word_size" | ${DIFF} - ${SRCDIR}/testrdd.dmp | tee testrdd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) # testrd - single precision read of double precision file echo "testrd ..." -${PREFIX} ${BINDIR}/f32_testrd${SUFFIX} | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word size" | ${DIFF} - ${SRCDIR}/testrd.dmp | tee testrd.res +${PREFIX} ${BINDIR}/f32_testrd${SUFFIX} | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v "word_size" | ${DIFF} - ${SRCDIR}/testrd.dmp | tee testrd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) echo "************************************************************************" diff --git a/packages/seacas/libraries/exoIIv2for32/test/testd.dmp b/packages/seacas/libraries/exoIIv2for32/test/testd.dmp index d814217ab260..f73a886e07bf 100644 --- a/packages/seacas/libraries/exoIIv2for32/test/testd.dmp +++ b/packages/seacas/libraries/exoIIv2for32/test/testd.dmp @@ -131,7 +131,6 @@ variables: int elem_var_tab(num_el_blk, num_elem_var) ; // global attributes: - :floating_point_word_size = 8 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; @@ -151,13 +150,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0 ; eb_names = @@ -306,55 +305,55 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6 ; name_elem_var = diff --git a/packages/seacas/libraries/exoIIv2for32/test/testdi64.dmp b/packages/seacas/libraries/exoIIv2for32/test/testdi64.dmp index 7321b8081917..401d3e7fc93e 100644 --- a/packages/seacas/libraries/exoIIv2for32/test/testdi64.dmp +++ b/packages/seacas/libraries/exoIIv2for32/test/testdi64.dmp @@ -131,7 +131,6 @@ variables: int elem_var_tab(num_el_blk, num_elem_var) ; // global attributes: - :floating_point_word_size = 8 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; @@ -151,13 +150,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0 ; eb_names = @@ -306,55 +305,55 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6 ; name_elem_var = diff --git a/packages/seacas/libraries/exoIIv2for32/test/testrd.f b/packages/seacas/libraries/exoIIv2for32/test/testrd.f index 3aec617dca11..3d2d53cc9954 100644 --- a/packages/seacas/libraries/exoIIv2for32/test/testrd.f +++ b/packages/seacas/libraries/exoIIv2for32/test/testrd.f @@ -66,7 +66,6 @@ program testrd write (iout, '("test.exo is an EXODUSII file; version ", 1 f4.2)') vers - write (iout, '(" I/O word size",i2)') io_ws mod_sz = exlgmd(exoid) write (iout, '(" Model Size",i2)') mod_sz @@ -729,4 +728,3 @@ program testrd stop end - diff --git a/packages/seacas/libraries/exoIIv2for32/test/testrdd.f b/packages/seacas/libraries/exoIIv2for32/test/testrdd.f index 74811cdfc2f2..aefab7744493 100644 --- a/packages/seacas/libraries/exoIIv2for32/test/testrdd.f +++ b/packages/seacas/libraries/exoIIv2for32/test/testrdd.f @@ -66,7 +66,6 @@ program testrdd write (iout, '("test.exo is an EXODUSII file; version ", 1 f4.2)') vers - write (iout, '(" I/O word size",i2)') io_ws mod_sz = exlgmd(exoid) write (iout, '(" Model Size",i2)') mod_sz @@ -729,4 +728,3 @@ program testrdd stop end - diff --git a/packages/seacas/libraries/exoIIv2for32/test/testrddi64.f b/packages/seacas/libraries/exoIIv2for32/test/testrddi64.f index 3b749e2a8fdd..8060816f140b 100644 --- a/packages/seacas/libraries/exoIIv2for32/test/testrddi64.f +++ b/packages/seacas/libraries/exoIIv2for32/test/testrddi64.f @@ -71,7 +71,6 @@ program testrdd write (iout, '("test.exo is an EXODUSII file; version ", 1 f4.2)') vers - write (iout, '(" I/O word size",i2)') io_ws mod_sz = exlgmd(exoid) write (iout, '(" Model Size",i2)') mod_sz @@ -734,4 +733,3 @@ program testrdd stop end - diff --git a/packages/seacas/libraries/exodus/CMakeLists.txt b/packages/seacas/libraries/exodus/CMakeLists.txt index da241a3c9c55..62a0c250c563 100644 --- a/packages/seacas/libraries/exodus/CMakeLists.txt +++ b/packages/seacas/libraries/exodus/CMakeLists.txt @@ -10,7 +10,7 @@ INCLUDE_DIRECTORIES( FILE(GLOB SOURCES src/ex_*.c) -if (SEACAS_HIDE_DEPRECATED_CODE OR SEACASProj_HIDE_DEPRECATED_CODE) +if (${SEACAS_HIDE_DEPRECATED_CODE} OR ${CMAKE_PROJECT_NAME}_HIDE_DEPRECATED_CODE) else() FILE(GLOB DEP_SOURCES src/deprecated/ex_*.c) endif() diff --git a/packages/seacas/libraries/exodus/include/exodusII.h b/packages/seacas/libraries/exodus/include/exodusII.h index b4e378ae360f..ae693962c274 100644 --- a/packages/seacas/libraries/exodus/include/exodusII.h +++ b/packages/seacas/libraries/exodus/include/exodusII.h @@ -54,12 +54,12 @@ #endif /* EXODUS version number */ -#define EXODUS_VERSION "8.14" +#define EXODUS_VERSION "8.15" #define EXODUS_VERSION_MAJOR 8 -#define EXODUS_VERSION_MINOR 14 -#define EXODUS_RELEASE_DATE "December 2, 2021" +#define EXODUS_VERSION_MINOR 15 +#define EXODUS_RELEASE_DATE "February 24, 2022" -#define EX_API_VERS 8.14f +#define EX_API_VERS 8.15f #define EX_API_VERS_NODOT (100 * EXODUS_VERSION_MAJOR + EXODUS_VERSION_MINOR) #define EX_VERS EX_API_VERS @@ -811,6 +811,9 @@ EXODUS_EXPORT int ex_get_partial_id_map(int exoid, ex_entity_type map_type, int64_t start_entity_num, int64_t num_entities, void_int *map); +EXODUS_EXPORT int ex_get_block_id_map(int exoid, ex_entity_type map_type, ex_entity_id entity_id, + void_int *map); + EXODUS_EXPORT int ex_put_coordinate_frames(int exoid, int nframes, const void_int *cf_ids, const void *pt_coordinates, const char *tags); diff --git a/packages/seacas/libraries/exodus/src/ex_get_assemblies.c b/packages/seacas/libraries/exodus/src/ex_get_assemblies.c index a58ac913d5ac..c12990d513b5 100644 --- a/packages/seacas/libraries/exodus/src/ex_get_assemblies.c +++ b/packages/seacas/libraries/exodus/src/ex_get_assemblies.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -13,7 +13,7 @@ * writes the assembly parameters and optionally assembly data for all assemblies * assumes that `assembly` is large enough to contain all assemblies. * \param exoid exodus file id - * \param *assembly array of ex_assembly structures + * \param assembly array of ex_assembly structures */ int ex_get_assemblies(int exoid, ex_assembly *assembly) { diff --git a/packages/seacas/libraries/exodus/src/ex_get_block_id_map.c b/packages/seacas/libraries/exodus/src/ex_get_block_id_map.c new file mode 100644 index 000000000000..77363be0291a --- /dev/null +++ b/packages/seacas/libraries/exodus/src/ex_get_block_id_map.c @@ -0,0 +1,103 @@ +/* + * Copyright(C) 2022 National Technology & Engineering Solutions + * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with + * NTESS, the U.S. Government retains certain rights in this software. + * + * See packages/seacas/LICENSE for details + */ +/***************************************************************************** + * + * ex_get_block_id_map + * + * entry conditions - + * input parameters: + * int exoid exodus file id + * int map_type type of map (node, edge, face, element) + * + * exit conditions - + * int* map map + * + *****************************************************************************/ + +#include "exodusII.h" // for ex_err, etc +#include "exodusII_int.h" // for EX_FATAL, EX_NOERR, etc + +/* + * reads the id map for the edge/face/element block with the specified id. + */ + +int ex_get_block_id_map(int exoid, ex_entity_type obj_type, ex_entity_id entity_id, void_int *map) +{ + int status; + char errmsg[MAX_ERR_LENGTH]; + const char *dnument; + ex_entity_type map_type; + + EX_FUNC_ENTER(); + if (ex__check_valid_file_id(exoid, __func__) == EX_FATAL) { + EX_FUNC_LEAVE(EX_FATAL); + } + + /* Determine index of entity_id in id array */ + int blk_id_ndx = ex__id_lkup(exoid, obj_type, entity_id); + if (blk_id_ndx <= 0) { /* Empty block */ + ex_get_err(NULL, NULL, &status); + if (status != 0) { + if (status == EX_NULLENTITY) { /* NULL element block? */ + EX_FUNC_LEAVE(EX_NOERR); + } + snprintf(errmsg, MAX_ERR_LENGTH, + "ERROR: failed to locate %s id %" PRId64 " in id array in file id %d", + ex_name_of_object(obj_type), entity_id, exoid); + ex_err_fn(exoid, __func__, errmsg, status); + EX_FUNC_LEAVE(EX_FATAL); + } + } + + /* At this point, we have a valid block. Determine the number of + entities it and all previous blocks contain. */ + switch (obj_type) { + case EX_EDGE_BLOCK: + dnument = DIM_NUM_ED_IN_EBLK(blk_id_ndx); + map_type = EX_EDGE_MAP; + break; + case EX_FACE_BLOCK: + dnument = DIM_NUM_FA_IN_FBLK(blk_id_ndx); + map_type = EX_FACE_MAP; + break; + case EX_ELEM_BLOCK: + dnument = DIM_NUM_EL_IN_BLK(blk_id_ndx); + map_type = EX_ELEM_MAP; + break; + default: + snprintf(errmsg, MAX_ERR_LENGTH, "Bad block type parameter (%d) specified for file id %d.", + obj_type, exoid); + ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM); + EX_FUNC_LEAVE(EX_FATAL); + } + + size_t offset = 1; + size_t len = 0; + for (int i = 1; i <= blk_id_ndx; i++) { + offset += len; + /* inquire values of some dimensions */ + int dimid = 0; + if ((status = nc_inq_dimid(exoid, dnument, &dimid)) != NC_NOERR) { + snprintf(errmsg, MAX_ERR_LENGTH, + "ERROR: failed to locate number of entities in %s %" PRId64 " in file id %d", + ex_name_of_object(obj_type), entity_id, exoid); + ex_err_fn(exoid, __func__, errmsg, status); + EX_FUNC_LEAVE(EX_FATAL); + } + + if ((status = nc_inq_dimlen(exoid, dimid, &len)) != NC_NOERR) { + snprintf(errmsg, MAX_ERR_LENGTH, + "ERROR: failed to get number of %ss in block %" PRId64 " in file id %d", + ex_name_of_object(obj_type), entity_id, exoid); + ex_err_fn(exoid, __func__, errmsg, status); + EX_FUNC_LEAVE(EX_FATAL); + } + } + EX_FUNC_UNLOCK(); + return ex_get_partial_id_map(exoid, map_type, offset, len, map); +} diff --git a/packages/seacas/libraries/exodus/test/rd_wt_mesh.c b/packages/seacas/libraries/exodus/test/rd_wt_mesh.c index 18502c5ba281..1499f864aebf 100644 --- a/packages/seacas/libraries/exodus/test/rd_wt_mesh.c +++ b/packages/seacas/libraries/exodus/test/rd_wt_mesh.c @@ -66,7 +66,7 @@ int write_exo_mesh(char *file_name, int rank, int num_dim, int num_domains, int int *node_map, int num_elems, int *elem_map, realtyp *x_coords, realtyp *y_coords, realtyp *z_coords, int *connect, int close_files); -double my_timer() +double my_timer(void) { #ifdef PARALLEL_AWARE_EXODUS double t1 = MPI_Wtime(); diff --git a/packages/seacas/libraries/exodus/test/test-compress.dmp b/packages/seacas/libraries/exodus/test/test-compress.dmp index ebb02ec215f2..f328e6d946b7 100644 --- a/packages/seacas/libraries/exodus/test/test-compress.dmp +++ b/packages/seacas/libraries/exodus/test/test-compress.dmp @@ -2,7 +2,7 @@ coordy:_DeflateLevel = 1 ; coordz:_DeflateLevel = 1 ; nattrb:_DeflateLevel = 1 ; - elem_map:_DeflateLevel = 1 ; + elem_num_map:_DeflateLevel = 1 ; attrib1:_DeflateLevel = 1 ; connect1:_DeflateLevel = 1 ; attrib2:_DeflateLevel = 1 ; diff --git a/packages/seacas/libraries/exodus/test/test-empty.c b/packages/seacas/libraries/exodus/test/test-empty.c index e3a386a24c83..142433fe9b60 100644 --- a/packages/seacas/libraries/exodus/test/test-empty.c +++ b/packages/seacas/libraries/exodus/test/test-empty.c @@ -9,7 +9,7 @@ #include #include -int main() +int main(int argc, char **argv) { float version = 0.0; diff --git a/packages/seacas/libraries/exodus/test/test.dmp b/packages/seacas/libraries/exodus/test/test.dmp index 081b61b02552..884d72209a6d 100644 --- a/packages/seacas/libraries/exodus/test/test.dmp +++ b/packages/seacas/libraries/exodus/test/test.dmp @@ -70,7 +70,7 @@ variables: char coor_names(num_dim, len_name) ; float nattrb(num_nodes, num_att_in_nblk) ; char nattrib_name(num_att_in_nblk, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; float attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -182,7 +182,6 @@ variables: float vals_nset_var3ns2(time_step, num_nod_ns2) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :title = "This is a test" ; data: @@ -201,13 +200,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0, 2.7, 6, 5.7, 3.7, 0, 10, 10 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2, 1.7, 1.7, 1.7, 0, 0, 0, 10 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0, 2.7, 3.3, 1.7, 2.3, 0, 0, 10 ; eb_names = @@ -274,7 +273,7 @@ data: "Node_attr_1", "Node_attr_2" ; - elem_map = 1, 2, 3, 4, 5, 6, 7 ; + elem_num_map = 10, 20, 30, 40, 50, 60, 70 ; attrib1 = 3.1416 ; @@ -426,67 +425,67 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, - 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, 1.54, 1.56, 1.58, 1.6, 1.62, 1.64, 1.66, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, 1.81, 1.84, 1.87, 1.9, 1.93, 1.96, 1.99, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, - 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, - 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, - 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, 2.62, 2.68, 2.74, 2.8, 2.86, 2.92, 2.98, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, 2.89, 2.96, 3.03, 3.1, 3.17, 3.24, 3.31, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, - 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, 3.16, 3.24, 3.32, 3.4, 3.48, 3.56, 3.64, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, 3.43, 3.52, 3.61, 3.7, 3.79, 3.88, 3.97, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, - 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, - 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, 2.54, 2.56, 2.58, 2.6, 2.62, 2.64, 2.66, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, 2.81, 2.84, 2.87, 2.9, 2.93, 2.96, 2.99, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, - 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, 3.08, 3.12, 3.16, 3.2, 3.24, 3.28, 3.32, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, - 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, 3.62, 3.68, 3.74, 3.8, 3.86, 3.92, 3.98, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, 3.89, 3.96, 4.03, 4.1, 4.17, 4.24, 4.31, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, - 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, 4.16, 4.24, 4.32, 4.4, 4.48, 4.56, 4.64, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, 4.43, 4.52, 4.61, 4.7, 4.79, 4.88, 4.97, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, - 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3 ; name_elem_var = diff --git a/packages/seacas/libraries/exodus/test/test1.dmp b/packages/seacas/libraries/exodus/test/test1.dmp index a69b04daa814..4be33e53b48e 100644 --- a/packages/seacas/libraries/exodus/test/test1.dmp +++ b/packages/seacas/libraries/exodus/test/test1.dmp @@ -165,7 +165,6 @@ variables: float vals_elem_var3eb7(time_step, num_el_in_blk7) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is testwt1" ; @@ -185,13 +184,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 100, 50, 3, 6, 0, 3, 6, 0 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 100, 50, 0, 0, 0, 2, 2, 2 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 0, 20, 6, 0, 0, 6, 2, 0 ; eb_names = @@ -224,7 +223,7 @@ data: nmap_names = "Node_Map_111" ; - node_map1 = 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, + node_map1 = 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84 ; em_prop1 = 111, 222 ; @@ -399,65 +398,65 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, - 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, 1.54, 1.56, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, 1.81, 1.84, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, - 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, 2.08, 2.12, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, - 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, - 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, 2.62, 2.68, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, 2.89, 2.96, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, - 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, 3.16, 3.24, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, 3.43, 3.52, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, - 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, 2.54, 2.56, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, 2.81, 2.84, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, - 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, 3.08, 3.12, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, - 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, 3.62, 3.68, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, 3.89, 3.96, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, - 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, 4.16, 4.24, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, 4.43, 4.52, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8 ; name_elem_var = diff --git a/packages/seacas/libraries/exodus/test/test2-1.dmp b/packages/seacas/libraries/exodus/test/test2-1.dmp index f9b81846a985..14c1cbb26b02 100644 --- a/packages/seacas/libraries/exodus/test/test2-1.dmp +++ b/packages/seacas/libraries/exodus/test/test2-1.dmp @@ -58,7 +58,7 @@ variables: char ns_names(num_node_sets, len_name) ; char ss_names(num_side_sets, len_name) ; char coor_names(num_dim, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; float attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -131,10 +131,8 @@ variables: int elem_var_tab(num_el_blk, num_elem_var) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; - :int64_status = 0 ; :title = "This is a test" ; data: @@ -152,13 +150,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0 ; eb_names = @@ -184,7 +182,7 @@ data: "ycoor", "zcoor" ; - elem_map = 1, 2, 3, 4, 5 ; + elem_num_map = 1, 2, 3, 4, 5 ; attrib1 = 3.1416 ; @@ -308,55 +306,55 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6 ; name_elem_var = diff --git a/packages/seacas/libraries/exodus/test/test2-2.dmp b/packages/seacas/libraries/exodus/test/test2-2.dmp index 1271398f0a62..2664e8a2aa52 100644 --- a/packages/seacas/libraries/exodus/test/test2-2.dmp +++ b/packages/seacas/libraries/exodus/test/test2-2.dmp @@ -58,7 +58,7 @@ variables: char ns_names(num_node_sets, len_name) ; char ss_names(num_side_sets, len_name) ; char coor_names(num_dim, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; float attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -131,7 +131,6 @@ variables: int elem_var_tab(num_el_blk, num_elem_var) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is test 2" ; @@ -151,13 +150,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0 ; eb_names = @@ -183,7 +182,7 @@ data: "ycoor", "zcoor" ; - elem_map = 1, 2, 3, 4, 5 ; + elem_num_map = 1, 2, 3, 4, 5 ; attrib1 = 3 ; @@ -307,55 +306,55 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6 ; name_elem_var = diff --git a/packages/seacas/libraries/exodus/test/test2.dmp b/packages/seacas/libraries/exodus/test/test2.dmp index 483ca96f99dd..8c724727752f 100644 --- a/packages/seacas/libraries/exodus/test/test2.dmp +++ b/packages/seacas/libraries/exodus/test/test2.dmp @@ -55,7 +55,7 @@ variables: char ns_names(num_node_sets, len_name) ; char ss_names(num_side_sets, len_name) ; char coor_names(num_dim, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; float attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -110,10 +110,8 @@ variables: char info_records(num_info, len_line) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; - :int64_status = 0 ; :title = "This is a test" ; data: @@ -129,13 +127,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0 ; eb_names = @@ -161,7 +159,7 @@ data: "ycoor", "zcoor" ; - elem_map = 1, 2, 3, 4, 5 ; + elem_num_map = 1, 2, 3, 4, 5 ; attrib1 = 3.1416 ; diff --git a/packages/seacas/libraries/exodus/test/test_clb.dmp b/packages/seacas/libraries/exodus/test/test_clb.dmp index 083ccab76888..fa8a10f89e5b 100644 --- a/packages/seacas/libraries/exodus/test/test_clb.dmp +++ b/packages/seacas/libraries/exodus/test/test_clb.dmp @@ -68,7 +68,7 @@ variables: char coor_names(num_dim, len_name) ; char qa_records(num_qa_rec, four, len_string) ; char info_records(num_info, len_line) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; connect1:elem_type = "quad" ; char attrib_name1(num_att_in_blk1, len_name) ; @@ -178,7 +178,6 @@ variables: int sset_var_tab(num_side_sets, num_sset_var) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; @@ -198,13 +197,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0, 2.7, 6, 5.7, 3.7, 0, 10, 10 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2, 1.7, 1.7, 1.7, 0, 0, 0, 10 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0, 2.7, 3.3, 1.7, 2.3, 0, 0, 10 ; eb_names = @@ -247,7 +246,7 @@ data: "", " " ; - elem_map = 1, 2, 3, 4, 5, 6, 7 ; + elem_num_map = 1, 2, 3, 4, 5, 6, 7 ; connect1 = 1, 2, 3, 4 ; @@ -370,67 +369,67 @@ data: "glo_vars" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, - 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, 1.54, 1.56, 1.58, 1.6, 1.62, 1.64, 1.66, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, 1.81, 1.84, 1.87, 1.9, 1.93, 1.96, 1.99, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, - 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, - 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, - 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, 2.62, 2.68, 2.74, 2.8, 2.86, 2.92, 2.98, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, 2.89, 2.96, 3.03, 3.1, 3.17, 3.24, 3.31, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, - 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, 3.16, 3.24, 3.32, 3.4, 3.48, 3.56, 3.64, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, 3.43, 3.52, 3.61, 3.7, 3.79, 3.88, 3.97, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, - 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, - 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, 2.54, 2.56, 2.58, 2.6, 2.62, 2.64, 2.66, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, 2.81, 2.84, 2.87, 2.9, 2.93, 2.96, 2.99, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, - 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, 3.08, 3.12, 3.16, 3.2, 3.24, 3.28, 3.32, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, - 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, 3.62, 3.68, 3.74, 3.8, 3.86, 3.92, 3.98, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, 3.89, 3.96, 4.03, 4.1, 4.17, 4.24, 4.31, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, - 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, 4.16, 4.24, 4.32, 4.4, 4.48, 4.56, 4.64, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, 4.43, 4.52, 4.61, 4.7, 4.79, 4.88, 4.97, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, - 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3 ; name_nod_var = diff --git a/packages/seacas/libraries/exodus/test/test_ts_files.c b/packages/seacas/libraries/exodus/test/test_ts_files.c index d86390a67b84..4c6c59e38f83 100644 --- a/packages/seacas/libraries/exodus/test/test_ts_files.c +++ b/packages/seacas/libraries/exodus/test/test_ts_files.c @@ -262,11 +262,11 @@ void *init_file(void *varg) elem_map = (int *)calloc(num_elem, sizeof(int)); for (i = 1; i <= num_elem; i++) { - elem_map[i - 1] = i; + elem_map[i - 1] = i * 10; } - error = ex_put_map(exoid, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); if (error) { ex_close(exoid); diff --git a/packages/seacas/libraries/exodus/test/test_ts_nvar.dmp b/packages/seacas/libraries/exodus/test/test_ts_nvar.dmp index aad5b6faa1b0..f17d47117b0a 100644 --- a/packages/seacas/libraries/exodus/test/test_ts_nvar.dmp +++ b/packages/seacas/libraries/exodus/test/test_ts_nvar.dmp @@ -22,32 +22,31 @@ variables: float vals_nod_var8(time_step, num_nodes) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :title = "This is a test" ; data: time_whole = 0 ; - coordx = 1, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, - 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, - 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, - 1.36, 1.37, 1.38, 1.39, 1.4, 1.41, 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, - 1.48, 1.49, 1.5, 1.51, 1.52, 1.53, 1.54, 1.55, 1.56, 1.57, 1.58, 1.59, + coordx = 1, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, + 1.12, 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, + 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, + 1.36, 1.37, 1.38, 1.39, 1.4, 1.41, 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, + 1.48, 1.49, 1.5, 1.51, 1.52, 1.53, 1.54, 1.55, 1.56, 1.57, 1.58, 1.59, 1.6, 1.61, 1.62, 1.63 ; - coordy = 2, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, - 2.12, 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, - 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, 2.34, 2.35, - 2.36, 2.37, 2.38, 2.39, 2.4, 2.41, 2.42, 2.43, 2.44, 2.45, 2.46, 2.47, - 2.48, 2.49, 2.5, 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, + coordy = 2, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, + 2.12, 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, + 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, 2.34, 2.35, + 2.36, 2.37, 2.38, 2.39, 2.4, 2.41, 2.42, 2.43, 2.44, 2.45, 2.46, 2.47, + 2.48, 2.49, 2.5, 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, 2.6, 2.61, 2.62, 2.63 ; - coordz = 3, 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.1, 3.11, - 3.12, 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.2, 3.21, 3.22, 3.23, - 3.24, 3.25, 3.26, 3.27, 3.28, 3.29, 3.3, 3.31, 3.32, 3.33, 3.34, 3.35, - 3.36, 3.37, 3.38, 3.39, 3.4, 3.41, 3.42, 3.43, 3.44, 3.45, 3.46, 3.47, - 3.48, 3.49, 3.5, 3.51, 3.52, 3.53, 3.54, 3.55, 3.56, 3.57, 3.58, 3.59, + coordz = 3, 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.1, 3.11, + 3.12, 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.2, 3.21, 3.22, 3.23, + 3.24, 3.25, 3.26, 3.27, 3.28, 3.29, 3.3, 3.31, 3.32, 3.33, 3.34, 3.35, + 3.36, 3.37, 3.38, 3.39, 3.4, 3.41, 3.42, 3.43, 3.44, 3.45, 3.46, 3.47, + 3.48, 3.49, 3.5, 3.51, 3.52, 3.53, 3.54, 3.55, 3.56, 3.57, 3.58, 3.59, 3.6, 3.61, 3.62, 3.63 ; coor_names = @@ -66,66 +65,66 @@ data: "NodalVar8" ; vals_nod_var1 = - 1, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, - 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, 1.36, - 1.37, 1.38, 1.39, 1.4, 1.41, 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, 1.48, - 1.49, 1.5, 1.51, 1.52, 1.53, 1.54, 1.55, 1.56, 1.57, 1.58, 1.59, 1.6, + 1, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, 1.36, + 1.37, 1.38, 1.39, 1.4, 1.41, 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, 1.48, + 1.49, 1.5, 1.51, 1.52, 1.53, 1.54, 1.55, 1.56, 1.57, 1.58, 1.59, 1.6, 1.61, 1.62, 1.63 ; vals_nod_var2 = - 2, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, - 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, 2.34, 2.35, 2.36, - 2.37, 2.38, 2.39, 2.4, 2.41, 2.42, 2.43, 2.44, 2.45, 2.46, 2.47, 2.48, - 2.49, 2.5, 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, 2.6, + 2, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, 2.34, 2.35, 2.36, + 2.37, 2.38, 2.39, 2.4, 2.41, 2.42, 2.43, 2.44, 2.45, 2.46, 2.47, 2.48, + 2.49, 2.5, 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, 2.6, 2.61, 2.62, 2.63 ; vals_nod_var3 = - 3, 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.1, 3.11, 3.12, - 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.2, 3.21, 3.22, 3.23, 3.24, - 3.25, 3.26, 3.27, 3.28, 3.29, 3.3, 3.31, 3.32, 3.33, 3.34, 3.35, 3.36, - 3.37, 3.38, 3.39, 3.4, 3.41, 3.42, 3.43, 3.44, 3.45, 3.46, 3.47, 3.48, - 3.49, 3.5, 3.51, 3.52, 3.53, 3.54, 3.55, 3.56, 3.57, 3.58, 3.59, 3.6, + 3, 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.1, 3.11, 3.12, + 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.2, 3.21, 3.22, 3.23, 3.24, + 3.25, 3.26, 3.27, 3.28, 3.29, 3.3, 3.31, 3.32, 3.33, 3.34, 3.35, 3.36, + 3.37, 3.38, 3.39, 3.4, 3.41, 3.42, 3.43, 3.44, 3.45, 3.46, 3.47, 3.48, + 3.49, 3.5, 3.51, 3.52, 3.53, 3.54, 3.55, 3.56, 3.57, 3.58, 3.59, 3.6, 3.61, 3.62, 3.63 ; vals_nod_var4 = - 4, 4.01, 4.02, 4.03, 4.04, 4.05, 4.06, 4.07, 4.08, 4.09, 4.1, 4.11, 4.12, - 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.2, 4.21, 4.22, 4.23, 4.24, - 4.25, 4.26, 4.27, 4.28, 4.29, 4.3, 4.31, 4.32, 4.33, 4.34, 4.35, 4.36, - 4.37, 4.38, 4.39, 4.4, 4.41, 4.42, 4.43, 4.44, 4.45, 4.46, 4.47, 4.48, - 4.49, 4.5, 4.51, 4.52, 4.53, 4.54, 4.55, 4.56, 4.57, 4.58, 4.59, 4.6, + 4, 4.01, 4.02, 4.03, 4.04, 4.05, 4.06, 4.07, 4.08, 4.09, 4.1, 4.11, 4.12, + 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.2, 4.21, 4.22, 4.23, 4.24, + 4.25, 4.26, 4.27, 4.28, 4.29, 4.3, 4.31, 4.32, 4.33, 4.34, 4.35, 4.36, + 4.37, 4.38, 4.39, 4.4, 4.41, 4.42, 4.43, 4.44, 4.45, 4.46, 4.47, 4.48, + 4.49, 4.5, 4.51, 4.52, 4.53, 4.54, 4.55, 4.56, 4.57, 4.58, 4.59, 4.6, 4.61, 4.62, 4.63 ; vals_nod_var5 = - 5, 5.01, 5.02, 5.03, 5.04, 5.05, 5.06, 5.07, 5.08, 5.09, 5.1, 5.11, 5.12, - 5.13, 5.14, 5.15, 5.16, 5.17, 5.18, 5.19, 5.2, 5.21, 5.22, 5.23, 5.24, - 5.25, 5.26, 5.27, 5.28, 5.29, 5.3, 5.31, 5.32, 5.33, 5.34, 5.35, 5.36, - 5.37, 5.38, 5.39, 5.4, 5.41, 5.42, 5.43, 5.44, 5.45, 5.46, 5.47, 5.48, - 5.49, 5.5, 5.51, 5.52, 5.53, 5.54, 5.55, 5.56, 5.57, 5.58, 5.59, 5.6, + 5, 5.01, 5.02, 5.03, 5.04, 5.05, 5.06, 5.07, 5.08, 5.09, 5.1, 5.11, 5.12, + 5.13, 5.14, 5.15, 5.16, 5.17, 5.18, 5.19, 5.2, 5.21, 5.22, 5.23, 5.24, + 5.25, 5.26, 5.27, 5.28, 5.29, 5.3, 5.31, 5.32, 5.33, 5.34, 5.35, 5.36, + 5.37, 5.38, 5.39, 5.4, 5.41, 5.42, 5.43, 5.44, 5.45, 5.46, 5.47, 5.48, + 5.49, 5.5, 5.51, 5.52, 5.53, 5.54, 5.55, 5.56, 5.57, 5.58, 5.59, 5.6, 5.61, 5.62, 5.63 ; vals_nod_var6 = - 6, 6.01, 6.02, 6.03, 6.04, 6.05, 6.06, 6.07, 6.08, 6.09, 6.1, 6.11, 6.12, - 6.13, 6.14, 6.15, 6.16, 6.17, 6.18, 6.19, 6.2, 6.21, 6.22, 6.23, 6.24, - 6.25, 6.26, 6.27, 6.28, 6.29, 6.3, 6.31, 6.32, 6.33, 6.34, 6.35, 6.36, - 6.37, 6.38, 6.39, 6.4, 6.41, 6.42, 6.43, 6.44, 6.45, 6.46, 6.47, 6.48, - 6.49, 6.5, 6.51, 6.52, 6.53, 6.54, 6.55, 6.56, 6.57, 6.58, 6.59, 6.6, + 6, 6.01, 6.02, 6.03, 6.04, 6.05, 6.06, 6.07, 6.08, 6.09, 6.1, 6.11, 6.12, + 6.13, 6.14, 6.15, 6.16, 6.17, 6.18, 6.19, 6.2, 6.21, 6.22, 6.23, 6.24, + 6.25, 6.26, 6.27, 6.28, 6.29, 6.3, 6.31, 6.32, 6.33, 6.34, 6.35, 6.36, + 6.37, 6.38, 6.39, 6.4, 6.41, 6.42, 6.43, 6.44, 6.45, 6.46, 6.47, 6.48, + 6.49, 6.5, 6.51, 6.52, 6.53, 6.54, 6.55, 6.56, 6.57, 6.58, 6.59, 6.6, 6.61, 6.62, 6.63 ; vals_nod_var7 = - 7, 7.01, 7.02, 7.03, 7.04, 7.05, 7.06, 7.07, 7.08, 7.09, 7.1, 7.11, 7.12, - 7.13, 7.14, 7.15, 7.16, 7.17, 7.18, 7.19, 7.2, 7.21, 7.22, 7.23, 7.24, - 7.25, 7.26, 7.27, 7.28, 7.29, 7.3, 7.31, 7.32, 7.33, 7.34, 7.35, 7.36, - 7.37, 7.38, 7.39, 7.4, 7.41, 7.42, 7.43, 7.44, 7.45, 7.46, 7.47, 7.48, - 7.49, 7.5, 7.51, 7.52, 7.53, 7.54, 7.55, 7.56, 7.57, 7.58, 7.59, 7.6, + 7, 7.01, 7.02, 7.03, 7.04, 7.05, 7.06, 7.07, 7.08, 7.09, 7.1, 7.11, 7.12, + 7.13, 7.14, 7.15, 7.16, 7.17, 7.18, 7.19, 7.2, 7.21, 7.22, 7.23, 7.24, + 7.25, 7.26, 7.27, 7.28, 7.29, 7.3, 7.31, 7.32, 7.33, 7.34, 7.35, 7.36, + 7.37, 7.38, 7.39, 7.4, 7.41, 7.42, 7.43, 7.44, 7.45, 7.46, 7.47, 7.48, + 7.49, 7.5, 7.51, 7.52, 7.53, 7.54, 7.55, 7.56, 7.57, 7.58, 7.59, 7.6, 7.61, 7.62, 7.63 ; vals_nod_var8 = - 8, 8.01, 8.02, 8.03, 8.04, 8.05, 8.06, 8.07, 8.08, 8.09, 8.1, 8.11, 8.12, - 8.13, 8.14, 8.15, 8.16, 8.17, 8.18, 8.19, 8.2, 8.21, 8.22, 8.23, 8.24, - 8.25, 8.26, 8.27, 8.28, 8.29, 8.3, 8.31, 8.32, 8.33, 8.34, 8.35, 8.36, - 8.37, 8.38, 8.39, 8.4, 8.41, 8.42, 8.43, 8.44, 8.45, 8.46, 8.47, 8.48, - 8.49, 8.5, 8.51, 8.52, 8.53, 8.54, 8.55, 8.56, 8.57, 8.58, 8.59, 8.6, + 8, 8.01, 8.02, 8.03, 8.04, 8.05, 8.06, 8.07, 8.08, 8.09, 8.1, 8.11, 8.12, + 8.13, 8.14, 8.15, 8.16, 8.17, 8.18, 8.19, 8.2, 8.21, 8.22, 8.23, 8.24, + 8.25, 8.26, 8.27, 8.28, 8.29, 8.3, 8.31, 8.32, 8.33, 8.34, 8.35, 8.36, + 8.37, 8.38, 8.39, 8.4, 8.41, 8.42, 8.43, 8.44, 8.45, 8.46, 8.47, 8.48, + 8.49, 8.5, 8.51, 8.52, 8.53, 8.54, 8.55, 8.56, 8.57, 8.58, 8.59, 8.6, 8.61, 8.62, 8.63 ; } diff --git a/packages/seacas/libraries/exodus/test/test_ts_partial_nvar.dmp b/packages/seacas/libraries/exodus/test/test_ts_partial_nvar.dmp index 8da7fa09eb33..743ab1fbe4d5 100644 --- a/packages/seacas/libraries/exodus/test/test_ts_partial_nvar.dmp +++ b/packages/seacas/libraries/exodus/test/test_ts_partial_nvar.dmp @@ -18,32 +18,31 @@ variables: float vals_nod_var4(time_step, num_nodes) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :title = "This is a test" ; data: time_whole = 0 ; - coordx = 0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, - 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, - 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, - 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, - 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, + coordx = 0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, + 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, + 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, + 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, + 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63 ; - coordy = 0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, - 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, - 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, - 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, - 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, + coordy = 0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, + 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, + 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, + 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, + 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63 ; - coordz = 0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, - 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, - 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, - 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, - 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, + coordz = 0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, + 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, + 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, + 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47, + 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63 ; coor_names = @@ -58,34 +57,34 @@ data: "NodalVar4" ; vals_nod_var1 = - 1, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, - 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, 1.36, - 1.37, 1.38, 1.39, 1.4, 1.41, 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, 1.48, - 1.49, 1.5, 1.51, 1.52, 1.53, 1.54, 1.55, 1.56, 1.57, 1.58, 1.59, 1.6, + 1, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, 1.34, 1.35, 1.36, + 1.37, 1.38, 1.39, 1.4, 1.41, 1.42, 1.43, 1.44, 1.45, 1.46, 1.47, 1.48, + 1.49, 1.5, 1.51, 1.52, 1.53, 1.54, 1.55, 1.56, 1.57, 1.58, 1.59, 1.6, 1.61, 1.62, 1.63 ; vals_nod_var2 = - 2, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, - 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, 2.34, 2.35, 2.36, - 2.37, 2.38, 2.39, 2.4, 2.41, 2.42, 2.43, 2.44, 2.45, 2.46, 2.47, 2.48, - 2.49, 2.5, 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, 2.6, + 2, 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, 2.34, 2.35, 2.36, + 2.37, 2.38, 2.39, 2.4, 2.41, 2.42, 2.43, 2.44, 2.45, 2.46, 2.47, 2.48, + 2.49, 2.5, 2.51, 2.52, 2.53, 2.54, 2.55, 2.56, 2.57, 2.58, 2.59, 2.6, 2.61, 2.62, 2.63 ; vals_nod_var3 = - 3, 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.1, 3.11, 3.12, - 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.2, 3.21, 3.22, 3.23, 3.24, - 3.25, 3.26, 3.27, 3.28, 3.29, 3.3, 3.31, 3.32, 3.33, 3.34, 3.35, 3.36, - 3.37, 3.38, 3.39, 3.4, 3.41, 3.42, 3.43, 3.44, 3.45, 3.46, 3.47, 3.48, - 3.49, 3.5, 3.51, 3.52, 3.53, 3.54, 3.55, 3.56, 3.57, 3.58, 3.59, 3.6, + 3, 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.1, 3.11, 3.12, + 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.2, 3.21, 3.22, 3.23, 3.24, + 3.25, 3.26, 3.27, 3.28, 3.29, 3.3, 3.31, 3.32, 3.33, 3.34, 3.35, 3.36, + 3.37, 3.38, 3.39, 3.4, 3.41, 3.42, 3.43, 3.44, 3.45, 3.46, 3.47, 3.48, + 3.49, 3.5, 3.51, 3.52, 3.53, 3.54, 3.55, 3.56, 3.57, 3.58, 3.59, 3.6, 3.61, 3.62, 3.63 ; vals_nod_var4 = - 4, 4.01, 4.02, 4.03, 4.04, 4.05, 4.06, 4.07, 4.08, 4.09, 4.1, 4.11, 4.12, - 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.2, 4.21, 4.22, 4.23, 4.24, - 4.25, 4.26, 4.27, 4.28, 4.29, 4.3, 4.31, 4.32, 4.33, 4.34, 4.35, 4.36, - 4.37, 4.38, 4.39, 4.4, 4.41, 4.42, 4.43, 4.44, 4.45, 4.46, 4.47, 4.48, - 4.49, 4.5, 4.51, 4.52, 4.53, 4.54, 4.55, 4.56, 4.57, 4.58, 4.59, 4.6, + 4, 4.01, 4.02, 4.03, 4.04, 4.05, 4.06, 4.07, 4.08, 4.09, 4.1, 4.11, 4.12, + 4.13, 4.14, 4.15, 4.16, 4.17, 4.18, 4.19, 4.2, 4.21, 4.22, 4.23, 4.24, + 4.25, 4.26, 4.27, 4.28, 4.29, 4.3, 4.31, 4.32, 4.33, 4.34, 4.35, 4.36, + 4.37, 4.38, 4.39, 4.4, 4.41, 4.42, 4.43, 4.44, 4.45, 4.46, 4.47, 4.48, + 4.49, 4.5, 4.51, 4.52, 4.53, 4.54, 4.55, 4.56, 4.57, 4.58, 4.59, 4.6, 4.61, 4.62, 4.63 ; } diff --git a/packages/seacas/libraries/exodus/test/testall.in b/packages/seacas/libraries/exodus/test/testall.in index 32bca7010b14..a0edf9a4cb00 100755 --- a/packages/seacas/libraries/exodus/test/testall.in +++ b/packages/seacas/libraries/exodus/test/testall.in @@ -2,7 +2,7 @@ # Copyright(C) 1999-2021 National Technology & Engineering Solutions # of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with # NTESS, the U.S. Government retains certain rights in this software. -# +# # See packages/seacas/LICENSE for details # script to run all tests and compare them to saved dump files. @@ -40,7 +40,7 @@ echo "begin testwt" > test.output ${PREFIX} ${BINDIR}/testwt${SUFFIX} >> test.output ret_status=$((ret_status+$?)) # Filter out the "maximum_name_length" attribute. Moves around in ncdump output for nc4 vs nc3 -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee testwt.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee testwt.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) echo "end testwt, status = $ret_status" >> test.output @@ -54,7 +54,7 @@ echo "testcp_ss - single-to-single precision copy test..." echo "begin testcp_ss" >> test.output ${PREFIX} ${BINDIR}/testcp${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 testcp.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testcp_ss.dmp | tee testcp_ss.res +${NCDUMP} -d5,5 testcp.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testcp_ss.dmp | tee testcp_ss.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testcp_ss, status = $ret_status" >> test.output @@ -62,7 +62,7 @@ echo "testcp_sd - single-to-double precision copy test..." echo "begin testcp_sd" >> test.output ${PREFIX} ${BINDIR}/testcpd${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 testcpd.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testcp_sd.dmp | tee testcp_sd.res +${NCDUMP} -d5,5 testcpd.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testcp_sd.dmp | tee testcp_sd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testcp_sd, status = $ret_status" >> test.output @@ -70,7 +70,7 @@ echo "testcp_nl - normal_model to large_model single precision copy test..." echo "begin testcp_nl" >> test.output ${PREFIX} ${BINDIR}/testcp_nl${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 testcp_nl.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testcp_nl.dmp | tee testcp_nl.res +${NCDUMP} -d5,5 testcp_nl.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testcp_nl.dmp | tee testcp_nl.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testcp_nl, status = $ret_status" >> test.output @@ -78,7 +78,7 @@ echo "testcp_transient - copy mesh and transient data..." echo "begin testcp_tran" >> test.output ${PREFIX} ${BINDIR}/testcp_tran${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 testcp.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testcp_tran.dmp | tee testcp_tran.res +${NCDUMP} -d5,5 testcp.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testcp_tran.dmp | tee testcp_tran.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testcp_tran, status = $ret_status" >> test.output @@ -86,7 +86,7 @@ echo "testwt_clb - single precision write test using concatenated puts..." echo "begin testwt_clb" >> test.output ${PREFIX} ${BINDIR}/testwt_clb${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/test_clb.dmp | tee testwt_clb.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/test_clb.dmp | tee testwt_clb.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testwt_clb, status = $ret_status" >> test.output @@ -94,7 +94,7 @@ echo "testwtd - double precision write test..." echo "begin testwtd" >> test.output ${PREFIX} ${BINDIR}/testwtd${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testd.dmp | tee testwtd.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testd.dmp | tee testwtd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testwtd, status = $ret_status" >> test.output @@ -108,7 +108,7 @@ echo "testcp_dd - double-to-double precision copy test..." echo "begin testcp_dd" >> test.output ${PREFIX} ${BINDIR}/testcpd${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 testcpd.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testcp_dd.dmp | tee testcp_dd.res +${NCDUMP} -d5,5 testcpd.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testcp_dd.dmp | tee testcp_dd.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testcp_dd, status = $ret_status" >> test.output @@ -116,7 +116,7 @@ echo "testcp_ds - double-to-single precision copy test..." echo "begin testcp_ds" >> test.output ${PREFIX} ${BINDIR}/testcp${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 testcp.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testcp_ds.dmp | tee testcp_ds.res +${NCDUMP} -d5,5 testcp.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testcp_ds.dmp | tee testcp_ds.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testcp_ds, status = $ret_status" >> test.output @@ -125,7 +125,7 @@ echo "testwt1 ... [Expect WEDGE6 warning from this test]" echo "begin testwt1" >> test.output ${PREFIX} ${BINDIR}/testwt1${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/test1.dmp | tee testwt1.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/test1.dmp | tee testwt1.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testwt1, status = $ret_status" >> test.output @@ -142,7 +142,7 @@ echo "testwt_ss ... [Expect WEDGE6 warning from this test]" echo "begin testwt_ss" >> test.output ${PREFIX} ${BINDIR}/testwt_ss${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testwt_ss.dmp | tee testwt_ss.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testwt_ss.dmp | tee testwt_ss.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testwt_ss, status = $ret_status" >> test.output @@ -157,9 +157,9 @@ echo "testwt2 - single precision write 2 files (simultaneously open) test..." echo "begin testwt2" >> test.output ${PREFIX} ${BINDIR}/testwt2${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/test2-1.dmp | tee testwt2-1.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/test2-1.dmp | tee testwt2-1.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) -${NCDUMP} -d5,5 test2.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/test2-2.dmp | tee testwt2-2.res +${NCDUMP} -d5,5 test2.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/test2-2.dmp | tee testwt2-2.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testwt2, status = $ret_status" >> test.output @@ -167,7 +167,7 @@ echo "testrdwt - read from one and write to another (simultaneously open) file.. echo "begin testrdwt" >> test.output ${PREFIX} ${BINDIR}/testrdwt${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test2.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/test2.dmp | tee testrdwt.res +${NCDUMP} -d5,5 test2.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/test2.dmp | tee testrdwt.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testrdwt, status = $ret_status" >> test.output @@ -176,7 +176,7 @@ echo "begin testwt_nc" >> test.output ${PREFIX} ${BINDIR}/testwt_nc${SUFFIX} >> test.output ret_status=$((ret_status+$?)) # Filter out the "maximum_name_length" attribute. Moves around in ncdump output for nc4 vs nc3 -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee testwt_nc.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee testwt_nc.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) echo "end testwt_nc, status = $ret_status" >> test.output @@ -190,7 +190,7 @@ echo "testwt-zeron - write file with zero nodes and elements..." echo "begin testwt-zeron" >> test.output ${PREFIX} ${BINDIR}/testwt-zeron${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testwt-zeron.dmp | tee testwt-zeron.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testwt-zeron.dmp | tee testwt-zeron.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testwt-zeron, status = $ret_status" >> test.output @@ -204,7 +204,7 @@ echo "testwt-zeroe - write file with zero elements..." echo "begin testwt-zeroe" >> test.output ${PREFIX} ${BINDIR}/testwt-zeroe${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testwt-zeroe.dmp | tee testwt-zeroe.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testwt-zeroe.dmp | tee testwt-zeroe.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testwt-zeroe, status = $ret_status" >> test.output @@ -224,7 +224,7 @@ echo "testwt-nsided - write file with nsided elements..." echo "begin testwt-nsided" >> test.output ${PREFIX} ${BINDIR}/testwt-nsided${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test-nsided.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testwt-nsided.dmp | tee testwt-nsided.res +${NCDUMP} -d5,5 test-nsided.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testwt-nsided.dmp | tee testwt-nsided.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testwt-nsided, status = $ret_status" >> test.output @@ -238,7 +238,7 @@ echo "testwt-nfaced - write file with nfaced elements..." echo "begin testwt-nfaced" >> test.output ${PREFIX} ${BINDIR}/testwt-nfaced${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test-nfaced.exo | grep -v version | grep -v int64_status| grep -v _FillValue | ${DIFF} - ${SRCDIR}/testwt-nfaced.dmp | tee testwt-nfaced.res +${NCDUMP} -d5,5 test-nfaced.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size| ${DIFF} - ${SRCDIR}/testwt-nfaced.dmp | tee testwt-nfaced.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testwt-nfaced, status = $ret_status" >> test.output @@ -253,7 +253,7 @@ echo "begin testwt-long-name" >> test.output # Filter out the "maximum_name_length" attribute. Moves around in ncdump output for nc4 vs nc3 ${PREFIX} ${BINDIR}/testwt-long-name${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/testwt-long-name.dmp | tee testwt-long-name.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/testwt-long-name.dmp | tee testwt-long-name.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[3]})) echo "end testwt-long-name, status = $ret_status" >> test.output @@ -286,7 +286,7 @@ echo "begin testwt-results" >> test.output ${PREFIX} ${BINDIR}/testwt-results${SUFFIX} >> test.output ret_status=$((ret_status+$?)) # Filter out the "maximum_name_length" attribute. Moves around in ncdump output for nc4 vs nc3 -${NCDUMP} -d5,5 test-results.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/testwt-results.dmp | tee testwt-results.re +${NCDUMP} -d5,5 test-results.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/testwt-results.dmp | tee testwt-results.re ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) echo "end testwt-results, status = $ret_status" >> test.output @@ -295,7 +295,7 @@ echo "begin testwt-assembly" >> test.output ${PREFIX} ${BINDIR}/testwt-assembly${SUFFIX} >> test.output ret_status=$((ret_status+$?)) # Filter out the "maximum_name_length" attribute. Moves around in ncdump output for nc4 vs nc3 -${NCDUMP} -d5,5 test-assembly.exo | grep -v version | grep -v int64_status| grep -v floating_point | grep -v _FillValue |grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/testwt-assembly.dmp | tee testwt-assembly.res +${NCDUMP} -d5,5 test-assembly.exo | grep -v version | grep -v int64_status| grep -v floating_point | grep -v _FillValue |grep -v word_size|grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/testwt-assembly.dmp | tee testwt-assembly.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[6]})) echo "end testwt-assembly, status = $ret_status" >> test.output @@ -310,7 +310,7 @@ echo "begin test-add-assembly" >> test.output ${PREFIX} ${BINDIR}/test-add-assembly${SUFFIX} >> test.output ret_status=$((ret_status+$?)) # Filter out the "maximum_name_length" attribute. Moves around in ncdump output for nc4 vs nc3 -${NCDUMP} -d5,5 test-assembly.exo | grep -v version | grep -v int64_status | grep -v floating_point | grep -v _FillValue |grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/test-add-assembly.dmp | tee test-add-assembly.res +${NCDUMP} -d5,5 test-assembly.exo | grep -v version | grep -v int64_status | grep -v floating_point | grep -v _FillValue |grep -v word_size|grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/test-add-assembly.dmp | tee test-add-assembly.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[6]})) echo "end test-add-assembly, status = $ret_status" >> test.output @@ -319,7 +319,7 @@ echo "begin testwt-blob" >> test.output ${PREFIX} ${BINDIR}/testwt-blob${SUFFIX} >> test.output ret_status=$((ret_status+$?)) # Filter out the "maximum_name_length" attribute. Moves around in ncdump output for nc4 vs nc3 -${NCDUMP} -d5,5 test-blob.exo | grep -v version | grep -v int64_status | grep -v floating_point | grep -v _FillValue |grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/testwt-blob.dmp | tee testwt-blob.res +${NCDUMP} -d5,5 test-blob.exo | grep -v version | grep -v int64_status | grep -v floating_point | grep -v _FillValue |grep -v word_size|grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/testwt-blob.dmp | tee testwt-blob.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[6]})) echo "end testwt-blob, status = $ret_status" >> test.output @@ -334,7 +334,7 @@ echo "begin testwt-oned" >> test.output ${PREFIX} ${BINDIR}/testwt-oned${SUFFIX} >> test.output ret_status=$((ret_status+$?)) # Filter out the "maximum_name_length" attribute. Moves around in ncdump output for nc4 vs nc3 -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/testwt-oned.dmp | tee testwt-oned.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/testwt-oned.dmp | tee testwt-oned.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) echo "end testwt-oned, status = $ret_status" >> test.output @@ -350,7 +350,7 @@ echo "test_ts_nvar - each thread writes data for a single nodal variable..." echo "begin test_ts_nvar" >> test.output ${PREFIX} ${BINDIR}/test_ts_nvar${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/test_ts_nvar.dmp | tee testwt-long-name.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/test_ts_nvar.dmp | tee testwt-long-name.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) echo "end test_ts_nvar, status = $ret_status" >> test.output @@ -365,7 +365,7 @@ echo "test_ts_partial_nvar - each thread writes data for a single nodal variable echo "begin test_ts_partial_nvar" >> test.output ${PREFIX} ${BINDIR}/test_ts_partial_nvar${SUFFIX} >> test.output ret_status=$((ret_status+$?)) -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/test_ts_partial_nvar.dmp | tee testwt-long-name.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v "maximum_name_length" | ${DIFF} - ${SRCDIR}/test_ts_partial_nvar.dmp | tee testwt-long-name.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) echo "end test_ts_partial_nvar, status = $ret_status" >> test.output @@ -382,28 +382,28 @@ echo "begin test_ts_files" >> test.output ${PREFIX} ${BINDIR}/test_ts_files${SUFFIX} >> test.output ret_status=$((ret_status+$?)) mv test0.exo test.exo -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files0.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files0.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) mv test1.exo test.exo -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files1.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files1.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) mv test2.exo test.exo -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files2.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files2.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) mv test3.exo test.exo -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files3.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files3.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) mv test4.exo test.exo -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files4.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files4.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) mv test5.exo test.exo -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files5.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files5.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) mv test6.exo test.exo -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files6.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files6.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) mv test7.exo test.exo -${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files7.res +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v word_size|grep -v maximum_name_length | ${DIFF} - ${SRCDIR}/test.dmp | tee test_ts_files7.res ret_status=$((ret_status+${PIPESTATUS[0]}+${PIPESTATUS[5]})) echo "end test_ts_files, status = $ret_status" >> test.output @@ -414,4 +414,3 @@ ret_status=$((ret_status+$?)) echo "end test_ts_errval, status = $ret_status" >> test.output fi exit $ret_status - diff --git a/packages/seacas/libraries/exodus/test/testcp_dd.dmp b/packages/seacas/libraries/exodus/test/testcp_dd.dmp index c7dc9a1bb688..91e5c1457994 100644 --- a/packages/seacas/libraries/exodus/test/testcp_dd.dmp +++ b/packages/seacas/libraries/exodus/test/testcp_dd.dmp @@ -50,7 +50,7 @@ variables: char ns_names(num_node_sets, len_name) ; char ss_names(num_side_sets, len_name) ; char coor_names(num_dim, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; double attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -99,7 +99,6 @@ variables: ss_prop2:name = "COLOR" ; // global attributes: - :floating_point_word_size = 8 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; @@ -117,13 +116,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0 ; eb_names = @@ -149,7 +148,7 @@ data: "ycoor", "zcoor" ; - elem_map = 1, 2, 3, 4, 5 ; + elem_num_map = 1, 2, 3, 4, 5 ; attrib1 = 3.1416 ; diff --git a/packages/seacas/libraries/exodus/test/testcp_ds.dmp b/packages/seacas/libraries/exodus/test/testcp_ds.dmp index f215bce49139..825b712b7bfb 100644 --- a/packages/seacas/libraries/exodus/test/testcp_ds.dmp +++ b/packages/seacas/libraries/exodus/test/testcp_ds.dmp @@ -50,7 +50,7 @@ variables: char ns_names(num_node_sets, len_name) ; char ss_names(num_side_sets, len_name) ; char coor_names(num_dim, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; float attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -99,10 +99,8 @@ variables: ss_prop2:name = "COLOR" ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; - :int64_status = 0 ; :title = "This is a test" ; data: @@ -118,13 +116,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0 ; eb_names = @@ -150,7 +148,7 @@ data: "ycoor", "zcoor" ; - elem_map = 1, 2, 3, 4, 5 ; + elem_num_map = 1, 2, 3, 4, 5 ; attrib1 = 3.1416 ; diff --git a/packages/seacas/libraries/exodus/test/testcp_nl.dmp b/packages/seacas/libraries/exodus/test/testcp_nl.dmp index bfcc74ba7067..d2c6146ad938 100644 --- a/packages/seacas/libraries/exodus/test/testcp_nl.dmp +++ b/packages/seacas/libraries/exodus/test/testcp_nl.dmp @@ -60,7 +60,7 @@ variables: char coor_names(num_dim, len_name) ; float nattrb(num_nodes, num_att_in_nblk) ; char nattrib_name(num_att_in_nblk, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; float attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -119,10 +119,8 @@ variables: ss_prop2:name = "COLOR" ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 33 ; - :int64_status = 0 ; :title = "This is a test" ; data: @@ -138,13 +136,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0, 2.7, 6, 5.7, 3.7, 0, 10, 10 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2, 1.7, 1.7, 1.7, 0, 0, 0, 10 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0, 2.7, 3.3, 1.7, 2.3, 0, 0, 10 ; eb_names = @@ -211,7 +209,7 @@ data: "Node_attr_1", "Node_attr_2" ; - elem_map = 1, 2, 3, 4, 5, 6, 7 ; + elem_num_map = 10, 20, 30, 40, 50, 60, 70 ; attrib1 = 3.1416 ; diff --git a/packages/seacas/libraries/exodus/test/testcp_sd.dmp b/packages/seacas/libraries/exodus/test/testcp_sd.dmp index 2dffaa875fc5..0ee820cf4ce6 100644 --- a/packages/seacas/libraries/exodus/test/testcp_sd.dmp +++ b/packages/seacas/libraries/exodus/test/testcp_sd.dmp @@ -60,7 +60,7 @@ variables: char coor_names(num_dim, len_name) ; double nattrb(num_nodes, num_att_in_nblk) ; char nattrib_name(num_att_in_nblk, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; double attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -119,10 +119,8 @@ variables: ss_prop2:name = "COLOR" ; // global attributes: - :floating_point_word_size = 8 ; :file_size = 1 ; :maximum_name_length = 33 ; - :int64_status = 0 ; :title = "This is a test" ; data: @@ -138,13 +136,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0, 2.7, 6, 5.7, 3.7, 0, 10, 10 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2, 1.7, 1.7, 1.7, 0, 0, 0, 10 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0, 2.7, 3.3, 1.7, 2.3, 0, 0, 10 ; eb_names = @@ -211,7 +209,7 @@ data: "Node_attr_1", "Node_attr_2" ; - elem_map = 1, 2, 3, 4, 5, 6, 7 ; + elem_num_map = 10, 20, 30, 40, 50, 60, 70 ; attrib1 = 3.1416 ; diff --git a/packages/seacas/libraries/exodus/test/testcp_ss.dmp b/packages/seacas/libraries/exodus/test/testcp_ss.dmp index 74c9b8f018bf..77366750ab43 100644 --- a/packages/seacas/libraries/exodus/test/testcp_ss.dmp +++ b/packages/seacas/libraries/exodus/test/testcp_ss.dmp @@ -60,7 +60,7 @@ variables: char coor_names(num_dim, len_name) ; float nattrb(num_nodes, num_att_in_nblk) ; char nattrib_name(num_att_in_nblk, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; float attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -119,7 +119,6 @@ variables: ss_prop2:name = "COLOR" ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 33 ; :title = "This is a test" ; @@ -137,13 +136,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0, 2.7, 6, 5.7, 3.7, 0, 10, 10 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2, 1.7, 1.7, 1.7, 0, 0, 0, 10 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0, 2.7, 3.3, 1.7, 2.3, 0, 0, 10 ; eb_names = @@ -210,7 +209,7 @@ data: "Node_attr_1", "Node_attr_2" ; - elem_map = 1, 2, 3, 4, 5, 6, 7 ; + elem_num_map = 10, 20, 30, 40, 50, 60, 70 ; attrib1 = 3.1416 ; diff --git a/packages/seacas/libraries/exodus/test/testcp_tran.dmp b/packages/seacas/libraries/exodus/test/testcp_tran.dmp index 15c04151adad..72eda4c0a64a 100644 --- a/packages/seacas/libraries/exodus/test/testcp_tran.dmp +++ b/packages/seacas/libraries/exodus/test/testcp_tran.dmp @@ -65,7 +65,7 @@ variables: char coor_names(num_dim, len_name) ; float nattrb(num_nodes, num_att_in_nblk) ; char nattrib_name(num_att_in_nblk, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; float attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -176,7 +176,6 @@ variables: float vals_elem_var4eb1(time_step, num_el_in_blk1) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 33 ; :title = "This is a test" ; @@ -196,13 +195,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0, 2.7, 6, 5.7, 3.7, 0, 10, 10 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2, 1.7, 1.7, 1.7, 0, 0, 0, 10 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0, 2.7, 3.3, 1.7, 2.3, 0, 0, 10 ; eb_names = @@ -269,7 +268,7 @@ data: "Node_attr_1", "Node_attr_2" ; - elem_map = 1, 2, 3, 4, 5, 6, 7 ; + elem_num_map = 10, 20, 30, 40, 50, 60, 70 ; attrib1 = 3.1416 ; @@ -392,99 +391,99 @@ data: "GregNode" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, - 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, 1.54, 1.56, 1.58, 1.6, 1.62, 1.64, 1.66, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, 1.81, 1.84, 1.87, 1.9, 1.93, 1.96, 1.99, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, - 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, - 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, - 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, 2.62, 2.68, 2.74, 2.8, 2.86, 2.92, 2.98, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, 2.89, 2.96, 3.03, 3.1, 3.17, 3.24, 3.31, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, - 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, 3.16, 3.24, 3.32, 3.4, 3.48, 3.56, 3.64, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, 3.43, 3.52, 3.61, 3.7, 3.79, 3.88, 3.97, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, - 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, - 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, 2.54, 2.56, 2.58, 2.6, 2.62, 2.64, 2.66, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, 2.81, 2.84, 2.87, 2.9, 2.93, 2.96, 2.99, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, - 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, 3.08, 3.12, 3.16, 3.2, 3.24, 3.28, 3.32, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, - 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, 3.62, 3.68, 3.74, 3.8, 3.86, 3.92, 3.98, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, 3.89, 3.96, 4.03, 4.1, 4.17, 4.24, 4.31, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, - 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, 4.16, 4.24, 4.32, 4.4, 4.48, 4.56, 4.64, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, 4.43, 4.52, 4.61, 4.7, 4.79, 4.88, 4.97, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, - 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3 ; vals_nod_var3 = - 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.1, 3.11, 3.12, - 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.2, 3.21, 3.22, 3.23, 3.24, + 3.01, 3.02, 3.03, 3.04, 3.05, 3.06, 3.07, 3.08, 3.09, 3.1, 3.11, 3.12, + 3.13, 3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.2, 3.21, 3.22, 3.23, 3.24, 3.25, 3.26, 3.27, 3.28, 3.29, 3.3, 3.31, 3.32, 3.33, - 3.02, 3.04, 3.06, 3.08, 3.1, 3.12, 3.14, 3.16, 3.18, 3.2, 3.22, 3.24, 3.26, - 3.28, 3.3, 3.32, 3.34, 3.36, 3.38, 3.4, 3.42, 3.44, 3.46, 3.48, 3.5, + 3.02, 3.04, 3.06, 3.08, 3.1, 3.12, 3.14, 3.16, 3.18, 3.2, 3.22, 3.24, 3.26, + 3.28, 3.3, 3.32, 3.34, 3.36, 3.38, 3.4, 3.42, 3.44, 3.46, 3.48, 3.5, 3.52, 3.54, 3.56, 3.58, 3.6, 3.62, 3.64, 3.66, - 3.03, 3.06, 3.09, 3.12, 3.15, 3.18, 3.21, 3.24, 3.27, 3.3, 3.33, 3.36, - 3.39, 3.42, 3.45, 3.48, 3.51, 3.54, 3.57, 3.6, 3.63, 3.66, 3.69, 3.72, + 3.03, 3.06, 3.09, 3.12, 3.15, 3.18, 3.21, 3.24, 3.27, 3.3, 3.33, 3.36, + 3.39, 3.42, 3.45, 3.48, 3.51, 3.54, 3.57, 3.6, 3.63, 3.66, 3.69, 3.72, 3.75, 3.78, 3.81, 3.84, 3.87, 3.9, 3.93, 3.96, 3.99, - 3.04, 3.08, 3.12, 3.16, 3.2, 3.24, 3.28, 3.32, 3.36, 3.4, 3.44, 3.48, 3.52, - 3.56, 3.6, 3.64, 3.68, 3.72, 3.76, 3.8, 3.84, 3.88, 3.92, 3.96, 4, 4.04, + 3.04, 3.08, 3.12, 3.16, 3.2, 3.24, 3.28, 3.32, 3.36, 3.4, 3.44, 3.48, 3.52, + 3.56, 3.6, 3.64, 3.68, 3.72, 3.76, 3.8, 3.84, 3.88, 3.92, 3.96, 4, 4.04, 4.08, 4.12, 4.16, 4.2, 4.24, 4.28, 4.32, - 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, - 3.7, 3.75, 3.8, 3.85, 3.9, 3.95, 4, 4.05, 4.1, 4.15, 4.2, 4.25, 4.3, + 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, + 3.7, 3.75, 3.8, 3.85, 3.9, 3.95, 4, 4.05, 4.1, 4.15, 4.2, 4.25, 4.3, 4.35, 4.4, 4.45, 4.5, 4.55, 4.6, 4.65, - 3.06, 3.12, 3.18, 3.24, 3.3, 3.36, 3.42, 3.48, 3.54, 3.6, 3.66, 3.72, 3.78, - 3.84, 3.9, 3.96, 4.02, 4.08, 4.14, 4.2, 4.26, 4.32, 4.38, 4.44, 4.5, + 3.06, 3.12, 3.18, 3.24, 3.3, 3.36, 3.42, 3.48, 3.54, 3.6, 3.66, 3.72, 3.78, + 3.84, 3.9, 3.96, 4.02, 4.08, 4.14, 4.2, 4.26, 4.32, 4.38, 4.44, 4.5, 4.56, 4.62, 4.68, 4.74, 4.8, 4.86, 4.92, 4.98, - 3.07, 3.14, 3.21, 3.28, 3.35, 3.42, 3.49, 3.56, 3.63, 3.7, 3.77, 3.84, - 3.91, 3.98, 4.05, 4.12, 4.19, 4.26, 4.33, 4.4, 4.47, 4.54, 4.61, 4.68, + 3.07, 3.14, 3.21, 3.28, 3.35, 3.42, 3.49, 3.56, 3.63, 3.7, 3.77, 3.84, + 3.91, 3.98, 4.05, 4.12, 4.19, 4.26, 4.33, 4.4, 4.47, 4.54, 4.61, 4.68, 4.75, 4.82, 4.89, 4.96, 5.03, 5.1, 5.17, 5.24, 5.31, - 3.08, 3.16, 3.24, 3.32, 3.4, 3.48, 3.56, 3.64, 3.72, 3.8, 3.88, 3.96, 4.04, - 4.12, 4.2, 4.28, 4.36, 4.44, 4.52, 4.6, 4.68, 4.76, 4.84, 4.92, 5, 5.08, + 3.08, 3.16, 3.24, 3.32, 3.4, 3.48, 3.56, 3.64, 3.72, 3.8, 3.88, 3.96, 4.04, + 4.12, 4.2, 4.28, 4.36, 4.44, 4.52, 4.6, 4.68, 4.76, 4.84, 4.92, 5, 5.08, 5.16, 5.24, 5.32, 5.4, 5.48, 5.56, 5.64, - 3.09, 3.18, 3.27, 3.36, 3.45, 3.54, 3.63, 3.72, 3.81, 3.9, 3.99, 4.08, - 4.17, 4.26, 4.35, 4.44, 4.53, 4.62, 4.71, 4.8, 4.89, 4.98, 5.07, 5.16, + 3.09, 3.18, 3.27, 3.36, 3.45, 3.54, 3.63, 3.72, 3.81, 3.9, 3.99, 4.08, + 4.17, 4.26, 4.35, 4.44, 4.53, 4.62, 4.71, 4.8, 4.89, 4.98, 5.07, 5.16, 5.25, 5.34, 5.43, 5.52, 5.61, 5.7, 5.79, 5.88, 5.97, - 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, - 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6, + 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, + 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6, 6.1, 6.2, 6.3 ; name_elem_var = diff --git a/packages/seacas/libraries/exodus/test/testd.dmp b/packages/seacas/libraries/exodus/test/testd.dmp index 37a3fc3ed66e..80b473a40f8b 100644 --- a/packages/seacas/libraries/exodus/test/testd.dmp +++ b/packages/seacas/libraries/exodus/test/testd.dmp @@ -58,7 +58,7 @@ variables: char ns_names(num_node_sets, len_name) ; char ss_names(num_side_sets, len_name) ; char coor_names(num_dim, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; double attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -131,7 +131,6 @@ variables: int elem_var_tab(num_el_blk, num_elem_var) ; // global attributes: - :floating_point_word_size = 8 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; @@ -151,13 +150,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0 ; eb_names = @@ -183,7 +182,7 @@ data: "ycoor", "zcoor" ; - elem_map = 1, 2, 3, 4, 5 ; + elem_num_map = 1, 2, 3, 4, 5 ; attrib1 = 3.1416 ; @@ -307,55 +306,55 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6 ; name_elem_var = diff --git a/packages/seacas/libraries/exodus/test/testrd-blob.c b/packages/seacas/libraries/exodus/test/testrd-blob.c index d350642445d5..3bdf6e783957 100644 --- a/packages/seacas/libraries/exodus/test/testrd-blob.c +++ b/packages/seacas/libraries/exodus/test/testrd-blob.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -160,13 +160,13 @@ int main(int argc, char **argv) } { /* Global attributes (includes exodus-internal attributes) */ - ex_attribute attr[10]; - int att_count = ex_get_attribute_count(exoid, EX_GLOBAL, 0); - printf("GLOBAL contains %d attributes:\n", att_count); - for (int j = 0; j < att_count; j++) { - ex_get_attribute_param(exoid, EX_GLOBAL, 0, attr); - printf("\tName: '%s', Type = %d, Value Count = %d\n", attr[j].name, attr[j].type, - (int)attr[j].value_count); + ex_attribute g_attr[10]; + int g_att_count = ex_get_attribute_count(exoid, EX_GLOBAL, 0); + printf("GLOBAL contains %d attributes:\n", g_att_count); + for (int j = 0; j < g_att_count; j++) { + ex_get_attribute_param(exoid, EX_GLOBAL, 0, g_attr); + printf("\tName: '%s', Type = %d, Value Count = %d\n", g_attr[j].name, attr[j].type, + (int)g_attr[j].value_count); } } diff --git a/packages/seacas/libraries/exodus/test/testrd-long-name.c b/packages/seacas/libraries/exodus/test/testrd-long-name.c index 5620ebed5519..450616627eaa 100644 --- a/packages/seacas/libraries/exodus/test/testrd-long-name.c +++ b/packages/seacas/libraries/exodus/test/testrd-long-name.c @@ -226,8 +226,8 @@ int main(int argc, char **argv) elem_map = (int *)calloc(num_elem, sizeof(int)); - error = ex_get_map(exoid, elem_map); - printf("\nafter ex_get_map, error = %3d\n", error); + error = ex_get_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("\nafter ex_get_id_map, error = %3d\n", error); for (i = 0; i < num_elem; i++) { printf("elem_map(%d) = %d \n", i, elem_map[i]); diff --git a/packages/seacas/libraries/exodus/test/testrd-long-name.dmp b/packages/seacas/libraries/exodus/test/testrd-long-name.dmp index 6abb69273e12..3071eb10f4e2 100644 --- a/packages/seacas/libraries/exodus/test/testrd-long-name.dmp +++ b/packages/seacas/libraries/exodus/test/testrd-long-name.dmp @@ -196,7 +196,7 @@ nodal attribute 1 = 'Node_attr_2' 0.0 10.0 -after ex_get_map, error = 0 +after ex_get_id_map, error = 0 elem_map(0) = 1 elem_map(1) = 2 elem_map(2) = 3 diff --git a/packages/seacas/libraries/exodus/test/testrd-nm32.dmp b/packages/seacas/libraries/exodus/test/testrd-nm32.dmp index 38f3a34fe97e..84c554f7df40 100644 --- a/packages/seacas/libraries/exodus/test/testrd-nm32.dmp +++ b/packages/seacas/libraries/exodus/test/testrd-nm32.dmp @@ -194,14 +194,14 @@ nodal attribute 1 = 'Node_attr_2' 0.0 10.0 -after ex_get_map, error = 0 -elem_map(0) = 1 -elem_map(1) = 2 -elem_map(2) = 3 -elem_map(3) = 4 -elem_map(4) = 5 -elem_map(5) = 6 -elem_map(6) = 7 +after ex_get_id_map, error = 0 +elem_id_map(0) = 1 +elem_id_map(1) = 2 +elem_id_map(2) = 3 +elem_id_map(3) = 4 +elem_id_map(4) = 5 +elem_id_map(5) = 6 +elem_id_map(6) = 7 after ex_get_elem_blk_ids, error = 0 diff --git a/packages/seacas/libraries/exodus/test/testrd-nsided.c b/packages/seacas/libraries/exodus/test/testrd-nsided.c index 0513c9353dbf..d5c23ac7a1e7 100644 --- a/packages/seacas/libraries/exodus/test/testrd-nsided.c +++ b/packages/seacas/libraries/exodus/test/testrd-nsided.c @@ -182,8 +182,8 @@ int main(int argc, char **argv) /* read element order map */ int *elem_map = (int *)calloc(num_elem, sizeof(int)); - error = ex_get_map(exoid, elem_map); - printf("\nafter ex_get_map, error = %3d\n", error); + error = ex_get_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("\nafter ex_get_id_map, error = %3d\n", error); for (int i = 0; i < num_elem; i++) { printf("elem_map(%d) = %d \n", i, elem_map[i]); diff --git a/packages/seacas/libraries/exodus/test/testrd-nsided.dmp b/packages/seacas/libraries/exodus/test/testrd-nsided.dmp index 6a7b9536672f..20b77f3779f1 100644 --- a/packages/seacas/libraries/exodus/test/testrd-nsided.dmp +++ b/packages/seacas/libraries/exodus/test/testrd-nsided.dmp @@ -192,7 +192,7 @@ nodal attribute 1 = 'Node_attr_2' 0.0 10.0 -after ex_get_map, error = 0 +after ex_get_id_map, error = 0 elem_map(0) = 1 elem_map(1) = 2 elem_map(2) = 3 diff --git a/packages/seacas/libraries/exodus/test/testrd-oned.dmp b/packages/seacas/libraries/exodus/test/testrd-oned.dmp index 4b2af18b36e7..d0ea2e9319c2 100644 --- a/packages/seacas/libraries/exodus/test/testrd-oned.dmp +++ b/packages/seacas/libraries/exodus/test/testrd-oned.dmp @@ -43,17 +43,17 @@ nodal attribute 0 = 'Node_attr_1' 2.2 2.5 -after ex_get_map, error = 0 -elem_map(0) = 10 -elem_map(1) = 20 -elem_map(2) = 30 -elem_map(3) = 40 -elem_map(4) = 50 -elem_map(5) = 60 -elem_map(6) = 70 -elem_map(7) = 80 -elem_map(8) = 90 -elem_map(9) = 100 +after ex_get_id_map, error = 0 +elem_id_map(0) = 10 +elem_id_map(1) = 20 +elem_id_map(2) = 30 +elem_id_map(3) = 40 +elem_id_map(4) = 50 +elem_id_map(5) = 60 +elem_id_map(6) = 70 +elem_id_map(7) = 80 +elem_id_map(8) = 90 +elem_id_map(9) = 100 after ex_get_elem_blk_ids, error = 0 diff --git a/packages/seacas/libraries/exodus/test/testrd.c b/packages/seacas/libraries/exodus/test/testrd.c index 64f21eb92568..b115e0b50413 100644 --- a/packages/seacas/libraries/exodus/test/testrd.c +++ b/packages/seacas/libraries/exodus/test/testrd.c @@ -12,6 +12,7 @@ *****************************************************************************/ #include "exodusII.h" +#include #include #include #include @@ -184,14 +185,13 @@ int main(int argc, char **argv) int *elem_map = (int *)calloc(num_elem, sizeof(int)); - error = ex_get_map(exoid, elem_map); - printf("\nafter ex_get_map, error = %3d\n", error); + error = ex_get_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("\nafter ex_get_id_map, error = %3d\n", error); for (int i = 0; i < num_elem; i++) { - printf("elem_map(%d) = %d \n", i, elem_map[i]); + printf("elem_id_map(%d) = %d \n", i, elem_map[i]); } - - free(elem_map); + /* NOTE: elem_map used below */ /* read element block parameters */ @@ -233,6 +233,22 @@ int main(int argc, char **argv) free(block_names[i]); } + /* Read per-block id map and compare to overall id map... */ + int offset = 0; + for (int i = 0; i < num_elem_blk; i++) { + int *block_map = (int *)calloc(num_elem_in_block[i], sizeof(int)); + error = ex_get_block_id_map(exoid, EX_ELEM_BLOCK, ids[i], block_map); + + /* Compare values with overall id map */ +#if 0 + for (int j = 0; j < num_elem_in_block[i]; j++) { + assert(block_map[j] == elem_map[offset + j]); + } +#endif + offset += num_elem_in_block[i]; + free(block_map); + } + /* read element block properties */ int num_props = ex_inquire_int(exoid, EX_INQ_EB_PROP); printf("\nafter ex_inquire, error = %d\n", error); @@ -314,6 +330,7 @@ int main(int argc, char **argv) free(num_nodes_per_elem); free(num_attr); } + free(elem_map); /* read individual node sets */ if (num_node_sets > 0) { diff --git a/packages/seacas/libraries/exodus/test/testrd.dmp b/packages/seacas/libraries/exodus/test/testrd.dmp index f85e38a9a2ee..d44c65196bab 100644 --- a/packages/seacas/libraries/exodus/test/testrd.dmp +++ b/packages/seacas/libraries/exodus/test/testrd.dmp @@ -194,14 +194,14 @@ nodal attribute 1 = 'Node_attr_2' 0.0 10.0 -after ex_get_map, error = 0 -elem_map(0) = 1 -elem_map(1) = 2 -elem_map(2) = 3 -elem_map(3) = 4 -elem_map(4) = 5 -elem_map(5) = 6 -elem_map(6) = 7 +after ex_get_id_map, error = 0 +elem_id_map(0) = 10 +elem_id_map(1) = 20 +elem_id_map(2) = 30 +elem_id_map(3) = 40 +elem_id_map(4) = 50 +elem_id_map(5) = 60 +elem_id_map(6) = 70 after ex_get_elem_blk_ids, error = 0 diff --git a/packages/seacas/libraries/exodus/test/testrd_nc.c b/packages/seacas/libraries/exodus/test/testrd_nc.c index 6ad56a52602f..dc4da24c55d8 100644 --- a/packages/seacas/libraries/exodus/test/testrd_nc.c +++ b/packages/seacas/libraries/exodus/test/testrd_nc.c @@ -164,8 +164,8 @@ int main(int argc, char **argv) int *elem_map = (int *)my_calloc(num_elem, sizeof(int)); - error = ex_get_map(exoid, elem_map); - printf("\nafter ex_get_map, error = %3d\n", error); + error = ex_get_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("\nafter ex_get_id_map, error = %3d\n", error); for (i = 0; i < num_elem; i++) { printf("elem_map(%d) = %d \n", i, elem_map[i]); diff --git a/packages/seacas/libraries/exodus/test/testrd_nc.dmp b/packages/seacas/libraries/exodus/test/testrd_nc.dmp index 648e9a5e24cc..e50ee4c6b806 100644 --- a/packages/seacas/libraries/exodus/test/testrd_nc.dmp +++ b/packages/seacas/libraries/exodus/test/testrd_nc.dmp @@ -125,14 +125,14 @@ after ex_get_coord_names, error = 0 x coord name = 'xcoor' y coord name = 'ycoor' -after ex_get_map, error = 0 -elem_map(0) = 1 -elem_map(1) = 2 -elem_map(2) = 3 -elem_map(3) = 4 -elem_map(4) = 5 -elem_map(5) = 6 -elem_map(6) = 7 +after ex_get_id_map, error = 0 +elem_map(0) = 10 +elem_map(1) = 20 +elem_map(2) = 30 +elem_map(3) = 40 +elem_map(4) = 50 +elem_map(5) = 60 +elem_map(6) = 70 after ex_get_elem_blk_ids, error = 0 diff --git a/packages/seacas/libraries/exodus/test/testrd_par.c b/packages/seacas/libraries/exodus/test/testrd_par.c index 5bbfb8504c90..b8c20c2ed358 100644 --- a/packages/seacas/libraries/exodus/test/testrd_par.c +++ b/packages/seacas/libraries/exodus/test/testrd_par.c @@ -204,8 +204,8 @@ int main(int argc, char **argv) int *elem_map = (int *)calloc(num_elem, sizeof(int)); - error = ex_get_map(exoid, elem_map); - printf("\nafter ex_get_map, error = %3d\n", error); + error = ex_get_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("\nafter ex_get_id_map, error = %3d\n", error); for (i = 0; i < num_elem; i++) { printf("elem_map(%d) = %d \n", i, elem_map[i]); diff --git a/packages/seacas/libraries/exodus/test/testrd_zeroe.dmp b/packages/seacas/libraries/exodus/test/testrd_zeroe.dmp index a177d96dbf67..41b5261351ab 100644 --- a/packages/seacas/libraries/exodus/test/testrd_zeroe.dmp +++ b/packages/seacas/libraries/exodus/test/testrd_zeroe.dmp @@ -123,7 +123,7 @@ z coord name = 'zcoor' after ex_get_attr_param, error = 0 num nodal attributes = 0 -after ex_get_map, error = 0 +after ex_get_id_map, error = 0 after ex_get_node_set_ids, error = 0 diff --git a/packages/seacas/libraries/exodus/test/testrd_zeron.dmp b/packages/seacas/libraries/exodus/test/testrd_zeron.dmp index e07c05291b5f..217fd539e4fc 100644 --- a/packages/seacas/libraries/exodus/test/testrd_zeron.dmp +++ b/packages/seacas/libraries/exodus/test/testrd_zeron.dmp @@ -20,7 +20,7 @@ x coord name = 'xcoor' after ex_get_attr_param, error = 0 num nodal attributes = 0 -after ex_get_map, error = 0 +after ex_get_id_map, error = 0 after ex_get_qa, error = 0 QA records = diff --git a/packages/seacas/libraries/exodus/test/testrdd.c b/packages/seacas/libraries/exodus/test/testrdd.c index c3aee929999d..566cbf02aff8 100644 --- a/packages/seacas/libraries/exodus/test/testrdd.c +++ b/packages/seacas/libraries/exodus/test/testrdd.c @@ -167,8 +167,8 @@ int main(int argc, char **argv) int *elem_map = (int *)my_calloc(num_elem, sizeof(int)); - error = ex_get_map(exoid, elem_map); - printf("\nafter ex_get_map, error = %3d\n", error); + error = ex_get_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("\nafter ex_get_id_map, error = %3d\n", error); for (i = 0; i < num_elem; i++) { printf("elem_map(%d) = %d \n", i, elem_map[i]); diff --git a/packages/seacas/libraries/exodus/test/testrdd.dmp b/packages/seacas/libraries/exodus/test/testrdd.dmp index 98d101c77bd5..e95e8f8cdaa7 100644 --- a/packages/seacas/libraries/exodus/test/testrdd.dmp +++ b/packages/seacas/libraries/exodus/test/testrdd.dmp @@ -99,7 +99,7 @@ after ex_get_coord_names, error = 0 x coord name = 'xcoor' y coord name = 'ycoor' -after ex_get_map, error = 0 +after ex_get_id_map, error = 0 elem_map(0) = 1 elem_map(1) = 2 elem_map(2) = 3 diff --git a/packages/seacas/libraries/exodus/test/testrdwt.c b/packages/seacas/libraries/exodus/test/testrdwt.c index 0448de76c8c4..0e5df85a954a 100644 --- a/packages/seacas/libraries/exodus/test/testrdwt.c +++ b/packages/seacas/libraries/exodus/test/testrdwt.c @@ -123,13 +123,13 @@ int main(int argc, char **argv) int *elem_map = (int *)calloc(num_elem, sizeof(int)); - error = ex_get_map(exoid, elem_map); - printf("\nafter ex_get_map, error = %3d\n", error); + error = ex_get_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("\nafter ex_get_id_map, error = %3d\n", error); /* write element order map */ - error = ex_put_map(exoid2, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid2, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); free(elem_map); diff --git a/packages/seacas/libraries/exodus/test/testwt-compress.c b/packages/seacas/libraries/exodus/test/testwt-compress.c index bc93b33daf74..f8b39a3c84b6 100644 --- a/packages/seacas/libraries/exodus/test/testwt-compress.c +++ b/packages/seacas/libraries/exodus/test/testwt-compress.c @@ -277,8 +277,8 @@ int main(int argc, char **argv) elem_map[i - 1] = i; } - error = ex_put_map(exoid, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); if (error) { ex_close(exoid); diff --git a/packages/seacas/libraries/exodus/test/testwt-groups.c b/packages/seacas/libraries/exodus/test/testwt-groups.c index 874685c26a75..98c8bb92d68f 100644 --- a/packages/seacas/libraries/exodus/test/testwt-groups.c +++ b/packages/seacas/libraries/exodus/test/testwt-groups.c @@ -265,8 +265,8 @@ int main(int argc, char **argv) elem_map[i - 1] = i; } - error = ex_put_map(exoid, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); if (error) { ex_close(rootid); diff --git a/packages/seacas/libraries/exodus/test/testwt-long-name.c b/packages/seacas/libraries/exodus/test/testwt-long-name.c index b79ca5d082bf..79cd4b34ded6 100644 --- a/packages/seacas/libraries/exodus/test/testwt-long-name.c +++ b/packages/seacas/libraries/exodus/test/testwt-long-name.c @@ -247,8 +247,8 @@ int main(int argc, char **argv) elem_map[i - 1] = i; } - error = ex_put_map(exoid, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); if (error) { ex_close(exoid); diff --git a/packages/seacas/libraries/exodus/test/testwt-long-name.dmp b/packages/seacas/libraries/exodus/test/testwt-long-name.dmp index 7bdfdca8ee2a..5ff5b0056fc4 100644 --- a/packages/seacas/libraries/exodus/test/testwt-long-name.dmp +++ b/packages/seacas/libraries/exodus/test/testwt-long-name.dmp @@ -70,7 +70,7 @@ variables: char coor_names(num_dim, len_name) ; float nattrb(num_nodes, num_att_in_nblk) ; char nattrib_name(num_att_in_nblk, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; float attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -182,7 +182,6 @@ variables: float vals_nset_var3ns2(time_step, num_nod_ns2) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :title = "This is a test" ; data: @@ -201,13 +200,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0, 2.7, 6, 5.7, 3.7, 0, 10, 10 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2, 1.7, 1.7, 1.7, 0, 0, 0, 10 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0, 2.7, 3.3, 1.7, 2.3, 0, 0, 10 ; eb_names = @@ -274,7 +273,7 @@ data: "Node_attr_1", "Node_attr_2" ; - elem_map = 1, 2, 3, 4, 5, 6, 7 ; + elem_num_map = 1, 2, 3, 4, 5, 6, 7 ; attrib1 = 3.1416 ; @@ -426,67 +425,67 @@ data: "node_variable_a_much_longer_name_that_is_not_too_long_name" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, - 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, 1.54, 1.56, 1.58, 1.6, 1.62, 1.64, 1.66, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, 1.81, 1.84, 1.87, 1.9, 1.93, 1.96, 1.99, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, - 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, - 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, - 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, 2.62, 2.68, 2.74, 2.8, 2.86, 2.92, 2.98, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, 2.89, 2.96, 3.03, 3.1, 3.17, 3.24, 3.31, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, - 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, 3.16, 3.24, 3.32, 3.4, 3.48, 3.56, 3.64, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, 3.43, 3.52, 3.61, 3.7, 3.79, 3.88, 3.97, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, - 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, - 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, 2.54, 2.56, 2.58, 2.6, 2.62, 2.64, 2.66, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, 2.81, 2.84, 2.87, 2.9, 2.93, 2.96, 2.99, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, - 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, 3.08, 3.12, 3.16, 3.2, 3.24, 3.28, 3.32, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, - 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, 3.62, 3.68, 3.74, 3.8, 3.86, 3.92, 3.98, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, 3.89, 3.96, 4.03, 4.1, 4.17, 4.24, 4.31, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, - 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, 4.16, 4.24, 4.32, 4.4, 4.48, 4.56, 4.64, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, 4.43, 4.52, 4.61, 4.7, 4.79, 4.88, 4.97, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, - 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3 ; name_elem_var = diff --git a/packages/seacas/libraries/exodus/test/testwt-nfaced.dmp b/packages/seacas/libraries/exodus/test/testwt-nfaced.dmp index 4e304bdd8d21..caf5d1bfeb3d 100644 --- a/packages/seacas/libraries/exodus/test/testwt-nfaced.dmp +++ b/packages/seacas/libraries/exodus/test/testwt-nfaced.dmp @@ -45,7 +45,6 @@ variables: char info_records(num_info, len_line) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; @@ -76,8 +75,8 @@ data: "y", "z" ; - fbconn1 = 5, 6, 8, 2, 1, 4, 6, 2, 4, 8, 8, 4, 1, 5, 1, 2, 6, 5, 5, 8, 7, 1, - 3, 4, 7, 8, 4, 3, 7, 3, 1, 5, 8, 4, 14, 10, 12, 7, 11, 9, 13, 3, 7, 8, + fbconn1 = 5, 6, 8, 2, 1, 4, 6, 2, 4, 8, 8, 4, 1, 5, 1, 2, 6, 5, 5, 8, 7, 1, + 3, 4, 7, 8, 4, 3, 7, 3, 1, 5, 8, 4, 14, 10, 12, 7, 11, 9, 13, 3, 7, 8, 12, 11, 11, 12, 10, 9, 9, 10, 14, 13, 13, 14, 4, 3 ; fbepecnt1 = 3, 3, 4, 4, 4, 3, 3, 4, 4, 5, 5, 4, 4, 4, 4 ; diff --git a/packages/seacas/libraries/exodus/test/testwt-nsided.c b/packages/seacas/libraries/exodus/test/testwt-nsided.c index 98d114630647..e5c941bf7953 100644 --- a/packages/seacas/libraries/exodus/test/testwt-nsided.c +++ b/packages/seacas/libraries/exodus/test/testwt-nsided.c @@ -250,8 +250,8 @@ int main(int argc, char **argv) elem_map[i - 1] = i; } - error = ex_put_map(exoid, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); if (error) { ex_close(exoid); diff --git a/packages/seacas/libraries/exodus/test/testwt-nsided.dmp b/packages/seacas/libraries/exodus/test/testwt-nsided.dmp index b2a1a3cfc286..79dbe5614ec0 100644 --- a/packages/seacas/libraries/exodus/test/testwt-nsided.dmp +++ b/packages/seacas/libraries/exodus/test/testwt-nsided.dmp @@ -51,7 +51,7 @@ variables: char coor_names(num_dim, len_name) ; float nattrb(num_nodes, num_att_in_nblk) ; char nattrib_name(num_att_in_nblk, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; int connect1(num_nod_per_el1) ; connect1:elem_type = "nsided" ; int ebepecnt1(num_el_in_blk1) ; @@ -118,7 +118,6 @@ variables: float vals_nset_var3ns2(time_step, num_nod_ns2) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; @@ -138,13 +137,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0, 2.7, 6, 5.7, 3.7, 0, 10, 10 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2, 1.7, 1.7, 1.7, 0, 0, 0, 10 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0, 2.7, 3.3, 1.7, 2.3, 0, 0, 10 ; eb_names = @@ -205,9 +204,9 @@ data: "Node_attr_1", "Node_attr_2" ; - elem_map = 1, 2, 3, 4, 5, 6, 7 ; + elem_num_map = 1, 2, 3, 4, 5, 6, 7 ; - connect1 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + connect1 = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 17, 18, 19, 20, 27, 28, 30, 29, 31, 32, 33 ; ebepecnt1 = 4, 4, 8, 4, 6, 8, 3 ; @@ -295,67 +294,67 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, - 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, 1.54, 1.56, 1.58, 1.6, 1.62, 1.64, 1.66, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, 1.81, 1.84, 1.87, 1.9, 1.93, 1.96, 1.99, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, - 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, - 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, - 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, 2.62, 2.68, 2.74, 2.8, 2.86, 2.92, 2.98, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, 2.89, 2.96, 3.03, 3.1, 3.17, 3.24, 3.31, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, - 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, 3.16, 3.24, 3.32, 3.4, 3.48, 3.56, 3.64, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, 3.43, 3.52, 3.61, 3.7, 3.79, 3.88, 3.97, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, - 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, - 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, 2.54, 2.56, 2.58, 2.6, 2.62, 2.64, 2.66, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, 2.81, 2.84, 2.87, 2.9, 2.93, 2.96, 2.99, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, - 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, 3.08, 3.12, 3.16, 3.2, 3.24, 3.28, 3.32, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, - 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, 3.62, 3.68, 3.74, 3.8, 3.86, 3.92, 3.98, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, 3.89, 3.96, 4.03, 4.1, 4.17, 4.24, 4.31, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, - 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, 4.16, 4.24, 4.32, 4.4, 4.48, 4.56, 4.64, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, 4.43, 4.52, 4.61, 4.7, 4.79, 4.88, 4.97, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, - 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3 ; name_elem_var = diff --git a/packages/seacas/libraries/exodus/test/testwt-oned.c b/packages/seacas/libraries/exodus/test/testwt-oned.c index ae4ed5ac6dc6..3e780197a393 100644 --- a/packages/seacas/libraries/exodus/test/testwt-oned.c +++ b/packages/seacas/libraries/exodus/test/testwt-oned.c @@ -101,7 +101,7 @@ int main(int argc, char **argv) elem_map[i - 1] = 10 * i; } - EXCHECK(ex_put_map(exoid, elem_map)); + EXCHECK(ex_put_id_map(exoid, EX_ELEM_MAP, elem_map)); free(elem_map); /* write element block parameters */ diff --git a/packages/seacas/libraries/exodus/test/testwt-oned.dmp b/packages/seacas/libraries/exodus/test/testwt-oned.dmp index d41ccea09db1..0f69e924025e 100644 --- a/packages/seacas/libraries/exodus/test/testwt-oned.dmp +++ b/packages/seacas/libraries/exodus/test/testwt-oned.dmp @@ -50,7 +50,7 @@ variables: char coor_names(num_dim, len_name) ; float nattrb(num_nodes, num_att_in_nblk) ; char nattrib_name(num_att_in_nblk, len_name) ; - int elem_map(num_elem) ; + int elem_num_map(num_elem) ; float attrib1(num_el_in_blk1, num_att_in_blk1) ; char attrib_name1(num_att_in_blk1, len_name) ; int connect1(num_el_in_blk1, num_nod_per_el1) ; @@ -104,7 +104,6 @@ variables: float vals_nset_var3ns2(time_step, num_nod_ns2) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :title = "This is a test" ; data: @@ -123,7 +122,7 @@ data: ss_prop1 = 1, 2 ; - coordx = 1, 1.1052, 1.2214, 1.3499, 1.4918, 1.6487, 1.8221, 2.0138, 2.2255, + coordx = 1, 1.1052, 1.2214, 1.3499, 1.4918, 1.6487, 1.8221, 2.0138, 2.2255, 2.4596 ; eb_names = @@ -157,7 +156,7 @@ data: nattrib_name = "Node_attr_1" ; - elem_map = 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ; + elem_num_map = 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 ; attrib1 = 0, diff --git a/packages/seacas/libraries/exodus/test/testwt-partial.c b/packages/seacas/libraries/exodus/test/testwt-partial.c index cbab96c1e6be..6e3cb17737e7 100644 --- a/packages/seacas/libraries/exodus/test/testwt-partial.c +++ b/packages/seacas/libraries/exodus/test/testwt-partial.c @@ -271,8 +271,8 @@ int main(int argc, char **argv) elem_map[i - 1] = i; } - error = ex_put_map(exoid, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); if (error) { ex_close(exoid); diff --git a/packages/seacas/libraries/exodus/test/testwt-results.dmp b/packages/seacas/libraries/exodus/test/testwt-results.dmp index e7f768eff47f..c89756c8999f 100644 --- a/packages/seacas/libraries/exodus/test/testwt-results.dmp +++ b/packages/seacas/libraries/exodus/test/testwt-results.dmp @@ -51,7 +51,6 @@ variables: int elem_var_tab(num_el_blk, num_elem_var) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :title = "This is a test" ; data: @@ -91,67 +90,67 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, - 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, 1.54, 1.56, 1.58, 1.6, 1.62, 1.64, 1.66, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, 1.81, 1.84, 1.87, 1.9, 1.93, 1.96, 1.99, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, - 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, - 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, - 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, 2.62, 2.68, 2.74, 2.8, 2.86, 2.92, 2.98, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, 2.89, 2.96, 3.03, 3.1, 3.17, 3.24, 3.31, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, - 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, 3.16, 3.24, 3.32, 3.4, 3.48, 3.56, 3.64, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, 3.43, 3.52, 3.61, 3.7, 3.79, 3.88, 3.97, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, - 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, - 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, 2.54, 2.56, 2.58, 2.6, 2.62, 2.64, 2.66, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, 2.81, 2.84, 2.87, 2.9, 2.93, 2.96, 2.99, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, - 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, 3.08, 3.12, 3.16, 3.2, 3.24, 3.28, 3.32, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, - 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, 3.62, 3.68, 3.74, 3.8, 3.86, 3.92, 3.98, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, 3.89, 3.96, 4.03, 4.1, 4.17, 4.24, 4.31, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, - 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, 4.16, 4.24, 4.32, 4.4, 4.48, 4.56, 4.64, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, 4.43, 4.52, 4.61, 4.7, 4.79, 4.88, 4.97, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, - 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3 ; name_elem_var = diff --git a/packages/seacas/libraries/exodus/test/testwt-zeroe.dmp b/packages/seacas/libraries/exodus/test/testwt-zeroe.dmp index 39f841c5c66a..44a4ae1b3386 100644 --- a/packages/seacas/libraries/exodus/test/testwt-zeroe.dmp +++ b/packages/seacas/libraries/exodus/test/testwt-zeroe.dmp @@ -41,7 +41,6 @@ variables: float vals_nod_var2(time_step, num_nodes) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; @@ -53,13 +52,13 @@ data: ns_prop1 = 20, 21 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0, 2.7, 6, 5.7, 3.7, 0, 10, 10 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2, 1.7, 1.7, 1.7, 0, 0, 0, 10 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0, 2.7, 3.3, 1.7, 2.3, 0, 0, 10 ; ns_names = @@ -118,66 +117,66 @@ data: "nod_var1" ; vals_nod_var1 = - 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, - 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, + 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, 1.1, 1.11, 1.12, + 1.13, 1.14, 1.15, 1.16, 1.17, 1.18, 1.19, 1.2, 1.21, 1.22, 1.23, 1.24, 1.25, 1.26, 1.27, 1.28, 1.29, 1.3, 1.31, 1.32, 1.33, - 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, - 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, + 1.02, 1.04, 1.06, 1.08, 1.1, 1.12, 1.14, 1.16, 1.18, 1.2, 1.22, 1.24, 1.26, + 1.28, 1.3, 1.32, 1.34, 1.36, 1.38, 1.4, 1.42, 1.44, 1.46, 1.48, 1.5, 1.52, 1.54, 1.56, 1.58, 1.6, 1.62, 1.64, 1.66, - 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, - 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, + 1.03, 1.06, 1.09, 1.12, 1.15, 1.18, 1.21, 1.24, 1.27, 1.3, 1.33, 1.36, + 1.39, 1.42, 1.45, 1.48, 1.51, 1.54, 1.57, 1.6, 1.63, 1.66, 1.69, 1.72, 1.75, 1.78, 1.81, 1.84, 1.87, 1.9, 1.93, 1.96, 1.99, - 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, - 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, + 1.04, 1.08, 1.12, 1.16, 1.2, 1.24, 1.28, 1.32, 1.36, 1.4, 1.44, 1.48, 1.52, + 1.56, 1.6, 1.64, 1.68, 1.72, 1.76, 1.8, 1.84, 1.88, 1.92, 1.96, 2, 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, - 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, - 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, + 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.55, 1.6, 1.65, + 1.7, 1.75, 1.8, 1.85, 1.9, 1.95, 2, 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, - 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, + 1.06, 1.12, 1.18, 1.24, 1.3, 1.36, 1.42, 1.48, 1.54, 1.6, 1.66, 1.72, 1.78, + 1.84, 1.9, 1.96, 2.02, 2.08, 2.14, 2.2, 2.26, 2.32, 2.38, 2.44, 2.5, 2.56, 2.62, 2.68, 2.74, 2.8, 2.86, 2.92, 2.98, - 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, - 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, + 1.07, 1.14, 1.21, 1.28, 1.35, 1.42, 1.49, 1.56, 1.63, 1.7, 1.77, 1.84, + 1.91, 1.98, 2.05, 2.12, 2.19, 2.26, 2.33, 2.4, 2.47, 2.54, 2.61, 2.68, 2.75, 2.82, 2.89, 2.96, 3.03, 3.1, 3.17, 3.24, 3.31, - 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, - 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, + 1.08, 1.16, 1.24, 1.32, 1.4, 1.48, 1.56, 1.64, 1.72, 1.8, 1.88, 1.96, 2.04, + 2.12, 2.2, 2.28, 2.36, 2.44, 2.52, 2.6, 2.68, 2.76, 2.84, 2.92, 3, 3.08, 3.16, 3.24, 3.32, 3.4, 3.48, 3.56, 3.64, - 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, - 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, + 1.09, 1.18, 1.27, 1.36, 1.45, 1.54, 1.63, 1.72, 1.81, 1.9, 1.99, 2.08, + 2.17, 2.26, 2.35, 2.44, 2.53, 2.62, 2.71, 2.8, 2.89, 2.98, 3.07, 3.16, 3.25, 3.34, 3.43, 3.52, 3.61, 3.7, 3.79, 3.88, 3.97, - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, - 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, + 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3 ; vals_nod_var2 = - 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, - 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, + 2.01, 2.02, 2.03, 2.04, 2.05, 2.06, 2.07, 2.08, 2.09, 2.1, 2.11, 2.12, + 2.13, 2.14, 2.15, 2.16, 2.17, 2.18, 2.19, 2.2, 2.21, 2.22, 2.23, 2.24, 2.25, 2.26, 2.27, 2.28, 2.29, 2.3, 2.31, 2.32, 2.33, - 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, - 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, + 2.02, 2.04, 2.06, 2.08, 2.1, 2.12, 2.14, 2.16, 2.18, 2.2, 2.22, 2.24, 2.26, + 2.28, 2.3, 2.32, 2.34, 2.36, 2.38, 2.4, 2.42, 2.44, 2.46, 2.48, 2.5, 2.52, 2.54, 2.56, 2.58, 2.6, 2.62, 2.64, 2.66, - 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, - 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, + 2.03, 2.06, 2.09, 2.12, 2.15, 2.18, 2.21, 2.24, 2.27, 2.3, 2.33, 2.36, + 2.39, 2.42, 2.45, 2.48, 2.51, 2.54, 2.57, 2.6, 2.63, 2.66, 2.69, 2.72, 2.75, 2.78, 2.81, 2.84, 2.87, 2.9, 2.93, 2.96, 2.99, - 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, - 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, + 2.04, 2.08, 2.12, 2.16, 2.2, 2.24, 2.28, 2.32, 2.36, 2.4, 2.44, 2.48, 2.52, + 2.56, 2.6, 2.64, 2.68, 2.72, 2.76, 2.8, 2.84, 2.88, 2.92, 2.96, 3, 3.04, 3.08, 3.12, 3.16, 3.2, 3.24, 3.28, 3.32, - 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, - 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, + 2.05, 2.1, 2.15, 2.2, 2.25, 2.3, 2.35, 2.4, 2.45, 2.5, 2.55, 2.6, 2.65, + 2.7, 2.75, 2.8, 2.85, 2.9, 2.95, 3, 3.05, 3.1, 3.15, 3.2, 3.25, 3.3, 3.35, 3.4, 3.45, 3.5, 3.55, 3.6, 3.65, - 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, - 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, + 2.06, 2.12, 2.18, 2.24, 2.3, 2.36, 2.42, 2.48, 2.54, 2.6, 2.66, 2.72, 2.78, + 2.84, 2.9, 2.96, 3.02, 3.08, 3.14, 3.2, 3.26, 3.32, 3.38, 3.44, 3.5, 3.56, 3.62, 3.68, 3.74, 3.8, 3.86, 3.92, 3.98, - 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, - 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, + 2.07, 2.14, 2.21, 2.28, 2.35, 2.42, 2.49, 2.56, 2.63, 2.7, 2.77, 2.84, + 2.91, 2.98, 3.05, 3.12, 3.19, 3.26, 3.33, 3.4, 3.47, 3.54, 3.61, 3.68, 3.75, 3.82, 3.89, 3.96, 4.03, 4.1, 4.17, 4.24, 4.31, - 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, - 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, + 2.08, 2.16, 2.24, 2.32, 2.4, 2.48, 2.56, 2.64, 2.72, 2.8, 2.88, 2.96, 3.04, + 3.12, 3.2, 3.28, 3.36, 3.44, 3.52, 3.6, 3.68, 3.76, 3.84, 3.92, 4, 4.08, 4.16, 4.24, 4.32, 4.4, 4.48, 4.56, 4.64, - 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, - 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, + 2.09, 2.18, 2.27, 2.36, 2.45, 2.54, 2.63, 2.72, 2.81, 2.9, 2.99, 3.08, + 3.17, 3.26, 3.35, 3.44, 3.53, 3.62, 3.71, 3.8, 3.89, 3.98, 4.07, 4.16, 4.25, 4.34, 4.43, 4.52, 4.61, 4.7, 4.79, 4.88, 4.97, - 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, - 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, + 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, + 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3 ; } diff --git a/packages/seacas/libraries/exodus/test/testwt-zeron.dmp b/packages/seacas/libraries/exodus/test/testwt-zeron.dmp index 29e8f86137a3..ecb0c9f5132a 100644 --- a/packages/seacas/libraries/exodus/test/testwt-zeron.dmp +++ b/packages/seacas/libraries/exodus/test/testwt-zeron.dmp @@ -18,7 +18,6 @@ variables: float vals_glo_var(time_step, num_glo_var) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; diff --git a/packages/seacas/libraries/exodus/test/testwt.c b/packages/seacas/libraries/exodus/test/testwt.c index a97d42a54d3c..bef16b7f6684 100644 --- a/packages/seacas/libraries/exodus/test/testwt.c +++ b/packages/seacas/libraries/exodus/test/testwt.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -26,9 +26,9 @@ #define EXCHECK(funcall) \ do { \ - int error = (funcall); \ - printf("after %s, error = %d\n", TOSTRING(funcall), error); \ - if (error != EX_NOERR && error != EX_WARN) { \ + int f_error = (funcall); \ + printf("after %s, error = %d\n", TOSTRING(funcall), f_error); \ + if (f_error != EX_NOERR && f_error != EX_WARN) { \ fprintf(stderr, "Error calling %s\n", TOSTRING(funcall)); \ ex_close(exoid); \ exit(-1); \ @@ -130,14 +130,13 @@ int main(int argc, char **argv) EXCHECK(ex_put_attr_names(exoid, EX_NODAL, 0, attrib_names)); } - /* write element order map */ - + /* write element id map */ int *elem_map = (int *)calloc(num_elem, sizeof(int)); for (int i = 1; i <= num_elem; i++) { - elem_map[i - 1] = i; + elem_map[i - 1] = i * 10; } - EXCHECK(ex_put_map(exoid, elem_map)); + EXCHECK(ex_put_id_map(exoid, EX_ELEM_MAP, elem_map)); free(elem_map); @@ -464,10 +463,12 @@ int main(int argc, char **argv) /* write element variable truth table */ int *truth_tab = (int *)calloc((num_elem_blk * num_ele_vars), sizeof(int)); - int k = 0; - for (int i = 0; i < num_elem_blk; i++) { - for (int j = 0; j < num_ele_vars; j++) { - truth_tab[k++] = 1; + { + int k = 0; + for (int i = 0; i < num_elem_blk; i++) { + for (int j = 0; j < num_ele_vars; j++) { + truth_tab[k++] = 1; + } } } diff --git a/packages/seacas/libraries/exodus/test/testwt2.c b/packages/seacas/libraries/exodus/test/testwt2.c index 3b9c86b4e518..ff56678a73a8 100644 --- a/packages/seacas/libraries/exodus/test/testwt2.c +++ b/packages/seacas/libraries/exodus/test/testwt2.c @@ -234,8 +234,8 @@ int main(int argc, char **argv) elem_map[i - 1] = i; } - error = ex_put_map(exoid, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); free(elem_map); @@ -245,8 +245,8 @@ int main(int argc, char **argv) elem_map2[i - 1] = i; } - error = ex_put_map(exoid2, elem_map2); - printf("after ex_put_map (2), error = %d\n", error); + error = ex_put_id_map(exoid2, EX_ELEM_MAP, elem_map2); + printf("after ex_put_id_map (2), error = %d\n", error); free(elem_map2); diff --git a/packages/seacas/libraries/exodus/test/testwt_clb.c b/packages/seacas/libraries/exodus/test/testwt_clb.c index 91fbf8cf5488..1e3868b110b6 100644 --- a/packages/seacas/libraries/exodus/test/testwt_clb.c +++ b/packages/seacas/libraries/exodus/test/testwt_clb.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -229,7 +229,7 @@ int main(int argc, char **argv) elem_map[i - 1] = i; } - EXCHECK(ex_put_map(exoid, elem_map)); + EXCHECK(ex_put_id_map(exoid, EX_ELEM_MAP, elem_map)); free(elem_map); @@ -344,11 +344,10 @@ int main(int argc, char **argv) EXCHECK(ex_put_attr(exoid, EX_ELEM_BLOCK, ebids[6], attrib)); /* write individual node sets */ - int nsids[] = {20, 21}; int num_nodes_per_set[] = {5, 3}; - int num_df_per_set[] = {5, 3}; { + int num_df_per_set[] = {5, 3}; struct ex_set_specs set_specs; set_specs.sets_ids = nsids; diff --git a/packages/seacas/libraries/exodus/test/testwt_nc.c b/packages/seacas/libraries/exodus/test/testwt_nc.c index 26b50dd7602b..18fffc2b4fc1 100644 --- a/packages/seacas/libraries/exodus/test/testwt_nc.c +++ b/packages/seacas/libraries/exodus/test/testwt_nc.c @@ -263,16 +263,14 @@ int main(int argc, char **argv) } } - /* write element order map */ - elem_map = (int *)calloc(num_elem, sizeof(int)); for (i = 1; i <= num_elem; i++) { - elem_map[i - 1] = i; + elem_map[i - 1] = 10 * i; } - error = ex_put_map(exoid, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); if (error) { ex_close(exoid); diff --git a/packages/seacas/libraries/exodus/test/testwt_nossnsdf.c b/packages/seacas/libraries/exodus/test/testwt_nossnsdf.c index 00c0e28cb9df..afe7ec31084c 100644 --- a/packages/seacas/libraries/exodus/test/testwt_nossnsdf.c +++ b/packages/seacas/libraries/exodus/test/testwt_nossnsdf.c @@ -220,7 +220,7 @@ int main(int argc, char **argv) } error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); - printf("after ex_put_elem_num_map, error = %d\n", error); + printf("after ex_put_id_map, error = %d\n", error); free(elem_map); diff --git a/packages/seacas/libraries/exodus/test/testwt_ss.dmp b/packages/seacas/libraries/exodus/test/testwt_ss.dmp index ecd8cd7a1263..03feeeda80ab 100644 --- a/packages/seacas/libraries/exodus/test/testwt_ss.dmp +++ b/packages/seacas/libraries/exodus/test/testwt_ss.dmp @@ -116,7 +116,6 @@ variables: char info_records(num_info, len_line) ; // global attributes: - :floating_point_word_size = 4 ; :file_size = 1 ; :maximum_name_length = 32 ; :title = "This is a test" ; @@ -134,13 +133,13 @@ data: ss_prop1 = 30, 31, 32, 33, 34, 35, 36, 37, 38 ; - coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, + coordx = 0, 1, 1, 0, 1, 2, 2, 1, 0, 10, 10, 1, 1, 10, 10, 1, 0, 1, 10, 7, 3, 6, 0, 3, 6, 0, 2.7, 6, 5.7, 3.7, 2.7, 6, 5.7 ; - coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, + coordy = 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 10, 10, 10, 10, 0, 0, 0, 5, 0, 0, 0, 2, 2, 2, 1.7, 1.7, 1.7, 0, 1.7, 1.7, 1.7 ; - coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, + coordz = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10, -10, 0, 0, -10, -10, 0, 5, 2, 3, 6, 0, 0, 6, 2, 0, 2.7, 3.3, 1.7, 2.3, 2.7, 3.3, 1.7 ; eb_names = diff --git a/packages/seacas/libraries/exodus/test/testwtd.c b/packages/seacas/libraries/exodus/test/testwtd.c index 07e06df0281d..e32af18e5146 100644 --- a/packages/seacas/libraries/exodus/test/testwtd.c +++ b/packages/seacas/libraries/exodus/test/testwtd.c @@ -193,8 +193,8 @@ int main(int argc, char **argv) elem_map[i - 1] = i; } - error = ex_put_map(exoid, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); free(elem_map); diff --git a/packages/seacas/libraries/exodus/test/testwtm.c b/packages/seacas/libraries/exodus/test/testwtm.c index 7ea78fa208db..0fe0151e8986 100644 --- a/packages/seacas/libraries/exodus/test/testwtm.c +++ b/packages/seacas/libraries/exodus/test/testwtm.c @@ -256,8 +256,8 @@ int main(int argc, char **argv) elem_map[i - 1] = i; } - error = ex_put_map(exoid, elem_map); - printf("after ex_put_map, error = %d\n", error); + error = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); + printf("after ex_put_id_map, error = %d\n", error); free(elem_map); @@ -268,8 +268,8 @@ int main(int argc, char **argv) } for (n = 0; n < nexofiles; n++) { - error = ex_put_map(exoidm[n], elem_map2); - printf("after ex_put_map (%d), error = %d\n", n, error); + error = ex_put_id_map(exoidm[n], EX_ELEM_MAP, elem_map2); + printf("after ex_put_id_map (%d), error = %d\n", n, error); } free(elem_map2); diff --git a/packages/seacas/libraries/exodus/test/twod.c b/packages/seacas/libraries/exodus/test/twod.c index a01c8fc7dbf8..ef5ec0487340 100644 --- a/packages/seacas/libraries/exodus/test/twod.c +++ b/packages/seacas/libraries/exodus/test/twod.c @@ -84,7 +84,7 @@ int main(int argc, char **argv) { int elem_map[] = {11, 21, 31, 41, 52, 62, 72, 82, 93, 103, 113, 123, 133, 143, 153, 163, 174, 184, 194, 204}; - ex_put_elem_num_map(exoid, elem_map); + ex_put_id_map(exoid, EX_ELEM_MAP, elem_map); } /* write element block parameters */ diff --git a/packages/seacas/libraries/exodus/test/update_all_tests b/packages/seacas/libraries/exodus/test/update_all_tests index 2144a2f0db46..5a8019dd8947 100644 --- a/packages/seacas/libraries/exodus/test/update_all_tests +++ b/packages/seacas/libraries/exodus/test/update_all_tests @@ -11,8 +11,8 @@ #set PREFIX = "valgrind --tool=memcheck" set PREFIX = "" -set SRCDIR = /Users/gdsjaar/src/seacas/build/packages/seacas/libraries/exodus/test -set NCDUMP = /Users/gdsjaar/src/seacas/bin/ncdump +SRCDIR=/Users/gdsjaar/src/seacas/build/packages/seacas/libraries/exodus/test +NCDUMP=/Users/gdsjaar/src/seacas/bin/ncdump echo "************************************************************************" echo "************************************************************************" rm -f test.output @@ -20,7 +20,7 @@ echo "testwt - single precision write test..." echo "begin testwt" > test.output ${PREFIX} ${SRCDIR}/testwt >> test.output echo "end testwt" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version > ${SRCDIR}/test.dmp +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue |grep -v maximum_name_length > ${SRCDIR}/test.dmp echo "testrd - single precision read test..." echo "begin testrd" >> test.output @@ -36,37 +36,37 @@ echo "testcp_ss - single-to-single precision copy test..." echo "begin testcp_ss" >> test.output ${PREFIX} ${SRCDIR}/testcp >> test.output echo "end testcp_ss" >> test.output -${NCDUMP} -d5,5 testcp.exo | grep -v version > ${SRCDIR}/testcp_ss.dmp +${NCDUMP} -d5,5 testcp.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testcp_ss.dmp echo "testcp_sd - single-to-double precision copy test..." echo "begin testcp_sd" >> test.output ${PREFIX} ${SRCDIR}/testcpd >> test.output echo "end testcp_sd" >> test.output -${NCDUMP} -d5,5 testcpd.exo | grep -v version > ${SRCDIR}/testcp_sd.dmp +${NCDUMP} -d5,5 testcpd.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testcp_sd.dmp echo "testcp_ln - large model to normal model single precision copy test..." echo "begin testcp_ln" >> test.output ${PREFIX} ${SRCDIR}/testcp_ln >> test.output echo "end testcp_ln" >> test.output -${NCDUMP} -d5,5 testcp.exo | grep -v version > ${SRCDIR}/testcp_ln.dmp +${NCDUMP} -d5,5 testcp.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testcp_ln.dmp echo "testcp_nl - normal_model to large_model single precision copy test..." echo "begin testcp_nl" >> test.output ${PREFIX} ${SRCDIR}/testcp_nl >> test.output echo "end testcp_nl" >> test.output -${NCDUMP} -d5,5 testcp_nl.exo | grep -v version > ${SRCDIR}/testcp_nl.dmp +${NCDUMP} -d5,5 testcp_nl.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testcp_nl.dmp echo "testwt_clb - single precision write test using concatenated puts..." echo "begin testwt_clb" >> test.output ${PREFIX} ${SRCDIR}/testwt_clb >> test.output echo "end testwt_clb" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version > ${SRCDIR}/test_clb.dmp +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/test_clb.dmp echo "testwtd - double precision write test..." echo "begin testwtd" >> test.output ${PREFIX} ${SRCDIR}/testwtd >> test.output echo "end testwtd" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version > ${SRCDIR}/testd.dmp +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testd.dmp echo "testrdd - double precision read test..." echo "begin testrdd" >> test.output @@ -77,20 +77,20 @@ echo "testcp_dd - double-to-double precision copy test..." echo "begin testcp_dd" >> test.output ${PREFIX} ${SRCDIR}/testcpd >> test.output echo "end testcp_dd" >> test.output -${NCDUMP} -d5,5 testcpd.exo | grep -v version > ${SRCDIR}/testcp_dd.dmp +${NCDUMP} -d5,5 testcpd.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testcp_dd.dmp echo "testcp_ds - double-to-single precision copy test..." echo "begin testcp_ds" >> test.output ${PREFIX} ${SRCDIR}/testcp >> test.output echo "end testcp_ds" >> test.output -${NCDUMP} -d5,5 testcp.exo | grep -v version > ${SRCDIR}/testcp_ds.dmp +${NCDUMP} -d5,5 testcp.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testcp_ds.dmp echo "testwt1 - single precision write files with several side sets..." echo "testwt1 ... [Expect WEDGE6 warning from this test]" echo "begin testwt1" >> test.output ${PREFIX} ${SRCDIR}/testwt1 >> test.output echo "end testwt1" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version > ${SRCDIR}/test1.dmp +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/test1.dmp echo "testrd1 - single precision read test of a file with several side sets..." echo "testrd1 ... [Expect file create failure error, NOCLOBBER]" @@ -104,7 +104,7 @@ echo "testwt_ss ... [Expect WEDGE6 warning from this test]" echo "begin testwt_ss" >> test.output ${PREFIX} ${SRCDIR}/testwt_ss >> test.output echo "end testwt_ss" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version > ${SRCDIR}/testwt_ss.dmp +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testwt_ss.dmp echo "testrd_ss - read test of a file with several side sets..." echo "testrd_ss ... [Expect warning for NULL sidesets 30 and 31]" @@ -116,20 +116,20 @@ echo "testwt2 - single precision write 2 files (simultaneously open) test..." echo "begin testwt2" >> test.output ${PREFIX} ${SRCDIR}/testwt2 >> test.output echo "end testwt2" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version > ${SRCDIR}/test2-1.dmp -${NCDUMP} -d5,5 test2.exo | grep -v version > ${SRCDIR}/test2-2.dmp +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/test2-1.dmp +${NCDUMP} -d5,5 test2.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/test2-2.dmp echo "testrdwt - read from one and write to another (simultaneously open) file..." echo "begin testrdwt" >> test.output ${PREFIX} ${SRCDIR}/testrdwt >> test.output echo "end testrdwt" >> test.output -${NCDUMP} -d5,5 test2.exo | grep -v version > ${SRCDIR}/test2.dmp +${NCDUMP} -d5,5 test2.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/test2.dmp echo "testwt_nc - write x y z components of coordinates separately..." echo "begin testwt_nc" >> test.output ${PREFIX} ${SRCDIR}/testwt_nc >> test.output echo "end testwt_nc" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version > ${SRCDIR}/test.dmp +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/test.dmp echo "testrd_nc - read x y z components of coordinates separately..." echo "begin testrd_nc" >> test.output @@ -140,7 +140,7 @@ echo "testwt-zeron - write file with zero nodes and elements..." echo "begin testwt-zeron" >> test.output ${PREFIX} ${SRCDIR}/testwt-zeron >> test.output echo "end testwt-zeron" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version > ${SRCDIR}/testwt-zeron.dmp +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testwt-zeron.dmp echo "testrd - read test of file with zero nodes and elements..." echo "begin testrd zero nodes" >> test.output @@ -151,7 +151,7 @@ echo "testwt-zeroe - write file with zero elements..." echo "begin testwt-zeroe" >> test.output ${PREFIX} ${SRCDIR}/testwt-zeroe >> test.output echo "end testwt-zeroe" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version > ${SRCDIR}/testwt-zeroe.dmp +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testwt-zeroe.dmp echo "testrd - read test of file with zero elements..." echo "begin testrd zero elements" >> test.output @@ -167,7 +167,7 @@ echo "testwt-nsided - write file with nsided elements..." echo "begin testwt-nsided" >> test.output ${PREFIX} ${SRCDIR}/testwt-nsided >> test.output echo "end testwt-nsided" >> test.output -${NCDUMP} -d5,5 test-nsided.exo | grep -v version > ${SRCDIR}/testwt-nsided.dmp +${NCDUMP} -d5,5 test-nsided.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testwt-nsided.dmp echo "testrd-nsided - read file with nsided elements..." echo "begin testrd-nsided" >> test.output @@ -178,7 +178,7 @@ echo "testwt-nfaced - write file with nfaced elements..." echo "begin testwt-nfaced" >> test.output ${PREFIX} ${SRCDIR}/testwt-nfaced >> test.output echo "end testwt-nfaced" >> test.output -${NCDUMP} -d5,5 test-nfaced.exo | grep -v version > ${SRCDIR}/testwt-nfaced.dmp +${NCDUMP} -d5,5 test-nfaced.exo | grep -v version | grep -v int64_status| grep -v _FillValue > ${SRCDIR}/testwt-nfaced.dmp echo "testrd-nfaced - read file with nfaced elements..." echo "begin testrd-nfaced" >> test.output @@ -189,7 +189,7 @@ echo "testwt-long-name - write file with long (64-character) names..." echo "begin testwt-long-name" >> test.output ${PREFIX} ${SRCDIR}/testwt-long-name >> test.output echo "end testwt-long-name" >> test.output -${NCDUMP} -d5,5 test.exo | grep -v version > ${SRCDIR}/testwt-long-name.dmp +${NCDUMP} -d5,5 test.exo | grep -v version | grep -v int64_status| grep -v _FillValue ${SRCDIR}/testwt-long-name.dmp echo "testrd - read long name file truncating to 32 characters on read..." echo "begin testrd (truncate)" >> test.output diff --git a/packages/seacas/libraries/exodus_for/src/exo_jack.c b/packages/seacas/libraries/exodus_for/src/exo_jack.c index fe2d62969a4a..cc612aaafc62 100644 --- a/packages/seacas/libraries/exodus_for/src/exo_jack.c +++ b/packages/seacas/libraries/exodus_for/src/exo_jack.c @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -46,7 +46,7 @@ #if defined(Build64) && !defined(DEFAULT_REAL_INT) /* 64-bit */ -#define real double +#define real double #define entity_id ex_entity_id #ifdef ADDC_ @@ -61,7 +61,7 @@ #else /* 32-bit */ -#define real float +#define real float #define entity_id int #ifdef ADDC_ #define F2C(name, NAME) name##_ @@ -2421,7 +2421,7 @@ void F2C(expfrm, EXPFRM)(int *idexo, int *nframe, void_int *cfids, real *coord, * Routine to return floating point word size * \sa ex__get_cpu_ws() */ -int F2C(excpws, EXCPWS)() { return (ex__get_cpu_ws()); } +int F2C(excpws, EXCPWS)(void) { return (ex__get_cpu_ws()); } /*! * Routine to return large model setting diff --git a/packages/seacas/libraries/ioss/src/Ioss_Beam4.C b/packages/seacas/libraries/ioss/src/Ioss_Beam4.C index 4054b5a793fc..2201bdd3c38a 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_Beam4.C +++ b/packages/seacas/libraries/ioss/src/Ioss_Beam4.C @@ -1,4 +1,4 @@ -// Copyright(C) 1999-2021 National Technology & Engineering Solutions +// Copyright(C) 1999-2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -86,11 +86,13 @@ Ioss::IntVector Ioss::Beam4::edge_connectivity(int edge_number) const connectivity[0] = 0; connectivity[1] = 1; connectivity[2] = 2; + connectivity[3] = 3; } else { connectivity[0] = 1; connectivity[1] = 0; - connectivity[2] = 2; + connectivity[2] = 3; + connectivity[3] = 2; } return connectivity; } diff --git a/packages/seacas/libraries/ioss/src/Ioss_CodeTypes.h b/packages/seacas/libraries/ioss/src/Ioss_CodeTypes.h index f0a8bee4784a..6417a8439807 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_CodeTypes.h +++ b/packages/seacas/libraries/ioss/src/Ioss_CodeTypes.h @@ -48,7 +48,7 @@ inline const std::string IOSS_SYM_TENSOR() { return std::string("sym_tensor_33") #if defined(SEACAS_HAVE_MPI) #include #define PAR_UNUSED(x) -using Ioss_MPI_Comm = MPI_Comm; +using Ioss_MPI_Comm = MPI_Comm; #else #define PAR_UNUSED(x) \ do { \ diff --git a/packages/seacas/libraries/ioss/src/Ioss_DataPool.h b/packages/seacas/libraries/ioss/src/Ioss_DataPool.h index 7441f39f98a9..9920fb965a80 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_DataPool.h +++ b/packages/seacas/libraries/ioss/src/Ioss_DataPool.h @@ -1,4 +1,4 @@ -// Copyright(C) 2020, 2021 National Technology & Engineering Solutions +// Copyright(C) 2020, 2021, 2022 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // @@ -12,30 +12,32 @@ struct DataPool { // Data space shared by most field input/output routines... - std::vector data; - std::vector data_int; - std::vector data_int64; - std::vector data_double; - std::vector data_complex; + std::vector data{}; + std::vector data_int{}; + std::vector data_int64{}; + std::vector data_double{}; + std::vector data_complex{}; #ifdef SEACAS_HAVE_KOKKOS - Kokkos::View data_view_char; - Kokkos::View data_view_int; - Kokkos::View data_view_int64; - Kokkos::View data_view_double; + Kokkos::View data_view_char{}; + Kokkos::View data_view_int{}; + Kokkos::View data_view_int64{}; + Kokkos::View data_view_double{}; // Kokkos::View data_view_complex cannot be a global variable, // Since Kokkos::initialize() has not yet been called. Also, a Kokkos:View cannot // have type std::complex entities. - Kokkos::View data_view_2D_char; - Kokkos::View data_view_2D_int; - Kokkos::View data_view_2D_int64; - Kokkos::View data_view_2D_double; + Kokkos::View data_view_2D_char{}; + Kokkos::View data_view_2D_int{}; + Kokkos::View data_view_2D_int64{}; + Kokkos::View data_view_2D_double{}; // Kokkos::View data_view_2D_complex cannot be a global variable, // Since Kokkos::initialize() has not yet been called. Also, a Kokkos:View cannot // have type std::complex entities. - Kokkos::View data_view_2D_char_layout_space; - Kokkos::View data_view_2D_int_layout_space; - Kokkos::View data_view_2D_int64_layout_space; - Kokkos::View data_view_2D_double_layout_space; + Kokkos::View data_view_2D_char_layout_space{}; + Kokkos::View data_view_2D_int_layout_space{}; + Kokkos::View + data_view_2D_int64_layout_space{}; + Kokkos::View + data_view_2D_double_layout_space{}; // Kokkos::View // data_view_2D_complex_layout_space cannot be a global variable, // Since Kokkos::initialize() has not yet been called. Also, a Kokkos:View cannot diff --git a/packages/seacas/libraries/ioss/src/Ioss_DatabaseIO.C b/packages/seacas/libraries/ioss/src/Ioss_DatabaseIO.C index 9101a155167c..b87ee29a8de2 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_DatabaseIO.C +++ b/packages/seacas/libraries/ioss/src/Ioss_DatabaseIO.C @@ -187,6 +187,7 @@ namespace Ioss { util_.add_environment_properties(properties); Utils::check_set_bool_property(properties, "ENABLE_FIELD_RECOGNITION", enableFieldRecognition); + Utils::check_set_bool_property(properties, "IGNORE_REALN_FIELDS", m_ignoreRealnFields); if (properties.exists("FIELD_SUFFIX_SEPARATOR")) { std::string tmp = properties.get("FIELD_SUFFIX_SEPARATOR").get_string(); @@ -201,6 +202,37 @@ namespace Ioss { Utils::check_set_bool_property(properties, "FIELD_STRIP_TRAILING_UNDERSCORE", fieldStripTrailing_); + if (properties.exists("SURFACE_SPLIT_TYPE")) { + Ioss::SurfaceSplitType split_type = Ioss::SPLIT_INVALID; + auto type = properties.get("SURFACE_SPLIT_TYPE").get_type(); + if (type == Ioss::Property::INTEGER) { + int split = properties.get("SURFACE_SPLIT_TYPE").get_int(); + split_type = Ioss::int_to_surface_split(split); + } + else if (type == Ioss::Property::STRING) { + std::string split = properties.get("SURFACE_SPLIT_TYPE").get_string(); + if (Ioss::Utils::str_equal(split, "TOPOLOGY")) { + split_type = Ioss::SPLIT_BY_TOPOLOGIES; + } + else if (Ioss::Utils::str_equal(split, "BLOCK")) { + split_type = Ioss::SPLIT_BY_ELEMENT_BLOCK; + } + else if (Ioss::Utils::str_equal(split, "NO_SPLIT")) { + split_type = Ioss::SPLIT_BY_DONT_SPLIT; + } + else { + split_type = Ioss::SPLIT_INVALID; + fmt::print(Ioss::WARNING(), + "Invalid setting for SURFACE_SPLIT_TYPE Property ('{}'). Valid entries are " + "TOPOLOGY, BLOCK, NO_SPLIT. Ignoring.\n", + split); + } + } + if (split_type != Ioss::SPLIT_INVALID) { + set_surface_split_type(split_type); + } + } + if (properties.exists("INTEGER_SIZE_API")) { int isize = properties.get("INTEGER_SIZE_API").get_int(); if (isize == 8) { @@ -216,13 +248,8 @@ namespace Ioss { } } - if (properties.exists("CYCLE_COUNT")) { - cycleCount = properties.get("CYCLE_COUNT").get_int(); - } - - if (properties.exists("OVERLAY_COUNT")) { - overlayCount = properties.get("OVERLAY_COUNT").get_int(); - } + cycleCount = properties.get_optional("CYCLE_COUNT", cycleCount); + overlayCount = properties.get_optional("OVERLAY_COUNT", overlayCount); Utils::check_set_bool_property(properties, "ENABLE_TRACING", m_enableTracing); Utils::check_set_bool_property(properties, "TIME_STATE_INPUT_OUTPUT", m_timeStateInOut); @@ -299,7 +326,7 @@ namespace Ioss { { // If the user has explicitly set the suffix separator for this database, // then use it for all fields. - // If it was not explicity set, then use whatever the field has defined, + // If it was not explicitly set, then use whatever the field has defined, // of if field also has nothing explicitly set, use '_' char suffix = fieldSeparatorSpecified ? get_field_separator() : 1; return field.get_component_name(component, in_out, suffix); @@ -499,6 +526,7 @@ namespace Ioss { bool DatabaseIO::begin_state(int state, double time) { IOSS_FUNC_ENTER(m_); + progress(__func__); if (m_timeStateInOut) { m_stateStart = std::chrono::steady_clock::now(); } @@ -512,6 +540,7 @@ namespace Ioss { auto finish = std::chrono::steady_clock::now(); log_time(m_stateStart, finish, state, time, is_input(), singleProcOnly, util_); } + progress(__func__); return res; } @@ -722,6 +751,29 @@ namespace Ioss { } } + void DatabaseIO::set_assembly_omissions(const std::vector &omissions, + const std::vector &inclusions) + { + if (!omissions.empty() && !inclusions.empty()) { + // Only one can be non-empty + std::ostringstream errmsg; + fmt::print(errmsg, + "ERROR: Only one of assembly omission or inclusion can be non-empty" + " [{}]\n", + get_filename()); + IOSS_ERROR(errmsg); + } + + if (!omissions.empty()) { + assemblyOmissions.assign(omissions.cbegin(), omissions.cend()); + Ioss::sort(assemblyOmissions.begin(), assemblyOmissions.end()); + } + if (!inclusions.empty()) { + assemblyInclusions.assign(inclusions.cbegin(), inclusions.cend()); + Ioss::sort(assemblyInclusions.begin(), assemblyInclusions.end()); + } + } + // Check topology of all sides (face/edges) in model... void DatabaseIO::check_side_topology() const { diff --git a/packages/seacas/libraries/ioss/src/Ioss_DatabaseIO.h b/packages/seacas/libraries/ioss/src/Ioss_DatabaseIO.h index c3f10e29fb53..48f68b28bb10 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_DatabaseIO.h +++ b/packages/seacas/libraries/ioss/src/Ioss_DatabaseIO.h @@ -224,18 +224,21 @@ namespace Ioss { void openDatabase() const { IOSS_FUNC_ENTER(m_); + progress(__func__); openDatabase__(); } void closeDatabase() const { IOSS_FUNC_ENTER(m_); + progress(__func__); closeDatabase__(); } void flush_database() const { IOSS_FUNC_ENTER(m_); + progress(__func__); flush_database__(); } @@ -289,6 +292,7 @@ namespace Ioss { bool begin(Ioss::State state) { IOSS_FUNC_ENTER(m_); + progress(__func__); return begin__(state); } @@ -305,6 +309,7 @@ namespace Ioss { bool end(Ioss::State state) { IOSS_FUNC_ENTER(m_); + progress(__func__); return end__(state); } @@ -315,7 +320,9 @@ namespace Ioss { void read_meta_data() { IOSS_FUNC_ENTER(m_); - return read_meta_data__(); + progress("Begin read_meta_data()"); + read_meta_data__(); + progress("End read_meta_data()"); } void get_step_times() @@ -404,6 +411,9 @@ namespace Ioss { bool ignore_database_names() const { return ignoreDatabaseNames; } void ignore_database_names(bool yes_no) { ignoreDatabaseNames = yes_no; } + bool get_ignore_realn_fields() const { return m_ignoreRealnFields; } + void set_ignore_realn_fields(bool yes_no) { m_ignoreRealnFields = yes_no; } + /** \brief Get the length of the longest name in the database file. * * \returns The length, or 0 for unlimited. @@ -437,6 +447,9 @@ namespace Ioss { void set_block_omissions(const std::vector &omissions, const std::vector &inclusions = {}); + void set_assembly_omissions(const std::vector &omissions, + const std::vector &inclusions = {}); + void get_block_adjacencies(const Ioss::ElementBlock *eb, std::vector &block_adjacency) const { @@ -584,9 +597,9 @@ namespace Ioss { * run since the passed in filename is just the basename, not the * processor-specific filename. */ - std::string originalDBFilename; - std::string DBFilename; - mutable std::string decodedFilename; + std::string originalDBFilename{}; + std::string DBFilename{}; + mutable std::string decodedFilename{}; /*! * `bbName` is a temporary swizzled name which resides inside Burst Buffer namespace. @@ -618,7 +631,7 @@ namespace Ioss { void check_side_topology() const; /// Used to speed up faceblock/edgeblock calculations. - TopoContainer sideTopology; + TopoContainer sideTopology{}; /*! Typically used for restart output, but can be used for all output... * Maximum number of states on the output file. Overwrite the existing @@ -641,7 +654,7 @@ namespace Ioss { double timeScaleFactor{1.0}; Ioss::SurfaceSplitType splitType{SPLIT_BY_TOPOLOGIES}; - Ioss::DatabaseUsage dbUsage; + Ioss::DatabaseUsage dbUsage{}; mutable Ioss::DataSize dbIntSizeAPI{USE_INT32_API}; @@ -664,11 +677,13 @@ namespace Ioss { // element ids and offsets are still calculated assuming that the // blocks exist in the model... // Only one of these can have values and the other must be empty. - std::vector blockOmissions; - std::vector blockInclusions; + std::vector blockOmissions{}; + std::vector blockInclusions{}; + std::vector assemblyOmissions{}; + std::vector assemblyInclusions{}; - std::vector informationRecords; - std::vector qaRecords; + std::vector informationRecords{}; + std::vector qaRecords{}; //---Node Map -- Maps internal (1..NUMNP) ids to global ids used on the // application side. global = nodeMap[local] @@ -818,8 +833,8 @@ namespace Ioss { // True is default and required for parallel-io databases. // Even if false, metadata operations must be called by all processors - bool singleProcOnly; // True if history or heartbeat which is only written from proc 0... - bool doLogging{false}; // True if logging field input/output + bool singleProcOnly{false}; // True if history or heartbeat which is only written from proc 0... + bool doLogging{false}; // True if logging field input/output bool useGenericCanonicalName{ false}; // True if "block_id" is used as canonical name instead of the name // given on the mesh file e.g. "fireset". Both names are still aliases. @@ -830,6 +845,8 @@ namespace Ioss { bool m_timeStateInOut{false}; bool m_enableTracing{false}; + bool m_ignoreRealnFields{false}; // Do not recognize var_1, var_2, ..., var_n as an n-component + // field. Keep as n scalar fields. std::chrono::time_point m_stateStart; // Used for optional output step timing. }; diff --git a/packages/seacas/libraries/ioss/src/Ioss_Decomposition.C b/packages/seacas/libraries/ioss/src/Ioss_Decomposition.C index c61c039c9669..e90e8fe9611f 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_Decomposition.C +++ b/packages/seacas/libraries/ioss/src/Ioss_Decomposition.C @@ -165,8 +165,10 @@ namespace Ioss { return valid_methods; } - template Decomposition::Decomposition(const Ioss::PropertyManager &props, Ioss_MPI_Comm comm); - template Decomposition::Decomposition(const Ioss::PropertyManager &props, Ioss_MPI_Comm comm); + template Decomposition::Decomposition(const Ioss::PropertyManager &props, + Ioss_MPI_Comm comm); + template Decomposition::Decomposition(const Ioss::PropertyManager &props, + Ioss_MPI_Comm comm); template Decomposition::Decomposition(const Ioss::PropertyManager &props, Ioss_MPI_Comm comm) diff --git a/packages/seacas/libraries/ioss/src/Ioss_Decomposition.h b/packages/seacas/libraries/ioss/src/Ioss_Decomposition.h index 39d508460a07..33fdacde3afe 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_Decomposition.h +++ b/packages/seacas/libraries/ioss/src/Ioss_Decomposition.h @@ -125,7 +125,7 @@ namespace Ioss { double distributionFactorValue{ 0.0}; // If distributionFactorConstant == true, the constant value Ioss_MPI_Comm setComm_{Ioss::ParallelUtils::comm_null()}; - bool distributionFactorConstant{false}; // T if all distribution factors the same value. + bool distributionFactorConstant{false}; // T if all distribution factors the same value. }; template class Decomposition diff --git a/packages/seacas/libraries/ioss/src/Ioss_Doxygen.h b/packages/seacas/libraries/ioss/src/Ioss_Doxygen.h index 50fd20cb19ca..da706274869b 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_Doxygen.h +++ b/packages/seacas/libraries/ioss/src/Ioss_Doxygen.h @@ -75,14 +75,15 @@ PARALLEL_IO_MODE | netcdf4, hdf5, pnetcdf, (mpiio and mpiposix are deprecated) REAL_SIZE_DB | 4 / [8] | byte size of floating point stored on the database. REAL_SIZE_API | 4 / [8] | byte size of floating point used in api functions. -## Properties related to field interpretation +## Properties related to field and sideset/surface interpretation Property | Value | Description --------------------------|:--------:|----------------------------------------------------------- ENABLE_FIELD_RECOGNITION | [on]/off | Does the IOSS library combine scalar fields into higher-order fields (tensor, vector) based on suffix interpretation. + IGNORE_REALN_FIELDS | [off]/on | Do not recognize var_1, var_2, ..., var_n as an n-component field. Keep as n scalar fields. Currently ignored for composite fields. FIELD_SUFFIX_SEPARATOR | char / '_'| The character that is used to separate the base field name from the suffix. Default is underscore. FIELD_STRIP_TRAILING_UNDERSCORE | on / [off] | If `FIELD_SUFFIX_SEPARATOR` is empty and there are fields that end with an underscore, then strip the underscore. (`a_x`, `a_y`, `a_z` is vector field `a`). IGNORE_ATTRIBUTE_NAMES | on/[off] | Do not read the attribute names that may exist on an input database. Instead for an element block with N attributes, the fields will be named `attribute_1` ... `attribute_N` -## Properties related to underlying file type (exodus only) + SURFACE_SPLIT_TYPE | {type} | Specify how to split sidesets into homogeneous sideblocks. Either an integer or string: 1 or `TOPOLOGY`, 2 or `BLOCK`, 3 or `NO_SPLIT`. Default is `TOPOLOGY` if not specified. ## Output Database-Related Properties Property | Value | Description @@ -119,7 +120,7 @@ PARALLEL_IO_MODE | netcdf4, hdf5, pnetcdf, (mpiio and mpiposix are deprecated) SHOW_LEGEND | [on]/off | Should a legend be printed at the beginning of the output showing the field names for each column of data. SHOW_TIME_FIELD | on/[off] | Should the current analysis time be output as the first field. -## Experimental +## Experimental / Special Purpose Property | Value | Description -----------------------|:------:|----------------------------------------------------------- @@ -128,7 +129,18 @@ MEMORY_WRITE | on/[off] | experimental ENABLE_FILE_GROUPS | on/[off] | experimental MINIMAL_NEMESIS_INFO | on/[off] | special case, omit all nemesis data except for nodal communication map OMIT_EXODUS_NUM_MAPS | on/[off] | special case, do not output the node and element numbering map. - +EXODUS_CALL_GET_ALL_TIMES| [on] / off | special case -- should the `ex_get_all_times()` function be called. See below. + +* `EXODUS_CALL_GET_ALL_TIMES`: Typically only used in `isSerialParallel` +mode and the client is responsible for making sure that the step times +are handled correctly. All databases will know about the number of +timesteps, but if the `ex_get_all_times()` function call is skipped, then +the times on that database will all be zero. The use case is that in `isSerialParallel`, +each call to `ex_get_all_times()` for all files is performed +sequentially, so if you have hundreds to thousands of files, the time +for the call is additive and since timesteps are record variables in +netCDF, accessing the data for all timesteps involves lseeks +throughout the file. ## Debugging / Profiling diff --git a/packages/seacas/libraries/ioss/src/Ioss_ElementTopology.h b/packages/seacas/libraries/ioss/src/Ioss_ElementTopology.h index 13639e6d33a2..c6ea50363dee 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_ElementTopology.h +++ b/packages/seacas/libraries/ioss/src/Ioss_ElementTopology.h @@ -65,7 +65,7 @@ namespace Ioss { //: Return whether the topology describes an "element". If it //: isn't an element, then it is a component of an element. For - // example, a quadrilater Shell is an element, but a QuadFace is + // example, a quadrilateral Shell is an element, but a QuadFace is // not. // // Default implementation returns true if spatial_dimension() == diff --git a/packages/seacas/libraries/ioss/src/Ioss_Field.h b/packages/seacas/libraries/ioss/src/Ioss_Field.h index bfbcc487d8c0..fff3c06ad7c1 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_Field.h +++ b/packages/seacas/libraries/ioss/src/Ioss_Field.h @@ -110,6 +110,7 @@ namespace Ioss { /** \brief Get name of the 'component_indexth` component (1-based) * * \param[in] component_index 1-based index of the component to be named + * \param[in] in_out Is the field being read or written * \param[in] suffix optional suffix separator to be used if the separator * on the field is set to '1' which means 'unset' * \returns name of the specified component diff --git a/packages/seacas/libraries/ioss/src/Ioss_FileInfo.C b/packages/seacas/libraries/ioss/src/Ioss_FileInfo.C index 3f19f387e794..ca5f15de8922 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_FileInfo.C +++ b/packages/seacas/libraries/ioss/src/Ioss_FileInfo.C @@ -86,7 +86,7 @@ namespace Ioss { { PAR_UNUSED(communicator); PAR_UNUSED(where); - int sum = exists_ ? 1 : 0; + int sum = exists_ ? 1 : 0; #ifdef SEACAS_HAVE_MPI Ioss::ParallelUtils pu(communicator); @@ -98,13 +98,13 @@ namespace Ioss { pu.all_gather(sum, result); sum = std::accumulate(result.begin(), result.end(), 0); if (my_rank == 0 && sum < my_size) { - std::vector procs; - for (int i = 0; i < my_size; i++) { - if (result[i] == 0) { - procs.push_back(i); - } - } - where = Ioss::Utils::format_id_list(procs, "--"); + std::vector procs; + for (int i = 0; i < my_size; i++) { + if (result[i] == 0) { + procs.push_back(i); + } + } + where = Ioss::Utils::format_id_list(procs, "--"); } } #endif diff --git a/packages/seacas/libraries/ioss/src/Ioss_Getline.c b/packages/seacas/libraries/ioss/src/Ioss_Getline.c index 1a14bdfbb317..806f96216cf9 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_Getline.c +++ b/packages/seacas/libraries/ioss/src/Ioss_Getline.c @@ -569,13 +569,7 @@ static void io_gl_fixup(const char *prompt, int change, int cursor) static int off_left; /* true if more text left of screen */ static char last_prompt[80] = ""; int left = 0, right = -1; /* bounds for redraw */ - int pad; /* how much to erase at end of line */ - int backup; /* how far to backup before fixing */ - int new_shift; /* value of shift based on cursor */ - int extra; /* adjusts when shift (scroll) happens */ - int i; - int new_right = -1; /* alternate right bound, using io_gl_extent */ - int l1, l2; + int new_right = -1; /* alternate right bound, using io_gl_extent */ if (change == -2) { /* reset */ io_gl_pos = io_gl_cnt = io_gl_shift = off_right = off_left = 0; @@ -586,8 +580,8 @@ static void io_gl_fixup(const char *prompt, int change, int cursor) io_gl_width = io_gl_termw - strlen(prompt); } else if (strcmp(prompt, last_prompt) != 0) { - l1 = strlen(last_prompt); - l2 = strlen(prompt); + int l1 = strlen(last_prompt); + int l2 = strlen(prompt); io_gl_cnt = io_gl_cnt + l1 - l2; copy_string(last_prompt, prompt, 80); io_gl_putc('\r'); @@ -596,8 +590,9 @@ static void io_gl_fixup(const char *prompt, int change, int cursor) io_gl_width = io_gl_termw - l2; change = 0; } - pad = (off_right) ? io_gl_width - 1 : io_gl_cnt - io_gl_shift; /* old length */ - backup = io_gl_pos - io_gl_shift; + /* how much to erase at end of line */ + int pad = (off_right) ? io_gl_width - 1 : io_gl_cnt - io_gl_shift; /* old length */ + int backup = io_gl_pos - io_gl_shift; /* how far to backup before fixing */ if (change >= 0) { io_gl_cnt = strlen(io_gl_buf); if (change > io_gl_cnt) @@ -615,11 +610,11 @@ static void io_gl_fixup(const char *prompt, int change, int cursor) io_gl_beep(); cursor = 0; } - if (off_right || (off_left && cursor < io_gl_shift + io_gl_width - io_gl_scroll / 2)) + int extra; /* adjusts when shift (scroll) happens */ + if (off_right || (off_left && cursor < io_gl_shift + io_gl_width - io_gl_scroll / 2)) { extra = 2; /* shift the scrolling boundary */ - else - extra = 0; - new_shift = cursor + extra + io_gl_scroll - io_gl_width; + } + int new_shift = cursor + extra + io_gl_scroll - io_gl_width; if (new_shift > 0) { new_shift /= io_gl_scroll; new_shift *= io_gl_scroll; @@ -648,13 +643,13 @@ static void io_gl_fixup(const char *prompt, int change, int cursor) pad -= (off_right) ? io_gl_width - 1 : io_gl_cnt - io_gl_shift; pad = (pad < 0) ? 0 : pad; if (left <= right) { /* clean up screen */ - for (i = 0; i < backup; i++) + for (int i = 0; i < backup; i++) io_gl_putc('\b'); if (left == io_gl_shift && off_left) { io_gl_putc('$'); left++; } - for (i = left; i < new_right; i++) + for (int i = left; i < new_right; i++) io_gl_putc(io_gl_buf[i]); io_gl_pos = new_right; if (off_right && new_right == right) { @@ -662,19 +657,19 @@ static void io_gl_fixup(const char *prompt, int change, int cursor) io_gl_pos++; } else { - for (i = 0; i < pad; i++) /* erase remains of prev line */ + for (int i = 0; i < pad; i++) /* erase remains of prev line */ io_gl_putc(' '); io_gl_pos += pad; } } - i = io_gl_pos - cursor; /* move to final cursor location */ + int i = io_gl_pos - cursor; /* move to final cursor location */ if (i > 0) { while (i--) io_gl_putc('\b'); } else { - for (i = io_gl_pos; i < cursor; i++) - io_gl_putc(io_gl_buf[i]); + for (int ii = io_gl_pos; ii < cursor; ii++) + io_gl_putc(io_gl_buf[ii]); } io_gl_pos = cursor; } diff --git a/packages/seacas/libraries/ioss/src/Ioss_Glob.h b/packages/seacas/libraries/ioss/src/Ioss_Glob.h index fb7fe94d5c97..ef0c9fe0efd1 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_Glob.h +++ b/packages/seacas/libraries/ioss/src/Ioss_Glob.h @@ -1,3 +1,8 @@ +// Apache License +// Version 2.0, January 2004 +// http://www.apache.org/licenses/ +// https://github.com/alexst07/glob-cpp + #pragma once #include @@ -5,793 +10,795 @@ #include #include -namespace glob { +namespace Ioss { + namespace glob { + + template using String = std::basic_string; - template using String = std::basic_string; + template class Automata; - template class Automata; + class Error : public std::exception + { + public: + Error(const std::string &msg) : msg_{msg} {} - class Error : public std::exception - { - public: - Error(const std::string &msg) : msg_{msg} {} + const char *what() const throw() override { return msg_.c_str(); } - const char *what() const throw() override { return msg_.c_str(); } + private: + std::string msg_; + }; - private: - std::string msg_; - }; + enum class StateType { + MATCH, + FAIL, + CHAR, + QUESTION, + MULT, + SET, + GROUP, + UNION, + }; - enum class StateType { - MATCH, - FAIL, - CHAR, - QUESTION, - MULT, - SET, - GROUP, - UNION, - }; + // From cppreference.com + template const T exchange(T &obj, U &&new_value) + { + T old_value = std::move(obj); + obj = std::forward(new_value); + return old_value; + } - // From cppreference.com - template const T exchange(T &obj, U &&new_value) - { - T old_value = std::move(obj); - obj = std::forward(new_value); - return old_value; - } + template class State + { + public: + State(StateType type, Automata &states) : type_(type), states_(states) {} - template class State - { - public: - State(StateType type, Automata &states) : type_(type), states_(states) {} + virtual ~State() = default; - virtual ~State() = default; + virtual bool Check(const String &str, size_t pos) = 0; - virtual bool Check(const String &str, size_t pos) = 0; + virtual std::tuple Next(const String &str, size_t pos) = 0; - virtual std::tuple Next(const String &str, size_t pos) = 0; + StateType Type() const { return type_; } - StateType Type() const { return type_; } + Automata &GetAutomata() { return states_; } - Automata &GetAutomata() { return states_; } + void AddNextState(size_t state_pos) { next_states_.push_back(state_pos); } - void AddNextState(size_t state_pos) { next_states_.push_back(state_pos); } + const std::vector &GetNextStates() const { return next_states_; } - const std::vector &GetNextStates() const { return next_states_; } + const String &MatchedStr() { return matched_str_; } - const String &MatchedStr() { return matched_str_; } + virtual void ResetState() {} - virtual void ResetState() {} + protected: + void SetMatchedStr(const String &str) { matched_str_ = str; } - protected: - void SetMatchedStr(const String &str) { matched_str_ = str; } + void SetMatchedStr(charT c) { matched_str_ = c; } - void SetMatchedStr(charT c) { matched_str_ = c; } + private: + StateType type_; + Automata &states_; + std::vector next_states_; + String matched_str_; + }; - private: - StateType type_; - Automata &states_; - std::vector next_states_; - String matched_str_; - }; + template class StateFail : public State + { + public: + StateFail(Automata &states) : State(StateType::FAIL, states) {} - template class StateFail : public State - { - public: - StateFail(Automata &states) : State(StateType::FAIL, states) {} + bool Check(const String &, size_t) override { return false; } - bool Check(const String &, size_t) override { return false; } + std::tuple Next(const String &, size_t pos) override + { + return std::tuple(0, ++pos); + } + }; - std::tuple Next(const String &, size_t pos) override + template class StateMatch : public State { - return std::tuple(0, ++pos); - } - }; + public: + StateMatch(Automata &states) : State(StateType::MATCH, states) {} - template class StateMatch : public State - { - public: - StateMatch(Automata &states) : State(StateType::MATCH, states) {} + bool Check(const String &, size_t) override { return true; } - bool Check(const String &, size_t) override { return true; } + std::tuple Next(const String &, size_t pos) override + { + return std::tuple(0, ++pos); + } + }; - std::tuple Next(const String &, size_t pos) override + template class Automata { - return std::tuple(0, ++pos); - } - }; + public: + Automata() = default; - template class Automata - { - public: - Automata() = default; + Automata(const Automata &) = delete; - Automata(const Automata &) = delete; + Automata &operator=(const Automata &automata) = delete; - Automata &operator=(const Automata &automata) = delete; + Automata(Automata &&automata) + : states_{std::move(automata.states_)}, match_state_{automata.match_state_}, + fail_state_{exchange(automata.fail_state_, 0)}, start_state_{ + exchange(automata.start_state_, 0)} + { + } - Automata(Automata &&automata) - : states_{std::move(automata.states_)}, match_state_{automata.match_state_}, - fail_state_{exchange(automata.fail_state_, 0)}, start_state_{ - exchange(automata.start_state_, 0)} - { - } + Automata &operator=(Automata &&automata) + { + states_ = std::move(automata.states_); + match_state_ = automata.match_state_; + fail_state_ = automata.fail_state_; + start_state_ = automata.start_state_; - Automata &operator=(Automata &&automata) - { - states_ = std::move(automata.states_); - match_state_ = automata.match_state_; - fail_state_ = automata.fail_state_; - start_state_ = automata.start_state_; - - return *this; - } + return *this; + } - const State &GetState(size_t pos) const { return *states_[pos]; } + const State &GetState(size_t pos) const { return *states_[pos]; } - State &GetState(size_t pos) { return *states_[pos]; } + State &GetState(size_t pos) { return *states_[pos]; } - size_t FailState() const { return fail_state_; } + size_t FailState() const { return fail_state_; } - Automata &SetFailState(size_t state_pos) - { - fail_state_ = state_pos; - return *this; - } + Automata &SetFailState(size_t state_pos) + { + fail_state_ = state_pos; + return *this; + } - Automata &SetMatchState(size_t state_pos) - { - match_state_ = state_pos; - return *this; - } + Automata &SetMatchState(size_t state_pos) + { + match_state_ = state_pos; + return *this; + } - size_t GetNumStates() const { return states_.size(); } + size_t GetNumStates() const { return states_.size(); } - std::tuple Exec(const String &str, bool comp_end = true) - { - auto r = ExecAux(str, comp_end); - ResetStates(); - return r; - } + std::tuple Exec(const String &str, bool comp_end = true) + { + auto r = ExecAux(str, comp_end); + ResetStates(); + return r; + } - std::vector> GetMatchedStrings() const - { - std::vector> vec; + std::vector> GetMatchedStrings() const + { + std::vector> vec; - for (auto &state : states_) { - if (state->Type() == StateType::MULT || state->Type() == StateType::QUESTION || - state->Type() == StateType::GROUP || state->Type() == StateType::SET) { - vec.push_back(state->MatchedStr()); + for (auto &state : states_) { + if (state->Type() == StateType::MULT || state->Type() == StateType::QUESTION || + state->Type() == StateType::GROUP || state->Type() == StateType::SET) { + vec.push_back(state->MatchedStr()); + } } + + return vec; } - return vec; - } + template size_t NewState(Args &&...args) + { + size_t state_pos = states_.size(); + auto state = std::unique_ptr>(new T(*this, std::forward(args)...)); - template size_t NewState(Args &&...args) - { - size_t state_pos = states_.size(); - auto state = std::unique_ptr>(new T(*this, std::forward(args)...)); + states_.push_back(std::move(state)); + return state_pos; + } - states_.push_back(std::move(state)); - return state_pos; - } + size_t fail_state_; - size_t fail_state_; + private: + std::tuple ExecAux(const String &str, bool comp_end = true) const + { + size_t state_pos = 0; + size_t str_pos = 0; - private: - std::tuple ExecAux(const String &str, bool comp_end = true) const - { - size_t state_pos = 0; - size_t str_pos = 0; + // run the state vector until state reaches fail or match state, or + // until the string is all consumed + while (state_pos != fail_state_ && state_pos != match_state_ && str_pos < str.length()) { + std::tie(state_pos, str_pos) = states_[state_pos]->Next(str, str_pos); + } - // run the state vector until state reaches fail or match state, or - // until the string is all consumed - while (state_pos != fail_state_ && state_pos != match_state_ && str_pos < str.length()) { - std::tie(state_pos, str_pos) = states_[state_pos]->Next(str, str_pos); - } + // if comp_end is true it matches only if the automata reached the end of + // the string + if (comp_end) { + if ((state_pos == match_state_) && (str_pos == str.length())) { + return std::tuple(state_pos == match_state_, str_pos); + } - // if comp_end is true it matches only if the automata reached the end of - // the string - if (comp_end) { - if ((state_pos == match_state_) && (str_pos == str.length())) { + return std::tuple(false, str_pos); + } + else { + // if comp_end is false, compare only if the states reached the + // match state return std::tuple(state_pos == match_state_, str_pos); } - - return std::tuple(false, str_pos); } - else { - // if comp_end is false, compare only if the states reached the - // match state - return std::tuple(state_pos == match_state_, str_pos); - } - } - void ResetStates() - { - for (auto &state : states_) { - state->ResetState(); + void ResetStates() + { + for (auto &state : states_) { + state->ResetState(); + } } - } - - std::vector>> states_; - size_t match_state_; - - size_t start_state_; - }; - - template class StateChar : public State - { - using State::GetNextStates; - using State::GetAutomata; - public: - StateChar(Automata &states, charT c) : State(StateType::CHAR, states), c_{c} {} + std::vector>> states_; + size_t match_state_; - bool Check(const String &str, size_t pos) override { return (c_ == str[pos]); } + size_t start_state_; + }; - std::tuple Next(const String &str, size_t pos) override + template class StateChar : public State { - if (c_ == str[pos]) { - this->SetMatchedStr(c_); - return std::tuple(GetNextStates()[0], pos + 1); - } + using State::GetNextStates; + using State::GetAutomata; - return std::tuple(GetAutomata().FailState(), pos + 1); - } + public: + StateChar(Automata &states, charT c) : State(StateType::CHAR, states), c_{c} {} - private: - charT c_; - }; + bool Check(const String &str, size_t pos) override { return (c_ == str[pos]); } - template class StateAny : public State - { - using State::GetNextStates; - using State::GetAutomata; + std::tuple Next(const String &str, size_t pos) override + { + if (c_ == str[pos]) { + this->SetMatchedStr(c_); + return std::tuple(GetNextStates()[0], pos + 1); + } - public: - StateAny(Automata &states) : State(StateType::QUESTION, states) {} + return std::tuple(GetAutomata().FailState(), pos + 1); + } - bool Check(const String &, size_t) override - { - // as it match any char, it is always trye - return true; - } + private: + charT c_; + }; - std::tuple Next(const String &str, size_t pos) override + template class StateAny : public State { - this->SetMatchedStr(str[pos]); - // state any always match with any char - return std::tuple(GetNextStates()[0], pos + 1); - } - }; - - template class StateStar : public State - { - using State::GetNextStates; - using State::GetAutomata; + using State::GetNextStates; + using State::GetAutomata; - public: - StateStar(Automata &states) : State(StateType::MULT, states) {} + public: + StateAny(Automata &states) : State(StateType::QUESTION, states) {} - bool Check(const String &, size_t) override - { - // as it match any char, it is always trye - return true; - } + bool Check(const String &, size_t) override + { + // as it match any char, it is always trye + return true; + } - std::tuple Next(const String &str, size_t pos) override - { - // next state vector from StateStar has two elements, the element 0 points - // to the same state, and the element points to next state if the - // conditions is satisfied - if (GetAutomata().GetState(GetNextStates()[1]).Type() == StateType::MATCH) { - // this case occurs when star is in the end of the glob, so the pos is - // the end of the string, because all string is consumed - this->SetMatchedStr(str.substr(pos)); - return std::tuple(GetNextStates()[1], str.length()); - } - - bool res = GetAutomata().GetState(GetNextStates()[1]).Check(str, pos); - // if the next state is satisfied goes to next state - if (res) { - return std::tuple(GetNextStates()[1], pos); + std::tuple Next(const String &str, size_t pos) override + { + this->SetMatchedStr(str[pos]); + // state any always match with any char + return std::tuple(GetNextStates()[0], pos + 1); } + }; - // while the next state check is false, the string is consumed by star state - this->SetMatchedStr(this->MatchedStr() + str[pos]); - return std::tuple(GetNextStates()[0], pos + 1); - } - }; + template class StateStar : public State + { + using State::GetNextStates; + using State::GetAutomata; - template class SetItem - { - public: - SetItem() = default; - virtual ~SetItem() = default; + public: + StateStar(Automata &states) : State(StateType::MULT, states) {} - virtual bool Check(charT c) const = 0; - }; + bool Check(const String &, size_t) override + { + // as it match any char, it is always trye + return true; + } - template class SetItemChar : public SetItem - { - public: - SetItemChar(charT c) : c_{c} {} + std::tuple Next(const String &str, size_t pos) override + { + // next state vector from StateStar has two elements, the element 0 points + // to the same state, and the element points to next state if the + // conditions is satisfied + if (GetAutomata().GetState(GetNextStates()[1]).Type() == StateType::MATCH) { + // this case occurs when star is in the end of the glob, so the pos is + // the end of the string, because all string is consumed + this->SetMatchedStr(str.substr(pos)); + return std::tuple(GetNextStates()[1], str.length()); + } - bool Check(charT c) const override { return c == c_; } + bool res = GetAutomata().GetState(GetNextStates()[1]).Check(str, pos); + // if the next state is satisfied goes to next state + if (res) { + return std::tuple(GetNextStates()[1], pos); + } - private: - charT c_; - }; + // while the next state check is false, the string is consumed by star state + this->SetMatchedStr(this->MatchedStr() + str[pos]); + return std::tuple(GetNextStates()[0], pos + 1); + } + }; - template class SetItemRange : public SetItem - { - public: - SetItemRange(charT start, charT end) - : start_{start < end ? start : end}, end_{start < end ? end : start} + template class SetItem { - } + public: + SetItem() = default; + virtual ~SetItem() = default; - bool Check(charT c) const override { return (c >= start_) && (c <= end_); } + virtual bool Check(charT c) const = 0; + }; - private: - charT start_; - charT end_; - }; + template class SetItemChar : public SetItem + { + public: + SetItemChar(charT c) : c_{c} {} - template class StateSet : public State - { - using State::GetNextStates; - using State::GetAutomata; + bool Check(charT c) const override { return c == c_; } - public: - StateSet(Automata &states, std::vector>> items, - bool neg = false) - : State(StateType::SET, states), items_{std::move(items)}, neg_{neg} - { - } + private: + charT c_; + }; - bool SetCheck(const String &str, size_t pos) const + template class SetItemRange : public SetItem { - for (auto &item : items_) { - // if any item match, then the set match with char - if (item.get()->Check(str[pos])) { - return true; - } + public: + SetItemRange(charT start, charT end) + : start_{start < end ? start : end}, end_{start < end ? end : start} + { } - return false; - } + bool Check(charT c) const override { return (c >= start_) && (c <= end_); } + + private: + charT start_; + charT end_; + }; - bool Check(const String &str, size_t pos) override + template class StateSet : public State { - if (neg_) { - return !SetCheck(str, pos); + using State::GetNextStates; + using State::GetAutomata; + + public: + StateSet(Automata &states, std::vector>> items, + bool neg = false) + : State(StateType::SET, states), items_{std::move(items)}, neg_{neg} + { } - return SetCheck(str, pos); - } + bool SetCheck(const String &str, size_t pos) const + { + for (auto &item : items_) { + // if any item match, then the set match with char + if (item.get()->Check(str[pos])) { + return true; + } + } - std::tuple Next(const String &str, size_t pos) override - { - if (Check(str, pos)) { - this->SetMatchedStr(str[pos]); - return std::tuple(GetNextStates()[0], pos + 1); + return false; } - return std::tuple(GetAutomata().FailState(), pos + 1); - } + bool Check(const String &str, size_t pos) override + { + if (neg_) { + return !SetCheck(str, pos); + } - private: - std::vector>> items_; - bool neg_; - }; + return SetCheck(str, pos); + } - template class StateGroup : public State - { - using State::GetNextStates; - using State::GetAutomata; + std::tuple Next(const String &str, size_t pos) override + { + if (Check(str, pos)) { + this->SetMatchedStr(str[pos]); + return std::tuple(GetNextStates()[0], pos + 1); + } - public: - enum class Type { BASIC, ANY, STAR, PLUS, NEG, AT }; + return std::tuple(GetAutomata().FailState(), pos + 1); + } - StateGroup(Automata &states, Type type, - std::vector>> &&automatas) - : State(StateType::GROUP, states), type_{type}, automatas_{std::move(automatas)}, - match_one_{false} + private: + std::vector>> items_; + bool neg_; + }; + + template class StateGroup : public State { - } + using State::GetNextStates; + using State::GetAutomata; - void ResetState() override { match_one_ = false; } + public: + enum class Type { BASIC, ANY, STAR, PLUS, NEG, AT }; - std::tuple BasicCheck(const String &str, size_t pos) - { - String str_part = str.substr(pos); - bool r; - size_t str_pos = 0; - - // each automata is a part of a union of the group, in basic check, - // we want find only if any automata is true - for (auto &automata : automatas_) { - std::tie(r, str_pos) = automata->Exec(str_part, false); - if (r) { - return std::tuple(r, pos + str_pos); - } + StateGroup(Automata &states, Type type, + std::vector>> &&automatas) + : State(StateType::GROUP, states), type_{type}, automatas_{std::move(automatas)}, + match_one_{false} + { } - return std::tuple(false, pos + str_pos); - } + void ResetState() override { match_one_ = false; } - bool Check(const String &str, size_t pos) override - { - bool r = false; - switch (type_) { - case Type::BASIC: - case Type::AT: - case Type::ANY: - case Type::STAR: - case Type::PLUS: { - std::tie(r, std::ignore) = BasicCheck(str, pos); - break; - } + std::tuple BasicCheck(const String &str, size_t pos) + { + String str_part = str.substr(pos); + bool r; + size_t str_pos = 0; - case Type::NEG: { - std::tie(r, std::ignore) = BasicCheck(str, pos); - break; - } - } - return r; - } + // each automata is a part of a union of the group, in basic check, + // we want find only if any automata is true + for (auto &automata : automatas_) { + std::tie(r, str_pos) = automata->Exec(str_part, false); + if (r) { + return std::tuple(r, pos + str_pos); + } + } - std::tuple Next(const String &str, size_t pos) override - { - // STATE 1 -> is the next state - // STATE 0 -> is the same state - switch (type_) { - case Type::BASIC: - case Type::AT: { - return NextBasic(str, pos); + return std::tuple(false, pos + str_pos); } - case Type::ANY: { - return NextAny(str, pos); - } + bool Check(const String &str, size_t pos) override + { + bool r = false; + switch (type_) { + case Type::BASIC: + case Type::AT: + case Type::ANY: + case Type::STAR: + case Type::PLUS: { + std::tie(r, std::ignore) = BasicCheck(str, pos); + break; + } - case Type::STAR: { - return NextStar(str, pos); + case Type::NEG: { + std::tie(r, std::ignore) = BasicCheck(str, pos); + break; + } + } + return r; } - case Type::PLUS: { - return NextPlus(str, pos); - } + std::tuple Next(const String &str, size_t pos) override + { + // STATE 1 -> is the next state + // STATE 0 -> is the same state + switch (type_) { + case Type::BASIC: + case Type::AT: { + return NextBasic(str, pos); + } - case Type::NEG: { - return NextNeg(str, pos); - } - } - return std::tuple(0, 0); - } + case Type::ANY: { + return NextAny(str, pos); + } - std::tuple NextNeg(const String &str, size_t pos) - { - bool r; - size_t new_pos; - std::tie(r, new_pos) = BasicCheck(str, pos); - if (r) { - this->SetMatchedStr(this->MatchedStr() + str.substr(pos, new_pos - pos)); - return std::tuple(GetAutomata().FailState(), new_pos); - } + case Type::STAR: { + return NextStar(str, pos); + } - return std::tuple(GetNextStates()[1], pos); - } + case Type::PLUS: { + return NextPlus(str, pos); + } - std::tuple NextBasic(const String &str, size_t pos) - { - bool r; - size_t new_pos; - std::tie(r, new_pos) = BasicCheck(str, pos); - if (r) { - this->SetMatchedStr(this->MatchedStr() + str.substr(pos, new_pos - pos)); - return std::tuple(GetNextStates()[1], new_pos); + case Type::NEG: { + return NextNeg(str, pos); + } + } + return std::tuple(0, 0); } - return std::tuple(GetAutomata().FailState(), new_pos); - } + std::tuple NextNeg(const String &str, size_t pos) + { + bool r; + size_t new_pos; + std::tie(r, new_pos) = BasicCheck(str, pos); + if (r) { + this->SetMatchedStr(this->MatchedStr() + str.substr(pos, new_pos - pos)); + return std::tuple(GetAutomata().FailState(), new_pos); + } - std::tuple NextAny(const String &str, size_t pos) - { - bool r; - size_t new_pos; - std::tie(r, new_pos) = BasicCheck(str, pos); - if (r) { - this->SetMatchedStr(this->MatchedStr() + str.substr(pos, new_pos - pos)); - return std::tuple(GetNextStates()[1], new_pos); + return std::tuple(GetNextStates()[1], pos); } - return std::tuple(GetNextStates()[1], pos); - } - - std::tuple NextStar(const String &str, size_t pos) - { - bool r; - size_t new_pos; - std::tie(r, new_pos) = BasicCheck(str, pos); - if (r) { - this->SetMatchedStr(this->MatchedStr() + str.substr(pos, new_pos - pos)); - if (GetAutomata().GetState(GetNextStates()[1]).Type() == StateType::MATCH && - new_pos == str.length()) { + std::tuple NextBasic(const String &str, size_t pos) + { + bool r; + size_t new_pos; + std::tie(r, new_pos) = BasicCheck(str, pos); + if (r) { + this->SetMatchedStr(this->MatchedStr() + str.substr(pos, new_pos - pos)); return std::tuple(GetNextStates()[1], new_pos); } - else { - return std::tuple(GetNextStates()[0], new_pos); - } - } - return std::tuple(GetNextStates()[1], pos); - } + return std::tuple(GetAutomata().FailState(), new_pos); + } - std::tuple NextPlus(const String &str, size_t pos) - { - bool r; - size_t new_pos; - std::tie(r, new_pos) = BasicCheck(str, pos); - if (r) { - match_one_ = true; - this->SetMatchedStr(this->MatchedStr() + str.substr(pos, new_pos - pos)); - - // if it matches and the string reached at the end, and the next - // state is the match state, goes to next state to avoid state mistake - if (GetAutomata().GetState(GetNextStates()[1]).Type() == StateType::MATCH && - new_pos == str.length()) { + std::tuple NextAny(const String &str, size_t pos) + { + bool r; + size_t new_pos; + std::tie(r, new_pos) = BasicCheck(str, pos); + if (r) { + this->SetMatchedStr(this->MatchedStr() + str.substr(pos, new_pos - pos)); return std::tuple(GetNextStates()[1], new_pos); } - else { - return std::tuple(GetNextStates()[0], new_pos); - } - } - // case where the next state matches and the group already matched - // one time -> goes to next state - bool res = GetAutomata().GetState(GetNextStates()[1]).Check(str, pos); - if (res && match_one_) { return std::tuple(GetNextStates()[1], pos); } - if (match_one_) { + std::tuple NextStar(const String &str, size_t pos) + { + bool r; + size_t new_pos; + std::tie(r, new_pos) = BasicCheck(str, pos); + if (r) { + this->SetMatchedStr(this->MatchedStr() + str.substr(pos, new_pos - pos)); + if (GetAutomata().GetState(GetNextStates()[1]).Type() == StateType::MATCH && + new_pos == str.length()) { + return std::tuple(GetNextStates()[1], new_pos); + } + else { + return std::tuple(GetNextStates()[0], new_pos); + } + } + return std::tuple(GetNextStates()[1], pos); } - else { - return std::tuple(GetAutomata().FailState(), new_pos); + + std::tuple NextPlus(const String &str, size_t pos) + { + bool r; + size_t new_pos; + std::tie(r, new_pos) = BasicCheck(str, pos); + if (r) { + match_one_ = true; + this->SetMatchedStr(this->MatchedStr() + str.substr(pos, new_pos - pos)); + + // if it matches and the string reached at the end, and the next + // state is the match state, goes to next state to avoid state mistake + if (GetAutomata().GetState(GetNextStates()[1]).Type() == StateType::MATCH && + new_pos == str.length()) { + return std::tuple(GetNextStates()[1], new_pos); + } + else { + return std::tuple(GetNextStates()[0], new_pos); + } + } + + // case where the next state matches and the group already matched + // one time -> goes to next state + bool res = GetAutomata().GetState(GetNextStates()[1]).Check(str, pos); + if (res && match_one_) { + return std::tuple(GetNextStates()[1], pos); + } + + if (match_one_) { + return std::tuple(GetNextStates()[1], pos); + } + else { + return std::tuple(GetAutomata().FailState(), new_pos); + } } - } - private: - Type type_{}; - std::vector>> automatas_; - bool match_one_; - }; + private: + Type type_{}; + std::vector>> automatas_; + bool match_one_; + }; #define TOKEN(X, Y) X, - enum class TokenKind { - UNKNOWN = 0, - CHAR, - TOKEN(EOS, "end of source") TOKEN(SUB, "-") TOKEN(STAR, "*") TOKEN(QUESTION, "?") - TOKEN(LPAREN, "(") TOKEN(QUESTLPAREN, "?(") TOKEN(STARLPAREN, "*(") TOKEN(PLUSLPAREN, "+(") - TOKEN(NEGLPAREN, "!(") TOKEN(ATLPAREN, "@(") TOKEN(RPAREN, ")") TOKEN(UNION, "|") - TOKEN(LBRACKET, "[") TOKEN(RBRACKET, "]") TOKEN(NEGLBRACKET, "[^") NUM_TOKENS - }; -#undef TOKEN - -#define TOKEN(X, Y) #X, - static const char *token_name_str[] = { - "UNKNOWN", // UNKNOWN - "CHAR", + enum class TokenKind { + UNKNOWN = 0, + CHAR, TOKEN(EOS, "end of source") TOKEN(SUB, "-") TOKEN(STAR, "*") TOKEN(QUESTION, "?") TOKEN(LPAREN, "(") TOKEN(QUESTLPAREN, "?(") TOKEN(STARLPAREN, "*(") TOKEN(PLUSLPAREN, "+(") TOKEN(NEGLPAREN, "!(") TOKEN(ATLPAREN, "@(") TOKEN(RPAREN, ")") TOKEN(UNION, "|") TOKEN(LBRACKET, "[") TOKEN(RBRACKET, "]") - TOKEN(NEGLBRACKET, "[^") ""}; + TOKEN(NEGLBRACKET, "[^") NUM_TOKENS + }; #undef TOKEN - template class Token - { - public: - Token(TokenKind kind) : kind_{kind} {} - Token(TokenKind kind, charT value) : kind_{kind}, value_{value} {} - TokenKind Kind() const { return kind_; } - - charT Value() const { return value_; } +#define TOKEN(X, Y) #X, + static const char *token_name_str[] = { + "UNKNOWN", // UNKNOWN + "CHAR", + TOKEN(EOS, "end of source") TOKEN(SUB, "-") TOKEN(STAR, "*") TOKEN(QUESTION, "?") + TOKEN(LPAREN, "(") TOKEN(QUESTLPAREN, "?(") TOKEN(STARLPAREN, "*(") + TOKEN(PLUSLPAREN, "+(") TOKEN(NEGLPAREN, "!(") TOKEN(ATLPAREN, "@(") + TOKEN(RPAREN, ")") TOKEN(UNION, "|") TOKEN(LBRACKET, "[") TOKEN(RBRACKET, "]") + TOKEN(NEGLBRACKET, "[^") ""}; +#undef TOKEN - bool operator==(TokenKind kind) { return kind_ == kind; } + template class Token + { + public: + Token(TokenKind kind) : kind_{kind} {} + Token(TokenKind kind, charT value) : kind_{kind}, value_{value} {} + TokenKind Kind() const { return kind_; } - bool operator==(TokenKind kind) const { return kind_ == kind; } + charT Value() const { return value_; } - bool operator!=(TokenKind kind) { return kind_ != kind; } + bool operator==(TokenKind kind) { return kind_ == kind; } - bool operator!=(TokenKind kind) const { return kind_ != kind; } + bool operator==(TokenKind kind) const { return kind_ == kind; } - private: - template - friend std::ostream &operator<<(std::ostream &stream, const Token &token); + bool operator!=(TokenKind kind) { return kind_ != kind; } - TokenKind kind_; - charT value_{}; - }; + bool operator!=(TokenKind kind) const { return kind_ != kind; } - template - inline std::ostream &operator<<(std::ostream &stream, const Token &token) - { - stream << '[' << token_name_str[static_cast(token.kind_)] << ']'; - return stream; - } + private: + template + friend std::ostream &operator<<(std::ostream &stream, const Token &token); - template class Lexer - { - public: - static const char kEndOfInput = -1; + TokenKind kind_; + charT value_{}; + }; - Lexer(const String &str) : str_(str), pos_{0}, c_{str[0]} {} + template + inline std::ostream &operator<<(std::ostream &stream, const Token &token) + { + stream << '[' << token_name_str[static_cast(token.kind_)] << ']'; + return stream; + } - std::vector> Scanner() + template class Lexer { - std::vector> tokens; - while (true) { - switch (c_) { - case '?': { - Advance(); - if (c_ == '(') { - tokens.push_back(Select(TokenKind::QUESTLPAREN)); + public: + static const char kEndOfInput = -1; + + Lexer(const String &str) : str_(str), pos_{0}, c_{str[0]} {} + + std::vector> Scanner() + { + std::vector> tokens; + while (true) { + switch (c_) { + case '?': { Advance(); + if (c_ == '(') { + tokens.push_back(Select(TokenKind::QUESTLPAREN)); + Advance(); + } + else { + tokens.push_back(Select(TokenKind::QUESTION)); + } + break; } - else { - tokens.push_back(Select(TokenKind::QUESTION)); - } - break; - } - case '*': { - Advance(); - if (c_ == '(') { - tokens.push_back(Select(TokenKind::STARLPAREN)); + case '*': { Advance(); + if (c_ == '(') { + tokens.push_back(Select(TokenKind::STARLPAREN)); + Advance(); + } + else { + tokens.push_back(Select(TokenKind::STAR)); + } + break; } - else { - tokens.push_back(Select(TokenKind::STAR)); - } - break; - } - case '+': { - Advance(); - if (c_ == '(') { - tokens.push_back(Select(TokenKind::PLUSLPAREN)); + case '+': { Advance(); + if (c_ == '(') { + tokens.push_back(Select(TokenKind::PLUSLPAREN)); + Advance(); + } + else { + tokens.push_back(Select(TokenKind::CHAR, '+')); + } + break; } - else { - tokens.push_back(Select(TokenKind::CHAR, '+')); - } - break; - } - - case '-': { - tokens.push_back(Select(TokenKind::SUB)); - Advance(); - break; - } - - case '|': { - tokens.push_back(Select(TokenKind::UNION)); - Advance(); - break; - } - case '@': { - Advance(); - if (c_ == '(') { - tokens.push_back(Select(TokenKind::ATLPAREN)); + case '-': { + tokens.push_back(Select(TokenKind::SUB)); Advance(); + break; } - else { - tokens.push_back(Select(TokenKind::CHAR, '@')); - } - break; - } - case '!': { - Advance(); - if (c_ == '(') { - tokens.push_back(Select(TokenKind::NEGLPAREN)); + case '|': { + tokens.push_back(Select(TokenKind::UNION)); Advance(); + break; } - else { - tokens.push_back(Select(TokenKind::CHAR, '!')); - } - break; - } - case '(': { - tokens.push_back(Select(TokenKind::LPAREN)); - Advance(); - break; - } + case '@': { + Advance(); + if (c_ == '(') { + tokens.push_back(Select(TokenKind::ATLPAREN)); + Advance(); + } + else { + tokens.push_back(Select(TokenKind::CHAR, '@')); + } + break; + } - case ')': { - tokens.push_back(Select(TokenKind::RPAREN)); - Advance(); - break; - } + case '!': { + Advance(); + if (c_ == '(') { + tokens.push_back(Select(TokenKind::NEGLPAREN)); + Advance(); + } + else { + tokens.push_back(Select(TokenKind::CHAR, '!')); + } + break; + } - case '[': { - Advance(); - if (c_ == '!') { - tokens.push_back(Select(TokenKind::NEGLBRACKET)); + case '(': { + tokens.push_back(Select(TokenKind::LPAREN)); Advance(); + break; } - else { - tokens.push_back(Select(TokenKind::LBRACKET)); + + case ')': { + tokens.push_back(Select(TokenKind::RPAREN)); + Advance(); + break; } - break; - } - case ']': { - tokens.push_back(Select(TokenKind::RBRACKET)); - Advance(); - break; - } + case '[': { + Advance(); + if (c_ == '!') { + tokens.push_back(Select(TokenKind::NEGLBRACKET)); + Advance(); + } + else { + tokens.push_back(Select(TokenKind::LBRACKET)); + } + break; + } - case '\\': { - Advance(); - if (c_ == kEndOfInput) { - throw Error("No valid char after '\\'"); + case ']': { + tokens.push_back(Select(TokenKind::RBRACKET)); + Advance(); + break; } - else if (IsSpecialChar(c_)) { - tokens.push_back(Select(TokenKind::CHAR, c_)); + + case '\\': { Advance(); + if (c_ == kEndOfInput) { + throw Error("No valid char after '\\'"); + } + else if (IsSpecialChar(c_)) { + tokens.push_back(Select(TokenKind::CHAR, c_)); + Advance(); + } + break; } - break; - } - default: { - if (c_ == kEndOfInput) { - tokens.push_back(Select(TokenKind::EOS)); - return tokens; + default: { + if (c_ == kEndOfInput) { + tokens.push_back(Select(TokenKind::EOS)); + return tokens; + } + else { + tokens.push_back(Select(TokenKind::CHAR, c_)); + Advance(); + } } - else { - tokens.push_back(Select(TokenKind::CHAR, c_)); - Advance(); } } - } } - } - private: - inline Token Select(TokenKind k) { return Token(k); } + private: + inline Token Select(TokenKind k) { return Token(k); } - inline Token Select(TokenKind k, charT value) { return Token(k, value); } + inline Token Select(TokenKind k, charT value) { return Token(k, value); } - void Advance() - { - if (pos_ == (str_.length() - 1)) { - c_ = kEndOfInput; - return; - } + void Advance() + { + if (pos_ == (str_.length() - 1)) { + c_ = kEndOfInput; + return; + } - c_ = str_[++pos_]; - } + c_ = str_[++pos_]; + } - inline bool IsSpecialChar(charT c) - { - bool b = c == '?' || c == '*' || c == '+' || c == '(' || c == ')' || c == '[' || c == ']' || - c == '|' || c == '!' || c == '@' || c == '\\'; - return b; - } + inline bool IsSpecialChar(charT c) + { + bool b = c == '?' || c == '*' || c == '+' || c == '(' || c == ')' || c == '[' || c == ']' || + c == '|' || c == '!' || c == '@' || c == '\\'; + return b; + } - String str_; - size_t pos_; - charT c_; - }; + String str_; + size_t pos_; + charT c_; + }; #define GLOB_AST_NODE_LIST(V) \ V(CharNode) \ @@ -806,870 +813,876 @@ namespace glob { V(UnionNode) \ V(GlobNode) - template class AstVisitor; + template class AstVisitor; // declare all classes used for nodes #define DECLARE_TYPE_CLASS(type) template class type; - GLOB_AST_NODE_LIST(DECLARE_TYPE_CLASS) + GLOB_AST_NODE_LIST(DECLARE_TYPE_CLASS) #undef DECLARE_TYPE_CLASS - template class AstNode - { - public: - enum class Type { - CHAR, - RANGE, - SET_ITEM, - SET_ITEMS, - POS_SET, - NEG_SET, - SET, - STAR, - ANY, - GROUP, - CONCAT_GLOB, - UNION, - GLOB - }; + template class AstNode + { + public: + enum class Type { + CHAR, + RANGE, + SET_ITEM, + SET_ITEMS, + POS_SET, + NEG_SET, + SET, + STAR, + ANY, + GROUP, + CONCAT_GLOB, + UNION, + GLOB + }; - virtual ~AstNode() = default; + virtual ~AstNode() = default; - Type GetType() const { return type_; } + Type GetType() const { return type_; } - virtual void Accept(AstVisitor *visitor) = 0; + virtual void Accept(AstVisitor *visitor) = 0; - protected: - AstNode(Type type) : type_{type} {} + protected: + AstNode(Type type) : type_{type} {} - private: - Type type_; - }; + private: + Type type_; + }; - template using AstNodePtr = std::unique_ptr>; + template using AstNodePtr = std::unique_ptr>; - template class AstVisitor - { - public: + template class AstVisitor + { + public: // define all visitor methods for the nodes #define DECLARE_VIRTUAL_FUNC(type) \ virtual void Visit##type(type * /*node*/) {} - GLOB_AST_NODE_LIST(DECLARE_VIRTUAL_FUNC) + GLOB_AST_NODE_LIST(DECLARE_VIRTUAL_FUNC) #undef DECLARE_VIRTUAL_FUNC - }; + }; - template class CharNode : public AstNode - { - public: - CharNode(charT c) : AstNode(AstNode::Type::CHAR), c_{c} {} + template class CharNode : public AstNode + { + public: + CharNode(charT c) : AstNode(AstNode::Type::CHAR), c_{c} {} - virtual void Accept(AstVisitor *visitor) { visitor->VisitCharNode(this); } + virtual void Accept(AstVisitor *visitor) { visitor->VisitCharNode(this); } - char GetValue() const { return c_; } + char GetValue() const { return c_; } - private: - charT c_; - }; + private: + charT c_; + }; - template class RangeNode : public AstNode - { - public: - RangeNode(AstNodePtr &&start, AstNodePtr &&end) - : AstNode(AstNode::Type::RANGE), start_{std::move(start)}, end_{ - std::move(end)} + template class RangeNode : public AstNode { - } + public: + RangeNode(AstNodePtr &&start, AstNodePtr &&end) + : AstNode(AstNode::Type::RANGE), start_{std::move(start)}, end_{std::move( + end)} + { + } - virtual void Accept(AstVisitor *visitor) { visitor->VisitRangeNode(this); } + virtual void Accept(AstVisitor *visitor) { visitor->VisitRangeNode(this); } - AstNode *GetStart() const { return start_.get(); } + AstNode *GetStart() const { return start_.get(); } - AstNode *GetEnd() const { return end_.get(); } + AstNode *GetEnd() const { return end_.get(); } - private: - AstNodePtr start_; - AstNodePtr end_; - }; + private: + AstNodePtr start_; + AstNodePtr end_; + }; - template class SetItemsNode : public AstNode - { - public: - SetItemsNode(std::vector> &&items) - : AstNode(AstNode::Type::SET_ITEMS), items_{std::move(items)} + template class SetItemsNode : public AstNode { - } + public: + SetItemsNode(std::vector> &&items) + : AstNode(AstNode::Type::SET_ITEMS), items_{std::move(items)} + { + } - virtual void Accept(AstVisitor *visitor) { visitor->VisitSetItemsNode(this); } + virtual void Accept(AstVisitor *visitor) { visitor->VisitSetItemsNode(this); } - std::vector> &GetItems() { return items_; } + std::vector> &GetItems() { return items_; } - private: - std::vector> items_; - }; + private: + std::vector> items_; + }; - template class PositiveSetNode : public AstNode - { - public: - PositiveSetNode(AstNodePtr &&set) - : AstNode(AstNode::Type::POS_SET), set_{std::move(set)} + template class PositiveSetNode : public AstNode { - } + public: + PositiveSetNode(AstNodePtr &&set) + : AstNode(AstNode::Type::POS_SET), set_{std::move(set)} + { + } - virtual void Accept(AstVisitor *visitor) { visitor->VisitPositiveSetNode(this); } + virtual void Accept(AstVisitor *visitor) { visitor->VisitPositiveSetNode(this); } - AstNode *GetSet() { return set_.get(); } + AstNode *GetSet() { return set_.get(); } - private: - AstNodePtr set_; - }; + private: + AstNodePtr set_; + }; - template class NegativeSetNode : public AstNode - { - public: - NegativeSetNode(AstNodePtr &&set) - : AstNode(AstNode::Type::NEG_SET), set_{std::move(set)} + template class NegativeSetNode : public AstNode { - } - - virtual void Accept(AstVisitor *visitor) { visitor->VisitNegativeSetNode(this); } + public: + NegativeSetNode(AstNodePtr &&set) + : AstNode(AstNode::Type::NEG_SET), set_{std::move(set)} + { + } - AstNode *GetSet() { return set_.get(); } + virtual void Accept(AstVisitor *visitor) { visitor->VisitNegativeSetNode(this); } - private: - AstNodePtr set_; - }; + AstNode *GetSet() { return set_.get(); } - template class StarNode : public AstNode - { - public: - StarNode() : AstNode(AstNode::Type::STAR) {} + private: + AstNodePtr set_; + }; - virtual void Accept(AstVisitor *visitor) { visitor->VisitStarNode(this); } - }; + template class StarNode : public AstNode + { + public: + StarNode() : AstNode(AstNode::Type::STAR) {} - template class AnyNode : public AstNode - { - public: - AnyNode() : AstNode(AstNode::Type::ANY) {} + virtual void Accept(AstVisitor *visitor) { visitor->VisitStarNode(this); } + }; - virtual void Accept(AstVisitor *visitor) { visitor->VisitAnyNode(this); } - }; + template class AnyNode : public AstNode + { + public: + AnyNode() : AstNode(AstNode::Type::ANY) {} - template class GroupNode : public AstNode - { - public: - enum class GroupType { BASIC, ANY, STAR, PLUS, NEG, AT }; + virtual void Accept(AstVisitor *visitor) { visitor->VisitAnyNode(this); } + }; - GroupNode(GroupType group_type, AstNodePtr &&glob) - : AstNode(AstNode::Type::GROUP), glob_{std::move(glob)}, group_type_{ - group_type} + template class GroupNode : public AstNode { - } + public: + enum class GroupType { BASIC, ANY, STAR, PLUS, NEG, AT }; - virtual void Accept(AstVisitor *visitor) { visitor->VisitGroupNode(this); } + GroupNode(GroupType group_type, AstNodePtr &&glob) + : AstNode(AstNode::Type::GROUP), glob_{std::move(glob)}, group_type_{ + group_type} + { + } - AstNode *GetGlob() { return glob_.get(); } + virtual void Accept(AstVisitor *visitor) { visitor->VisitGroupNode(this); } - GroupType GetGroupType() const { return group_type_; } + AstNode *GetGlob() { return glob_.get(); } - private: - AstNodePtr glob_; - GroupType group_type_; - }; + GroupType GetGroupType() const { return group_type_; } - template class ConcatNode : public AstNode - { - public: - ConcatNode(std::vector> &&basic_glob) - : AstNode(AstNode::Type::CONCAT_GLOB), basic_glob_{std::move(basic_glob)} + private: + AstNodePtr glob_; + GroupType group_type_; + }; + + template class ConcatNode : public AstNode { - } + public: + ConcatNode(std::vector> &&basic_glob) + : AstNode(AstNode::Type::CONCAT_GLOB), basic_glob_{std::move(basic_glob)} + { + } - virtual void Accept(AstVisitor *visitor) { visitor->VisitConcatNode(this); } + virtual void Accept(AstVisitor *visitor) { visitor->VisitConcatNode(this); } - std::vector> &GetBasicGlobs() { return basic_glob_; } + std::vector> &GetBasicGlobs() { return basic_glob_; } - private: - std::vector> basic_glob_; - }; + private: + std::vector> basic_glob_; + }; - template class UnionNode : public AstNode - { - public: - UnionNode(std::vector> &&items) - : AstNode(AstNode::Type::UNION), items_{std::move(items)} + template class UnionNode : public AstNode { - } + public: + UnionNode(std::vector> &&items) + : AstNode(AstNode::Type::UNION), items_{std::move(items)} + { + } - virtual void Accept(AstVisitor *visitor) { visitor->VisitUnionNode(this); } + virtual void Accept(AstVisitor *visitor) { visitor->VisitUnionNode(this); } - std::vector> &GetItems() { return items_; } + std::vector> &GetItems() { return items_; } - private: - std::vector> items_; - }; + private: + std::vector> items_; + }; - template class GlobNode : public AstNode - { - public: - GlobNode(AstNodePtr &&glob) - : AstNode(AstNode::Type::GLOB), glob_{std::move(glob)} + template class GlobNode : public AstNode { - } + public: + GlobNode(AstNodePtr &&glob) + : AstNode(AstNode::Type::GLOB), glob_{std::move(glob)} + { + } + + virtual void Accept(AstVisitor *visitor) { visitor->VisitGlobNode(this); } - virtual void Accept(AstVisitor *visitor) { visitor->VisitGlobNode(this); } + AstNode *GetConcat() { return glob_.get(); } - AstNode *GetConcat() { return glob_.get(); } + private: + AstNodePtr glob_; + }; - private: - AstNodePtr glob_; - }; + template class Parser + { + public: + Parser() = delete; - template class Parser - { - public: - Parser() = delete; + Parser(std::vector> &&tok_vec) : tok_vec_{std::move(tok_vec)}, pos_{0} {} - Parser(std::vector> &&tok_vec) : tok_vec_{std::move(tok_vec)}, pos_{0} {} + AstNodePtr GenAst() { return ParserGlob(); } - AstNodePtr GenAst() { return ParserGlob(); } + private: + AstNodePtr ParserChar() + { + Token &tk = NextToken(); + if (tk != TokenKind::CHAR) { + throw Error("char expected"); + } - private: - AstNodePtr ParserChar() - { - Token &tk = NextToken(); - if (tk != TokenKind::CHAR) { - throw Error("char expected"); + charT c = tk.Value(); + return AstNodePtr(new CharNode(c)); } - charT c = tk.Value(); - return AstNodePtr(new CharNode(c)); - } + AstNodePtr ParserRange() + { + AstNodePtr char_start = ParserChar(); - AstNodePtr ParserRange() - { - AstNodePtr char_start = ParserChar(); + Token &tk = NextToken(); + if (tk != TokenKind::SUB) { + throw Error("range expected"); + } - Token &tk = NextToken(); - if (tk != TokenKind::SUB) { - throw Error("range expected"); + AstNodePtr char_end = ParserChar(); + return AstNodePtr(new RangeNode(std::move(char_start), std::move(char_end))); } - AstNodePtr char_end = ParserChar(); - return AstNodePtr(new RangeNode(std::move(char_start), std::move(char_end))); - } + AstNodePtr ParserSetItem() + { + if (PeekAhead() == TokenKind::SUB) { + return ParserRange(); + } - AstNodePtr ParserSetItem() - { - if (PeekAhead() == TokenKind::SUB) { - return ParserRange(); + return ParserChar(); } - return ParserChar(); - } + AstNodePtr ParserSetItems() + { + std::vector> items; - AstNodePtr ParserSetItems() - { - std::vector> items; + do { + items.push_back(ParserSetItem()); + } while (GetToken() != TokenKind::RBRACKET); - do { - items.push_back(ParserSetItem()); - } while (GetToken() != TokenKind::RBRACKET); - - Advance(); + Advance(); - return AstNodePtr(new SetItemsNode(std::move(items))); - } + return AstNodePtr(new SetItemsNode(std::move(items))); + } - AstNodePtr ParserSet() - { - Token &tk = NextToken(); + AstNodePtr ParserSet() + { + Token &tk = NextToken(); - if (tk == TokenKind::LBRACKET) { - return AstNodePtr(new PositiveSetNode(ParserSetItems())); - } - else if (tk == TokenKind::NEGLBRACKET) { - return AstNodePtr(new NegativeSetNode(ParserSetItems())); - } - else { - throw Error("set expected"); + if (tk == TokenKind::LBRACKET) { + return AstNodePtr(new PositiveSetNode(ParserSetItems())); + } + else if (tk == TokenKind::NEGLBRACKET) { + return AstNodePtr(new NegativeSetNode(ParserSetItems())); + } + else { + throw Error("set expected"); + } } - } - AstNodePtr ParserBasicGlob() - { - Token &tk = GetToken(); + AstNodePtr ParserBasicGlob() + { + Token &tk = GetToken(); - switch (tk.Kind()) { - case TokenKind::QUESTION: Advance(); return AstNodePtr(new AnyNode()); + switch (tk.Kind()) { + case TokenKind::QUESTION: Advance(); return AstNodePtr(new AnyNode()); - case TokenKind::STAR: Advance(); return AstNodePtr(new StarNode()); + case TokenKind::STAR: Advance(); return AstNodePtr(new StarNode()); - case TokenKind::SUB: Advance(); return AstNodePtr(new CharNode('-')); + case TokenKind::SUB: Advance(); return AstNodePtr(new CharNode('-')); - case TokenKind::CHAR: return ParserChar(); + case TokenKind::CHAR: return ParserChar(); - case TokenKind::LBRACKET: - case TokenKind::NEGLBRACKET: return ParserSet(); + case TokenKind::LBRACKET: + case TokenKind::NEGLBRACKET: return ParserSet(); - case TokenKind::LPAREN: - case TokenKind::QUESTLPAREN: - case TokenKind::STARLPAREN: - case TokenKind::PLUSLPAREN: - case TokenKind::NEGLPAREN: - case TokenKind::ATLPAREN: return ParserGroup(); + case TokenKind::LPAREN: + case TokenKind::QUESTLPAREN: + case TokenKind::STARLPAREN: + case TokenKind::PLUSLPAREN: + case TokenKind::NEGLPAREN: + case TokenKind::ATLPAREN: return ParserGroup(); - default: throw Error("basic glob expected"); + default: throw Error("basic glob expected"); + } } - } - AstNodePtr ParserGroup() - { - typename GroupNode::GroupType type; - Token &tk = NextToken(); + AstNodePtr ParserGroup() + { + typename GroupNode::GroupType type; + Token &tk = NextToken(); + + switch (tk.Kind()) { + case TokenKind::LPAREN: type = GroupNode::GroupType::BASIC; break; - switch (tk.Kind()) { - case TokenKind::LPAREN: type = GroupNode::GroupType::BASIC; break; + case TokenKind::QUESTLPAREN: type = GroupNode::GroupType::ANY; break; - case TokenKind::QUESTLPAREN: type = GroupNode::GroupType::ANY; break; + case TokenKind::STARLPAREN: type = GroupNode::GroupType::STAR; break; - case TokenKind::STARLPAREN: type = GroupNode::GroupType::STAR; break; + case TokenKind::PLUSLPAREN: type = GroupNode::GroupType::PLUS; break; - case TokenKind::PLUSLPAREN: type = GroupNode::GroupType::PLUS; break; + case TokenKind::NEGLPAREN: type = GroupNode::GroupType::NEG; break; - case TokenKind::NEGLPAREN: type = GroupNode::GroupType::NEG; break; + case TokenKind::ATLPAREN: type = GroupNode::GroupType::AT; break; - case TokenKind::ATLPAREN: type = GroupNode::GroupType::AT; break; + default: throw Error("Not valid group"); break; + } - default: throw Error("Not valid group"); break; - } + AstNodePtr group_glob = ParserUnion(); + tk = NextToken(); + if (tk != TokenKind::RPAREN) { + throw Error("Expected ')' at and of group"); + } - AstNodePtr group_glob = ParserUnion(); - tk = NextToken(); - if (tk != TokenKind::RPAREN) { - throw Error("Expected ')' at and of group"); + return AstNodePtr(new GroupNode(type, std::move(group_glob))); } - return AstNodePtr(new GroupNode(type, std::move(group_glob))); - } + AstNodePtr ParserConcat() + { + auto check_end = [&]() -> bool { + Token &tk = GetToken(); - AstNodePtr ParserConcat() - { - auto check_end = [&]() -> bool { - Token &tk = GetToken(); + switch (tk.Kind()) { + case TokenKind::EOS: + case TokenKind::RPAREN: + case TokenKind::UNION: return true; - switch (tk.Kind()) { - case TokenKind::EOS: - case TokenKind::RPAREN: - case TokenKind::UNION: return true; + default: return false; + } + }; - default: return false; - } - }; + std::vector> parts; - std::vector> parts; + while (!check_end()) { + parts.push_back(ParserBasicGlob()); + } - while (!check_end()) { - parts.push_back(ParserBasicGlob()); + return AstNodePtr(new ConcatNode(std::move(parts))); } - return AstNodePtr(new ConcatNode(std::move(parts))); - } + AstNodePtr ParserUnion() + { + std::vector> items; + items.push_back(ParserConcat()); - AstNodePtr ParserUnion() - { - std::vector> items; - items.push_back(ParserConcat()); + while (GetToken() == TokenKind::UNION) { + Advance(); + items.push_back(ParserConcat()); + } - while (GetToken() == TokenKind::UNION) { - Advance(); - items.push_back(ParserConcat()); + return AstNodePtr(new UnionNode(std::move(items))); } - return AstNodePtr(new UnionNode(std::move(items))); - } + AstNodePtr ParserGlob() + { + AstNodePtr glob = ParserConcat(); - AstNodePtr ParserGlob() - { - AstNodePtr glob = ParserConcat(); + if (GetToken() != TokenKind::EOS) { + throw Error("Expected the end of glob"); + } - if (GetToken() != TokenKind::EOS) { - throw Error("Expected the end of glob"); + return AstNodePtr(new GlobNode(std::move(glob))); } - return AstNodePtr(new GlobNode(std::move(glob))); - } - - inline const Token &GetToken() const { return tok_vec_.at(pos_); } + inline const Token &GetToken() const { return tok_vec_.at(pos_); } - inline Token &GetToken() { return tok_vec_.at(pos_); } + inline Token &GetToken() { return tok_vec_.at(pos_); } - inline const Token &PeekAhead() const - { - if (pos_ >= (tok_vec_.size() - 1)) - return tok_vec_.back(); - - return tok_vec_.at(pos_ + 1); - } + inline const Token &PeekAhead() const + { + if (pos_ >= (tok_vec_.size() - 1)) + return tok_vec_.back(); - inline Token &NextToken() - { - if (pos_ >= (tok_vec_.size() - 1)) - return tok_vec_.back(); + return tok_vec_.at(pos_ + 1); + } - Token &tk = tok_vec_.at(pos_); - pos_++; - return tk; - } + inline Token &NextToken() + { + if (pos_ >= (tok_vec_.size() - 1)) + return tok_vec_.back(); - inline bool Advance() - { - if (pos_ == tok_vec_.size() - 1) - return false; + Token &tk = tok_vec_.at(pos_); + pos_++; + return tk; + } - ++pos_; - return true; - } + inline bool Advance() + { + if (pos_ == tok_vec_.size() - 1) + return false; - inline size_t Size() const noexcept { return tok_vec_.size(); } + ++pos_; + return true; + } - std::vector> tok_vec_; - size_t pos_; - }; + inline size_t Size() const noexcept { return tok_vec_.size(); } - template class AstConsumer - { - public: - AstConsumer() = default; + std::vector> tok_vec_; + size_t pos_; + }; - void GenAutomata(AstNode *root_node, Automata &automata) + template class AstConsumer { - AstNode *concat_node = static_cast *>(root_node)->GetConcat(); - ExecConcat(concat_node, automata); + public: + AstConsumer() = default; - size_t match_state = automata.template NewState>(); - automata.GetState(preview_state_).AddNextState(match_state); - automata.SetMatchState(match_state); + void GenAutomata(AstNode *root_node, Automata &automata) + { + AstNode *concat_node = static_cast *>(root_node)->GetConcat(); + ExecConcat(concat_node, automata); - size_t fail_state = automata.template NewState>(); - automata.SetFailState(fail_state); - } + size_t match_state = automata.template NewState>(); + automata.GetState(preview_state_).AddNextState(match_state); + automata.SetMatchState(match_state); - private: - void ExecConcat(AstNode *node, Automata &automata) - { - ConcatNode *concat_node = static_cast *>(node); - std::vector> &basic_globs = concat_node->GetBasicGlobs(); + size_t fail_state = automata.template NewState>(); + automata.SetFailState(fail_state); + } - for (auto &basic_glob : basic_globs) { - ExecBasicGlob(basic_glob.get(), automata); + private: + void ExecConcat(AstNode *node, Automata &automata) + { + ConcatNode *concat_node = static_cast *>(node); + std::vector> &basic_globs = concat_node->GetBasicGlobs(); + + for (auto &basic_glob : basic_globs) { + ExecBasicGlob(basic_glob.get(), automata); + } } - } - void ExecBasicGlob(AstNode *node, Automata &automata) - { - switch (node->GetType()) { - case AstNode::Type::CHAR: ExecChar(node, automata); break; + void ExecBasicGlob(AstNode *node, Automata &automata) + { + switch (node->GetType()) { + case AstNode::Type::CHAR: ExecChar(node, automata); break; - case AstNode::Type::ANY: ExecAny(node, automata); break; + case AstNode::Type::ANY: ExecAny(node, automata); break; - case AstNode::Type::STAR: ExecStar(node, automata); break; + case AstNode::Type::STAR: ExecStar(node, automata); break; - case AstNode::Type::POS_SET: ExecPositiveSet(node, automata); break; + case AstNode::Type::POS_SET: ExecPositiveSet(node, automata); break; - case AstNode::Type::NEG_SET: ExecNegativeSet(node, automata); break; + case AstNode::Type::NEG_SET: ExecNegativeSet(node, automata); break; - case AstNode::Type::GROUP: ExecGroup(node, automata); break; + case AstNode::Type::GROUP: ExecGroup(node, automata); break; - default: break; + default: break; + } } - } - - void ExecChar(AstNode *node, Automata &automata) - { - CharNode *char_node = static_cast *>(node); - char c = char_node->GetValue(); - NewState>(automata, c); - } - void ExecAny(AstNode *, Automata &automata) - { - NewState>(automata); - } + void ExecChar(AstNode *node, Automata &automata) + { + CharNode *char_node = static_cast *>(node); + char c = char_node->GetValue(); + NewState>(automata, c); + } - void ExecStar(AstNode *, Automata &automata) - { - NewState>(automata); - automata.GetState(current_state_).AddNextState(current_state_); - } + void ExecAny(AstNode *, Automata &automata) + { + NewState>(automata); + } - void ExecPositiveSet(AstNode *node, Automata &automata) - { - PositiveSetNode *pos_set_node = static_cast *>(node); + void ExecStar(AstNode *, Automata &automata) + { + NewState>(automata); + automata.GetState(current_state_).AddNextState(current_state_); + } - auto items = ProcessSetItems(pos_set_node->GetSet()); - NewState>(automata, std::move(items)); - } + void ExecPositiveSet(AstNode *node, Automata &automata) + { + PositiveSetNode *pos_set_node = static_cast *>(node); - void ExecNegativeSet(AstNode *node, Automata &automata) - { - NegativeSetNode *pos_set_node = static_cast *>(node); + auto items = ProcessSetItems(pos_set_node->GetSet()); + NewState>(automata, std::move(items)); + } - auto items = ProcessSetItems(pos_set_node->GetSet()); - NewState>(automata, std::move(items), /*neg*/ true); - } + void ExecNegativeSet(AstNode *node, Automata &automata) + { + NegativeSetNode *pos_set_node = static_cast *>(node); - std::vector>> ProcessSetItems(AstNode *node) - { - SetItemsNode *set_node = static_cast *>(node); - std::vector>> vec; - auto &items = set_node->GetItems(); - for (auto &item : items) { - vec.push_back(std::move(ProcessSetItem(item.get()))); + auto items = ProcessSetItems(pos_set_node->GetSet()); + NewState>(automata, std::move(items), /*neg*/ true); } - return vec; - } + std::vector>> ProcessSetItems(AstNode *node) + { + SetItemsNode *set_node = static_cast *>(node); + std::vector>> vec; + auto &items = set_node->GetItems(); + for (auto &item : items) { + vec.push_back(std::move(ProcessSetItem(item.get()))); + } - std::unique_ptr> ProcessSetItem(AstNode *node) - { - if (node->GetType() == AstNode::Type::CHAR) { - CharNode *char_node = static_cast *>(node); - char c = char_node->GetValue(); - return std::unique_ptr>(new SetItemChar(c)); + return vec; } - else if (node->GetType() == AstNode::Type::RANGE) { - RangeNode *range_node = static_cast *>(node); - CharNode *start_node = static_cast *>(range_node->GetStart()); - CharNode *end_node = static_cast *>(range_node->GetEnd()); + std::unique_ptr> ProcessSetItem(AstNode *node) + { + if (node->GetType() == AstNode::Type::CHAR) { + CharNode *char_node = static_cast *>(node); + char c = char_node->GetValue(); + return std::unique_ptr>(new SetItemChar(c)); + } + else if (node->GetType() == AstNode::Type::RANGE) { + RangeNode *range_node = static_cast *>(node); + CharNode *start_node = static_cast *>(range_node->GetStart()); - char start_char = start_node->GetValue(); - char end_char = end_node->GetValue(); - return std::unique_ptr>(new SetItemRange(start_char, end_char)); - } - else { - throw Error("Not valid set item"); + CharNode *end_node = static_cast *>(range_node->GetEnd()); + + char start_char = start_node->GetValue(); + char end_char = end_node->GetValue(); + return std::unique_ptr>(new SetItemRange(start_char, end_char)); + } + else { + throw Error("Not valid set item"); + } } - } - void ExecGroup(AstNode *node, Automata &automata) - { - GroupNode *group_node = static_cast *>(node); - AstNode *union_node = group_node->GetGlob(); - std::vector>> automatas = ExecUnion(union_node); + void ExecGroup(AstNode *node, Automata &automata) + { + GroupNode *group_node = static_cast *>(node); + AstNode *union_node = group_node->GetGlob(); + std::vector>> automatas = ExecUnion(union_node); - typename StateGroup::Type state_group_type{}; - switch (group_node->GetGroupType()) { - case GroupNode::GroupType::BASIC: - state_group_type = StateGroup::Type::BASIC; - break; + typename StateGroup::Type state_group_type{}; + switch (group_node->GetGroupType()) { + case GroupNode::GroupType::BASIC: + state_group_type = StateGroup::Type::BASIC; + break; - case GroupNode::GroupType::ANY: state_group_type = StateGroup::Type::ANY; break; + case GroupNode::GroupType::ANY: + state_group_type = StateGroup::Type::ANY; + break; - case GroupNode::GroupType::STAR: - state_group_type = StateGroup::Type::STAR; - break; + case GroupNode::GroupType::STAR: + state_group_type = StateGroup::Type::STAR; + break; - case GroupNode::GroupType::PLUS: - state_group_type = StateGroup::Type::PLUS; - break; + case GroupNode::GroupType::PLUS: + state_group_type = StateGroup::Type::PLUS; + break; - case GroupNode::GroupType::AT: state_group_type = StateGroup::Type::AT; break; + case GroupNode::GroupType::AT: state_group_type = StateGroup::Type::AT; break; - case GroupNode::GroupType::NEG: state_group_type = StateGroup::Type::NEG; break; + case GroupNode::GroupType::NEG: + state_group_type = StateGroup::Type::NEG; + break; + } + + NewState>(automata, state_group_type, std::move(automatas)); + automata.GetState(current_state_).AddNextState(current_state_); } - NewState>(automata, state_group_type, std::move(automatas)); - automata.GetState(current_state_).AddNextState(current_state_); - } + std::vector>> ExecUnion(AstNode *node) + { + UnionNode *union_node = static_cast *>(node); + auto &items = union_node->GetItems(); + std::vector>> vec_automatas; + for (auto &item : items) { + std::unique_ptr> automata_ptr(new Automata); + AstConsumer ast_consumer; + ast_consumer.ExecConcat(item.get(), *automata_ptr); - std::vector>> ExecUnion(AstNode *node) - { - UnionNode *union_node = static_cast *>(node); - auto &items = union_node->GetItems(); - std::vector>> vec_automatas; - for (auto &item : items) { - std::unique_ptr> automata_ptr(new Automata); - AstConsumer ast_consumer; - ast_consumer.ExecConcat(item.get(), *automata_ptr); + size_t match_state = automata_ptr->template NewState>(); + automata_ptr->GetState(ast_consumer.preview_state_).AddNextState(match_state); + automata_ptr->SetMatchState(match_state); - size_t match_state = automata_ptr->template NewState>(); - automata_ptr->GetState(ast_consumer.preview_state_).AddNextState(match_state); - automata_ptr->SetMatchState(match_state); + size_t fail_state = automata_ptr->template NewState>(); + automata_ptr->SetFailState(fail_state); - size_t fail_state = automata_ptr->template NewState>(); - automata_ptr->SetFailState(fail_state); + vec_automatas.push_back(std::move(automata_ptr)); + } - vec_automatas.push_back(std::move(automata_ptr)); + return vec_automatas; } - return vec_automatas; - } - - template void NewState(Automata &automata, Args &&...args) - { - current_state_ = automata.template NewState(std::forward(args)...); - if (preview_state_ >= 0) { - automata.GetState(preview_state_).AddNextState(current_state_); + template void NewState(Automata &automata, Args &&...args) + { + current_state_ = automata.template NewState(std::forward(args)...); + if (preview_state_ >= 0) { + automata.GetState(preview_state_).AddNextState(current_state_); + } + preview_state_ = current_state_; } - preview_state_ = current_state_; - } - private: - int preview_state_ = -1; - size_t current_state_ = 0; - }; + private: + int preview_state_ = -1; + size_t current_state_ = 0; + }; - template class ExtendedGlob - { - public: - ExtendedGlob(const String &pattern) + template class ExtendedGlob { - Lexer l(pattern); - std::vector> tokens = l.Scanner(); - Parser p(std::move(tokens)); - AstNodePtr ast_ptr = p.GenAst(); + public: + ExtendedGlob(const String &pattern) + { + Lexer l(pattern); + std::vector> tokens = l.Scanner(); + Parser p(std::move(tokens)); + AstNodePtr ast_ptr = p.GenAst(); - AstConsumer ast_consumer; - ast_consumer.GenAutomata(ast_ptr.get(), automata_); - } + AstConsumer ast_consumer; + ast_consumer.GenAutomata(ast_ptr.get(), automata_); + } - ExtendedGlob(const ExtendedGlob &) = delete; - ExtendedGlob &operator=(ExtendedGlob &) = delete; + ExtendedGlob(const ExtendedGlob &) = delete; + ExtendedGlob &operator=(ExtendedGlob &) = delete; - ExtendedGlob(ExtendedGlob &&glob) : automata_{std::move(glob.automata_)} {} + ExtendedGlob(ExtendedGlob &&glob) : automata_{std::move(glob.automata_)} {} - ExtendedGlob &operator=(ExtendedGlob &&glob) - { - automata_ = std::move(glob.automata_); - return *this; - } + ExtendedGlob &operator=(ExtendedGlob &&glob) + { + automata_ = std::move(glob.automata_); + return *this; + } - bool Exec(const String &str) - { - bool r; - std::tie(r, std::ignore) = automata_.Exec(str); - return r; - } + bool Exec(const String &str) + { + bool r; + std::tie(r, std::ignore) = automata_.Exec(str); + return r; + } - const Automata &GetAutomata() const { return automata_; } + const Automata &GetAutomata() const { return automata_; } - private: - Automata automata_; - }; + private: + Automata automata_; + }; - template class SimpleGlob - { - public: - SimpleGlob(const String &pattern) { Parser(pattern); } + template class SimpleGlob + { + public: + SimpleGlob(const String &pattern) { Parser(pattern); } - SimpleGlob(const SimpleGlob &) = delete; - SimpleGlob &operator=(SimpleGlob &) = delete; + SimpleGlob(const SimpleGlob &) = delete; + SimpleGlob &operator=(SimpleGlob &) = delete; - SimpleGlob(SimpleGlob &&glob) : automata_{std::move(glob.automata_)} {} + SimpleGlob(SimpleGlob &&glob) : automata_{std::move(glob.automata_)} {} - SimpleGlob &operator=(SimpleGlob &&glob) - { - automata_ = std::move(glob.automata_); - return *this; - } + SimpleGlob &operator=(SimpleGlob &&glob) + { + automata_ = std::move(glob.automata_); + return *this; + } - void Parser(const String &pattern) - { - size_t pos = 0; - int preview_state = -1; - - while (pos < pattern.length()) { - size_t current_state = 0; - char c = pattern[pos]; - switch (c) { - case '?': { - current_state = automata_.template NewState>(); - ++pos; - break; - } + void Parser(const String &pattern) + { + size_t pos = 0; + int preview_state = -1; + + while (pos < pattern.length()) { + size_t current_state = 0; + char c = pattern[pos]; + switch (c) { + case '?': { + current_state = automata_.template NewState>(); + ++pos; + break; + } - case '*': { - current_state = automata_.template NewState>(); - automata_.GetState(current_state).AddNextState(current_state); - ++pos; - break; - } + case '*': { + current_state = automata_.template NewState>(); + automata_.GetState(current_state).AddNextState(current_state); + ++pos; + break; + } - default: { - current_state = automata_.template NewState>(c); - ++pos; - break; - } - } + default: { + current_state = automata_.template NewState>(c); + ++pos; + break; + } + } - if (preview_state >= 0) { - automata_.GetState(preview_state).AddNextState(current_state); + if (preview_state >= 0) { + automata_.GetState(preview_state).AddNextState(current_state); + } + preview_state = current_state; } - preview_state = current_state; - } - size_t match_state = automata_.template NewState>(); - automata_.GetState(preview_state).AddNextState(match_state); - automata_.SetMatchState(match_state); + size_t match_state = automata_.template NewState>(); + automata_.GetState(preview_state).AddNextState(match_state); + automata_.SetMatchState(match_state); - size_t fail_state = automata_.template NewState>(); - automata_.SetFailState(fail_state); - } + size_t fail_state = automata_.template NewState>(); + automata_.SetFailState(fail_state); + } - bool Exec(const String &str) const - { - bool r; - std::tie(r, std::ignore) = automata_.Exec(str); - return r; - } + bool Exec(const String &str) const + { + bool r; + std::tie(r, std::ignore) = automata_.Exec(str); + return r; + } - const Automata &GetAutomata() const { return automata_; } + const Automata &GetAutomata() const { return automata_; } - private: - Automata automata_; - }; + private: + Automata automata_; + }; - template using extended_glob = ExtendedGlob; + template using extended_glob = ExtendedGlob; - template using no_extended_glob = SimpleGlob; + template using no_extended_glob = SimpleGlob; - template class MatchResults; + template class MatchResults; - template > class BasicGlob - { - public: - BasicGlob(const String &pattern) : glob_{pattern} {} + template > class BasicGlob + { + public: + BasicGlob(const String &pattern) : glob_{pattern} {} - BasicGlob(const BasicGlob &) = delete; - BasicGlob &operator=(BasicGlob &) = delete; + BasicGlob(const BasicGlob &) = delete; + BasicGlob &operator=(BasicGlob &) = delete; - BasicGlob(BasicGlob &&glob) : glob_{std::move(glob.glob_)} {} + BasicGlob(BasicGlob &&glob) : glob_{std::move(glob.glob_)} {} - BasicGlob &operator=(BasicGlob &&glob) - { - glob_ = std::move(glob.glob_); - return *this; - } + BasicGlob &operator=(BasicGlob &&glob) + { + glob_ = std::move(glob.glob_); + return *this; + } - const Automata &GetAutomata() const { return glob_.GetAutomata(); } + const Automata &GetAutomata() const { return glob_.GetAutomata(); } - private: - bool Exec(const String &str) { return glob_.Exec(str); } + private: + bool Exec(const String &str) { return glob_.Exec(str); } - template - friend bool glob_match(const String &str, BasicGlob &glob); + template + friend bool glob_match(const String &str, BasicGlob &glob); - template - friend bool glob_match(const charU *str, BasicGlob &glob); + template + friend bool glob_match(const charU *str, BasicGlob &glob); - template - friend bool glob_match(const String &str, MatchResults &res, - BasicGlob &glob); + template + friend bool glob_match(const String &str, MatchResults &res, + BasicGlob &glob); - template - friend bool glob_match(const charU *str, MatchResults &res, - BasicGlob &glob); + template + friend bool glob_match(const charU *str, MatchResults &res, + BasicGlob &glob); - globT glob_; - }; + globT glob_; + }; - template class MatchResults - { - public: - using const_iterator = typename std::vector>::const_iterator; + template class MatchResults + { + public: + using const_iterator = typename std::vector>::const_iterator; - MatchResults() = default; + MatchResults() = default; - MatchResults(const MatchResults &m) : results_{m.results_} {} + MatchResults(const MatchResults &m) : results_{m.results_} {} - MatchResults(MatchResults &&m) : results_{std::move(m.results_)} {} + MatchResults(MatchResults &&m) : results_{std::move(m.results_)} {} - MatchResults &operator=(const MatchResults &m) - { - results_ = m.results_; + MatchResults &operator=(const MatchResults &m) + { + results_ = m.results_; - return *this; - } + return *this; + } - MatchResults &operator=(MatchResults &&m) - { - results_ = std::move(m.results_); + MatchResults &operator=(MatchResults &&m) + { + results_ = std::move(m.results_); - return *this; - } + return *this; + } - bool empty() const { return results_.empty(); } + bool empty() const { return results_.empty(); } - size_t size() const { return results_.size(); } + size_t size() const { return results_.size(); } - const_iterator begin() const noexcept { return results_.begin(); } + const_iterator begin() const noexcept { return results_.begin(); } - const_iterator end() const noexcept { return results_.end(); } + const_iterator end() const noexcept { return results_.end(); } - const_iterator cbegin() const noexcept { return results_.cbegin(); } + const_iterator cbegin() const noexcept { return results_.cbegin(); } - const_iterator cend() const noexcept { return results_.cend(); } + const_iterator cend() const noexcept { return results_.cend(); } - String &operator[](size_t n) const { return results_[n]; } + String &operator[](size_t n) const { return results_[n]; } - private: - void SetResults(std::vector> &&results) { results_ = std::move(results); } + private: + void SetResults(std::vector> &&results) { results_ = std::move(results); } - template - friend bool glob_match(const String &str, BasicGlob &glob); + template + friend bool glob_match(const String &str, BasicGlob &glob); - template - friend bool glob_match(const charU *str, BasicGlob &glob); + template + friend bool glob_match(const charU *str, BasicGlob &glob); - template - friend bool glob_match(const String &str, MatchResults &res, - BasicGlob &glob); + template + friend bool glob_match(const String &str, MatchResults &res, + BasicGlob &glob); - template - friend bool glob_match(const charU *str, MatchResults &res, - BasicGlob &glob); + template + friend bool glob_match(const charU *str, MatchResults &res, + BasicGlob &glob); - std::vector> results_; - }; + std::vector> results_; + }; - template > - bool glob_match(const String &str, BasicGlob &glob) - { - return glob.Exec(str); - } + template > + bool glob_match(const String &str, BasicGlob &glob) + { + return glob.Exec(str); + } - template > - bool glob_match(const charT *str, BasicGlob &glob) - { - return glob.Exec(str); - } + template > + bool glob_match(const charT *str, BasicGlob &glob) + { + return glob.Exec(str); + } - template > - bool glob_match(const String &str, MatchResults &res, BasicGlob &glob) - { - bool r = glob.Exec(str); - res.SetResults(glob.GetAutomata().GetMatchedStrings()); - return r; - } + template > + bool glob_match(const String &str, MatchResults &res, + BasicGlob &glob) + { + bool r = glob.Exec(str); + res.SetResults(glob.GetAutomata().GetMatchedStrings()); + return r; + } - template > - bool glob_match(const charT *str, MatchResults &res, BasicGlob &glob) - { - bool r = glob.Exec(str); - res.SetResults(glob.GetAutomata().GetMatchedStrings()); - return r; - } + template > + bool glob_match(const charT *str, MatchResults &res, BasicGlob &glob) + { + bool r = glob.Exec(str); + res.SetResults(glob.GetAutomata().GetMatchedStrings()); + return r; + } - template > - using basic_glob = BasicGlob; + template > + using basic_glob = BasicGlob; - using glob = basic_glob>; + using glob = basic_glob>; - using wglob = basic_glob>; + using wglob = basic_glob>; - using cmatch = MatchResults; + using cmatch = MatchResults; - using wmatch = MatchResults; + using wmatch = MatchResults; -} // namespace glob + } // namespace glob +} // namespace Ioss diff --git a/packages/seacas/libraries/ioss/src/Ioss_IOFactory.h b/packages/seacas/libraries/ioss/src/Ioss_IOFactory.h index 4505d71b35d9..eb13f6504b26 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_IOFactory.h +++ b/packages/seacas/libraries/ioss/src/Ioss_IOFactory.h @@ -35,7 +35,7 @@ namespace Ioss { virtual ~IOFactory() = default; static DatabaseIO *create(const std::string &type, const std::string &filename, DatabaseUsage db_usage, - Ioss_MPI_Comm communicator = Ioss::ParallelUtils::comm_world(), + Ioss_MPI_Comm communicator = Ioss::ParallelUtils::comm_world(), const Ioss::PropertyManager &properties = Ioss::PropertyManager()); static int describe(NameList *names); diff --git a/packages/seacas/libraries/ioss/src/Ioss_ParallelUtils.C b/packages/seacas/libraries/ioss/src/Ioss_ParallelUtils.C index a1630feeb95d..b43fed21feb2 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_ParallelUtils.C +++ b/packages/seacas/libraries/ioss/src/Ioss_ParallelUtils.C @@ -42,7 +42,9 @@ namespace { #endif } // namespace -Ioss::ParallelUtils::ParallelUtils(Ioss_MPI_Comm the_communicator) : communicator_(the_communicator) {} +Ioss::ParallelUtils::ParallelUtils(Ioss_MPI_Comm the_communicator) : communicator_(the_communicator) +{ +} void Ioss::ParallelUtils::add_environment_properties(Ioss::PropertyManager &properties) { @@ -421,7 +423,8 @@ template <> void Ioss::ParallelUtils::broadcast(std::string &my_str, int root) c { #ifdef SEACAS_HAVE_MPI if (parallel_size() > 1) { - const int success = MPI_Bcast(const_cast(my_str.data()), (int)my_str.size()+1, MPI_CHAR, root, communicator_); + const int success = MPI_Bcast(const_cast(my_str.data()), (int)my_str.size() + 1, + MPI_CHAR, root, communicator_); if (success != MPI_SUCCESS) { std::ostringstream errmsg; fmt::print(errmsg, "{} - MPI_Broadcast failed", __func__); @@ -456,11 +459,13 @@ template void Ioss::ParallelUtils::broadcast(std::vector &, int) cons /// \relates Ioss::ParallelUtils::broadcast template void Ioss::ParallelUtils::broadcast(std::vector &, int) const; /// \relates Ioss::ParallelUtils::broadcast -template <> void Ioss::ParallelUtils::broadcast(std::vector> &my_value, int root) const +template <> +void Ioss::ParallelUtils::broadcast(std::vector> &my_value, int root) const { #ifdef SEACAS_HAVE_MPI if (parallel_size() > 1) { - const int success = MPI_Bcast(my_value.data(), (int)my_value.size() * 2, mpi_type(int(0)), root, communicator_); + const int success = + MPI_Bcast(my_value.data(), (int)my_value.size() * 2, mpi_type(int(0)), root, communicator_); if (success != MPI_SUCCESS) { std::ostringstream errmsg; fmt::print(errmsg, "{} - MPI_Broadcast failed", __func__); @@ -470,12 +475,12 @@ template <> void Ioss::ParallelUtils::broadcast(std::vector> #endif } - template void Ioss::ParallelUtils::broadcast(std::vector &my_value, int root) const { #ifdef SEACAS_HAVE_MPI if (parallel_size() > 1) { - const int success = MPI_Bcast(my_value.data(), (int)my_value.size(), mpi_type(T()), root, communicator_); + const int success = + MPI_Bcast(my_value.data(), (int)my_value.size(), mpi_type(T()), root, communicator_); if (success != MPI_SUCCESS) { std::ostringstream errmsg; fmt::print(errmsg, "{} - MPI_Broadcast failed", __func__); diff --git a/packages/seacas/libraries/ioss/src/Ioss_ParallelUtils.h b/packages/seacas/libraries/ioss/src/Ioss_ParallelUtils.h index 7acbc4403c09..c70e805a4a33 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_ParallelUtils.h +++ b/packages/seacas/libraries/ioss/src/Ioss_ParallelUtils.h @@ -40,9 +40,9 @@ namespace Ioss { static Ioss_MPI_Comm comm_self() { return (Ioss_MPI_Comm)MPI_COMM_SELF; } static Ioss_MPI_Comm comm_null() { return (Ioss_MPI_Comm)MPI_COMM_NULL; } #else - static constexpr Ioss_MPI_Comm comm_world() { return (Ioss_MPI_Comm)0; } - static constexpr Ioss_MPI_Comm comm_self() { return (Ioss_MPI_Comm)0; } - static constexpr Ioss_MPI_Comm comm_null() { return (Ioss_MPI_Comm)0; } + static constexpr Ioss_MPI_Comm comm_world() { return 0; } + static constexpr Ioss_MPI_Comm comm_self() { return 0; } + static constexpr Ioss_MPI_Comm comm_null() { return 0; } #endif /*! @@ -81,8 +81,8 @@ namespace Ioss { std::string decode_filename(const std::string &filename, bool is_parallel) const; Ioss_MPI_Comm communicator() const { return communicator_; } - int parallel_size() const; - int parallel_rank() const; + int parallel_size() const; + int parallel_rank() const; void barrier() const; diff --git a/packages/seacas/libraries/ioss/src/Ioss_PropertyManager.C b/packages/seacas/libraries/ioss/src/Ioss_PropertyManager.C index ffdefca5ffe0..db459029b467 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_PropertyManager.C +++ b/packages/seacas/libraries/ioss/src/Ioss_PropertyManager.C @@ -75,6 +75,16 @@ Ioss::Property Ioss::PropertyManager::get(const std::string &property_name) cons * \param[in] optional_value The value to return if the property does not exist. * \returns The property object. */ +int Ioss::PropertyManager::get_optional(const std::string &property_name, int optional_value) const +{ + IOSS_FUNC_ENTER(m_); + auto iter = m_properties.find(property_name); + if (iter == m_properties.end()) { + return optional_value; + } + return (*iter).second.get_int(); +} + int64_t Ioss::PropertyManager::get_optional(const std::string &property_name, int64_t optional_value) const { @@ -86,6 +96,17 @@ int64_t Ioss::PropertyManager::get_optional(const std::string &property_name, return (*iter).second.get_int(); } +double Ioss::PropertyManager::get_optional(const std::string &property_name, + double optional_value) const +{ + IOSS_FUNC_ENTER(m_); + auto iter = m_properties.find(property_name); + if (iter == m_properties.end()) { + return optional_value; + } + return (*iter).second.get_real(); +} + std::string Ioss::PropertyManager::get_optional(const std::string &property_name, const std::string &optional_value) const { diff --git a/packages/seacas/libraries/ioss/src/Ioss_PropertyManager.h b/packages/seacas/libraries/ioss/src/Ioss_PropertyManager.h index 1cde677f27fa..ffdd48e3e78c 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_PropertyManager.h +++ b/packages/seacas/libraries/ioss/src/Ioss_PropertyManager.h @@ -37,7 +37,9 @@ namespace Ioss { bool exists(const std::string &property_name) const; Property get(const std::string &property_name) const; + double get_optional(const std::string &property_name, double optional_value) const; int64_t get_optional(const std::string &property_name, int64_t optional_value) const; + int get_optional(const std::string &property_name, int optional_value) const; std::string get_optional(const std::string &property_name, const std::string &optional_value) const; @@ -52,7 +54,7 @@ namespace Ioss { size_t count() const; private: - PropMapType m_properties; + PropMapType m_properties{}; #if defined(IOSS_THREADSAFE) mutable std::mutex m_; #endif diff --git a/packages/seacas/libraries/ioss/src/Ioss_StructuredBlock.C b/packages/seacas/libraries/ioss/src/Ioss_StructuredBlock.C index 9fd3879a671d..60a7eed8bad0 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_StructuredBlock.C +++ b/packages/seacas/libraries/ioss/src/Ioss_StructuredBlock.C @@ -31,7 +31,7 @@ namespace { cell_count = static_cast(ni) * nj; } else if (index_dim == 3) { - cell_count = static_cast(ni) * nj * nk; + cell_count = static_cast(ni) * nj * (nk == 0 ? 1 : nk); } return cell_count; } diff --git a/packages/seacas/libraries/ioss/src/Ioss_Utils.C b/packages/seacas/libraries/ioss/src/Ioss_Utils.C index af31e26136fb..f2d8fb328090 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_Utils.C +++ b/packages/seacas/libraries/ioss/src/Ioss_Utils.C @@ -36,13 +36,10 @@ #endif #include -#if defined(_MSC_VER) -#include -#define isatty _isatty -#endif - // For memory utilities... #if defined(__IOSS_WINDOWS__) +#include +#define isatty _isatty #define WIN32_LEAN_AND_MEAN #ifndef NOMINMAX #define NOMINMAX @@ -444,7 +441,8 @@ namespace { } const Ioss::VariableType *match_single_field(char **names, Ioss::IntVector &which_names, - const char suffix_separator) + const char suffix_separator, + bool ignore_realn_fields) { // Strip off the suffix from each name indexed in 'which_names' // and see if it defines a valid type... @@ -460,13 +458,13 @@ namespace { Ioss::Suffix tmp(tokens[num_tokens - 1]); suffices.push_back(tmp); } - const Ioss::VariableType *type = Ioss::VariableType::factory(suffices); + const Ioss::VariableType *type = Ioss::VariableType::factory(suffices, ignore_realn_fields); return type; } Ioss::Field get_next_field(char **names, int num_names, size_t count, Ioss::Field::RoleType fld_role, const char suffix_separator, - const int *truth_table) + const int *truth_table, bool ignore_realn_fields) { // NOTE: 'names' are all lowercase at this point. @@ -578,7 +576,7 @@ namespace { } else { assert(suffix_size == 1); - type = match_single_field(names, which_names, suffix_separator); + type = match_single_field(names, which_names, suffix_separator, ignore_realn_fields); } if (type != nullptr) { @@ -674,6 +672,7 @@ void Ioss::Utils::get_fields(int64_t entity_count, // The number of objects in t { bool enable_field_recognition = db->get_field_recognition(); bool strip_trailing_ = db->get_field_strip_trailing_(); + bool ignore_realn_fields = db->get_ignore_realn_fields(); char suffix_separator = db->get_field_separator(); if (!enable_field_recognition) { @@ -689,8 +688,8 @@ void Ioss::Utils::get_fields(int64_t entity_count, // The number of objects in t else if (suffix_separator != 0) { while (true) { // NOTE: 'get_next_field' determines storage type (vector, tensor,...) - Ioss::Field field = - get_next_field(names, num_names, entity_count, fld_role, suffix_separator, local_truth); + Ioss::Field field = get_next_field(names, num_names, entity_count, fld_role, suffix_separator, + local_truth, ignore_realn_fields); if (field.is_valid()) { fields.push_back(field); } @@ -1019,6 +1018,22 @@ int64_t Ioss::Utils::get_side_offset(const Ioss::SideBlock *sb) return side_offset; } +std::string Ioss::Utils::shape_to_string(const Ioss::ElementShape &shape) +{ + switch (shape) { + case Ioss::ElementShape::UNKNOWN: return std::string("Unknown"); + case Ioss::ElementShape::POINT: return std::string("Point"); + case Ioss::ElementShape::LINE: return std::string("Line"); + case Ioss::ElementShape::TRI: return std::string("Tri"); + case Ioss::ElementShape::QUAD: return std::string("Quad"); + case Ioss::ElementShape::TET: return std::string("Tet"); + case Ioss::ElementShape::PYRAMID: return std::string("Pyramid"); + case Ioss::ElementShape::WEDGE: return std::string("Wedge"); + case Ioss::ElementShape::HEX: return std::string("Hex"); + } + return std::string("INTERNAL ERROR"); +} + unsigned int Ioss::Utils::hash(const std::string &name) { // Hash function from Aho, Sethi, Ullman "Compilers: Principles, @@ -1089,6 +1104,12 @@ bool Ioss::Utils::substr_equal(const std::string &prefix, const std::string &str return (str.size() >= prefix.size()) && str_equal(prefix, str.substr(0, prefix.size())); } +std::string Ioss::Utils::capitalize(std::string name) +{ + std::toupper(name[0]); + return name; +} + std::string Ioss::Utils::uppercase(std::string name) { std::transform(name.begin(), name.end(), name.begin(), @@ -1442,3 +1463,43 @@ void Ioss::Utils::info_property(const Ioss::GroupingEntity *ige, Ioss::Property: fmt::print("\n"); } } + +void Ioss::Utils::copyright(std::ostream &out, const std::string &year_range) +{ + fmt::print(out, + "\n" + "Copyright(C) {} National Technology & Engineering Solutions of\n" + "Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with\n" + "NTESS, the U.S. Government retains certain rights in this software.\n" + "\n" + "Redistribution and use in source and binary forms, with or without\n" + "modification, are permitted provided that the following conditions are\n" + "met:\n" + "\n" + "* Redistributions of source code must retain the above copyright\n" + " notice, this list of conditions and the following disclaimer.\n" + "\n" + "* Redistributions in binary form must reproduce the above\n" + " copyright notice, this list of conditions and the following\n" + " disclaimer in the documentation and/or other materials provided\n" + " with the distribution.\n" + "\n" + "* Neither the name of NTESS nor the names of its\n" + " contributors may be used to endorse or promote products derived\n" + " from this software without specific prior written permission.\n" + "\n" + "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" + "\" AS IS \" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" + "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" + "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" + "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" + "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" + "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" + "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" + "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" + "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" + "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" + "\n", + year_range); + return; +} diff --git a/packages/seacas/libraries/ioss/src/Ioss_Utils.h b/packages/seacas/libraries/ioss/src/Ioss_Utils.h index b097008f892b..e305dda7ecb4 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_Utils.h +++ b/packages/seacas/libraries/ioss/src/Ioss_Utils.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include #include @@ -107,6 +108,8 @@ namespace Ioss { static void set_pre_warning_text(const std::string &text) { m_preWarningText = text; } /** @}*/ + static void copyright(std::ostream &out, const std::string &year_range); + static void check_dynamic_cast(const void *ptr) { if (ptr == nullptr) { @@ -351,6 +354,13 @@ namespace Ioss { */ static std::string fixup_type(const std::string &base, int nodes_per_element, int spatial); + /** \brief Uppercase the first letter of the string + * + * \param[in] name The string to convert. + * \returns The converted string. + */ + static std::string capitalize(std::string name); + /** \brief Convert a string to upper case. * * \param[in] name The string to convert. @@ -480,6 +490,8 @@ namespace Ioss { static std::string variable_name_kluge(const std::string &name, size_t component_count, size_t copies, size_t max_var_len); + static std::string shape_to_string(const ElementShape &shape); + /** \brief Create a nominal mesh for use in history databases. * * The model for a history file is a single sphere element (1 node, 1 element). diff --git a/packages/seacas/libraries/ioss/src/Ioss_VariableType.C b/packages/seacas/libraries/ioss/src/Ioss_VariableType.C index 3a0c71e0f9fc..c834531fe874 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_VariableType.C +++ b/packages/seacas/libraries/ioss/src/Ioss_VariableType.C @@ -174,7 +174,8 @@ namespace Ioss { return inst; } - const VariableType *VariableType::factory(const std::vector &suffices) + const VariableType *VariableType::factory(const std::vector &suffices, + bool ignore_realn_fields) { size_t size = suffices.size(); const VariableType *ivt = nullptr; @@ -184,16 +185,17 @@ namespace Ioss { bool match = false; for (const auto &vtype : registry()) { - ivt = vtype.second; - if (ivt->suffix_count() == static_cast(size)) { - if (ivt->match(suffices)) { + auto *tst_ivt = vtype.second; + if (tst_ivt->suffix_count() == static_cast(size)) { + if (tst_ivt->match(suffices)) { + ivt = tst_ivt; match = true; break; } } } - if (!match) { + if (!match && !ignore_realn_fields) { match = true; // Check if the suffices form a sequence (1,2,3,...,N) // This indicates a "component" variable type that is @@ -215,9 +217,6 @@ namespace Ioss { // it would have been found above. ivt = new ConstructedVariableType(size, true); } - else { - ivt = nullptr; - } } return ivt; } diff --git a/packages/seacas/libraries/ioss/src/Ioss_VariableType.h b/packages/seacas/libraries/ioss/src/Ioss_VariableType.h index d8e6bd64a12a..a89942a7180d 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_VariableType.h +++ b/packages/seacas/libraries/ioss/src/Ioss_VariableType.h @@ -81,7 +81,8 @@ namespace Ioss { virtual bool match(const std::vector &suffices) const; static const VariableType *factory(const std::string &raw_name, int copies = 1); - static const VariableType *factory(const std::vector &suffices); + static const VariableType *factory(const std::vector &suffices, + bool ignore_realn_fields = false); protected: VariableType(const std::string &type, int comp_count, bool delete_me = false); diff --git a/packages/seacas/libraries/ioss/src/Ioss_Version.h b/packages/seacas/libraries/ioss/src/Ioss_Version.h index 80cd2a20ce15..6c286d8f951c 100644 --- a/packages/seacas/libraries/ioss/src/Ioss_Version.h +++ b/packages/seacas/libraries/ioss/src/Ioss_Version.h @@ -6,5 +6,5 @@ #pragma once namespace Ioss { - inline const char *Version() { return "2021-10-12"; } + inline const char *Version() { return "2022-03-15"; } } // namespace Ioss diff --git a/packages/seacas/libraries/ioss/src/cgns/Iocgns_DatabaseIO.C b/packages/seacas/libraries/ioss/src/cgns/Iocgns_DatabaseIO.C index c71cdce8fbc4..0a148bb7f19a 100644 --- a/packages/seacas/libraries/ioss/src/cgns/Iocgns_DatabaseIO.C +++ b/packages/seacas/libraries/ioss/src/cgns/Iocgns_DatabaseIO.C @@ -1571,9 +1571,10 @@ namespace Iocgns { int cell_dimension = 0; int phys_dimension = 0; CGCHECKM(cg_base_read(get_file_pointer(), base, basename, &cell_dimension, &phys_dimension)); - if (phys_dimension != 3) { + if (phys_dimension != 3 && mesh_type == Ioss::MeshType::STRUCTURED) { std::ostringstream errmsg; - fmt::print(errmsg, "ERROR: The model is {}D. Only 3D models are supported.", phys_dimension); + fmt::print(errmsg, "ERROR: The model is {}D. Only 3D structured models are supported.", + phys_dimension); IOSS_ERROR(errmsg); } @@ -1812,16 +1813,19 @@ namespace Iocgns { size_t num_to_get = field.verify(data_size); cgsize_t first = 1; - // Create a lambda to eliminate lots of duplicate code in coordinate outputs... - auto coord_lambda = [this, &data, &first, base](const char *ordinate) { + // Create a lambda to eliminate some duplicate code in coordinate outputs... + auto coord_lambda = [&data, &first, + base](const char *ordinate, int cgns_file_ptr, + const std::vector &block_local_node_map, + int myProcessor) { auto *rdata = static_cast(data); - for (int zone = 1; zone < static_cast(m_blockLocalNodeMap.size()); zone++) { - auto &block_map = m_blockLocalNodeMap[zone]; + for (int zone = 1; zone < static_cast(block_local_node_map.size()); zone++) { + auto &block_map = block_local_node_map[zone]; cgsize_t num_coord = block_map.size(); std::vector coord(num_coord); - CGCHECKM(cg_coord_read(get_file_pointer(), base, zone, ordinate, CGNS_ENUMV(RealDouble), - &first, &num_coord, coord.data())); + CGCHECK(cg_coord_read(cgns_file_ptr, base, zone, ordinate, CGNS_ENUMV(RealDouble), &first, + &num_coord, coord.data())); // Map to global coordinate position... for (cgsize_t i = 0; i < num_coord; i++) { @@ -1834,15 +1838,15 @@ namespace Iocgns { if (role == Ioss::Field::MESH) { if (field.get_name() == "mesh_model_coordinates_x") { // Use the lambda... - coord_lambda("CoordinateX"); + coord_lambda("CoordinateX", get_file_pointer(), m_blockLocalNodeMap, myProcessor); } else if (field.get_name() == "mesh_model_coordinates_y") { - coord_lambda("CoordinateY"); + coord_lambda("CoordinateY", get_file_pointer(), m_blockLocalNodeMap, myProcessor); } else if (field.get_name() == "mesh_model_coordinates_z") { - coord_lambda("CoordinateZ"); + coord_lambda("CoordinateZ", get_file_pointer(), m_blockLocalNodeMap, myProcessor); } else if (field.get_name() == "mesh_model_coordinates") { @@ -1866,10 +1870,11 @@ namespace Iocgns { // ======================================================================== // Repetitive code for each coordinate direction; use a lambda to consolidate... - auto blk_coord_lambda = [this, block_map, base, zone, &coord, first, num_coord, - phys_dimension, &rdata](const char *ord_name, int ordinate) { - CGCHECKM(cg_coord_read(get_file_pointer(), base, zone, ord_name, CGNS_ENUMV(RealDouble), - &first, &num_coord, coord.data())); + auto blk_coord_lambda = [block_map, base, zone, &coord, first, num_coord, phys_dimension, + &rdata](const char *ord_name, int ordinate, int cgns_file_ptr, + int myProcessor) { + CGCHECK(cg_coord_read(cgns_file_ptr, base, zone, ord_name, CGNS_ENUMV(RealDouble), + &first, &num_coord, coord.data())); // Map to global coordinate position... for (cgsize_t i = 0; i < num_coord; i++) { @@ -1879,14 +1884,14 @@ namespace Iocgns { // End of lambda... // ======================================================================== - blk_coord_lambda("CoordinateX", 0); + blk_coord_lambda("CoordinateX", 0, get_file_pointer(), myProcessor); if (phys_dimension >= 2) { - blk_coord_lambda("CoordinateY", 1); + blk_coord_lambda("CoordinateY", 1, get_file_pointer(), myProcessor); } if (phys_dimension >= 3) { - blk_coord_lambda("CoordinateZ", 2); + blk_coord_lambda("CoordinateZ", 2, get_file_pointer(), myProcessor); } } } @@ -2258,10 +2263,11 @@ namespace Iocgns { // ======================================================================== // Repetitive code for each coordinate direction; use a lambda to consolidate... - auto coord_lambda = [this, base, zone, &coord, &rmin, &rmax, phys_dimension, num_to_get, - &rdata](const char *ord_name, int ordinate) { - CGCHECKM(cg_coord_read(get_file_pointer(), base, zone, ord_name, CGNS_ENUMV(RealDouble), - rmin, rmax, coord.data())); + auto coord_lambda = [base, zone, &coord, &rmin, &rmax, phys_dimension, num_to_get, + &rdata](const char *ord_name, int ordinate, int cgns_file_ptr, + int myProcessor) { + CGCHECK(cg_coord_read(cgns_file_ptr, base, zone, ord_name, CGNS_ENUMV(RealDouble), rmin, + rmax, coord.data())); // Map to global coordinate position... for (cgsize_t i = 0; i < num_to_get; i++) { @@ -2271,14 +2277,14 @@ namespace Iocgns { // End of lambda... // ======================================================================== - coord_lambda("CoordinateX", 0); + coord_lambda("CoordinateX", 0, get_file_pointer(), myProcessor); if (phys_dimension >= 2) { - coord_lambda("CoordinateY", 1); + coord_lambda("CoordinateY", 1, get_file_pointer(), myProcessor); } if (phys_dimension == 3) { - coord_lambda("CoordinateZ", 2); + coord_lambda("CoordinateZ", 2, get_file_pointer(), myProcessor); } } else if (field.get_name() == "cell_node_ids") { @@ -2571,8 +2577,9 @@ namespace Iocgns { // ======================================================================== // Repetitive code for each coordinate direction; use a lambda to consolidate... - auto coord_lambda = [this, &coord, num_to_get, phys_dimension, &rdata, base, - zone](const char *ord_name, int ordinate) { + auto coord_lambda = [&coord, num_to_get, phys_dimension, &rdata, base, + zone](const char *ord_name, int ordinate, int cgns_file_ptr, + int myProcessor) { int crd_index = 0; // Map to global coordinate position... @@ -2580,19 +2587,19 @@ namespace Iocgns { coord[i] = rdata[phys_dimension * i + ordinate]; } - CGCHECKM(cg_coord_write(get_file_pointer(), base, zone, CGNS_ENUMV(RealDouble), ord_name, - coord.data(), &crd_index)); + CGCHECK(cg_coord_write(cgns_file_ptr, base, zone, CGNS_ENUMV(RealDouble), ord_name, + coord.data(), &crd_index)); }; // End of lambda... // ======================================================================== - coord_lambda("CoordinateX", 0); + coord_lambda("CoordinateX", 0, get_file_pointer(), myProcessor); if (phys_dimension >= 2) { - coord_lambda("CoordinateY", 1); + coord_lambda("CoordinateY", 1, get_file_pointer(), myProcessor); } if (phys_dimension == 3) { - coord_lambda("CoordinateZ", 2); + coord_lambda("CoordinateZ", 2, get_file_pointer(), myProcessor); } } else { @@ -2713,8 +2720,10 @@ namespace Iocgns { int field_byte_size = (field.get_type() == Ioss::Field::INT32) ? 32 : 64; if (field_byte_size == CG_SIZEOF_SIZE) { Utils::unmap_cgns_connectivity(eb->topology(), num_to_get, (cgsize_t *)data); - CGCHECKM(cg_section_write(get_file_pointer(), base, zone, "HexElements", type, 1, - num_to_get, 0, (cgsize_t *)data, §)); + std::string element_type = + fmt::format("{}Elements", Ioss::Utils::shape_to_string(eb->topology()->shape())); + CGCHECKM(cg_section_write(get_file_pointer(), base, zone, element_type.c_str(), type, + 1, num_to_get, 0, (cgsize_t *)data, §)); } else { CGNSIntVector connect; @@ -2732,8 +2741,10 @@ namespace Iocgns { } } Utils::unmap_cgns_connectivity(eb->topology(), num_to_get, connect.data()); - CGCHECKM(cg_section_write(get_file_pointer(), base, zone, "HexElements", type, 1, - num_to_get, 0, connect.data(), §)); + std::string element_type = + fmt::format("{}Elements", Ioss::Utils::shape_to_string(eb->topology()->shape())); + CGCHECKM(cg_section_write(get_file_pointer(), base, zone, element_type.c_str(), type, + 1, num_to_get, 0, connect.data(), §)); } m_bcOffset[zone] += num_to_get; eb->property_update("section", sect); @@ -3089,8 +3100,10 @@ namespace Iocgns { CGCHECKM( cg_goto(get_file_pointer(), base, "Zone_t", zone, "ZoneBC_t", 1, "BC_t", sect, "end")); CGCHECKM(cg_famname_write(name.c_str())); - CGCHECKM(cg_boco_gridlocation_write(get_file_pointer(), base, zone, sect, - CGNS_ENUMV(FaceCenter))); + + int phys_dimension = get_region()->get_property("spatial_dimension").get_int(); + auto location = phys_dimension == 2 ? CGNS_ENUMV(EdgeCenter) : CGNS_ENUMV(FaceCenter); + CGCHECKM(cg_boco_gridlocation_write(get_file_pointer(), base, zone, sect, location)); CGCHECKM(cg_section_partial_write(get_file_pointer(), base, zone, sb_name.c_str(), type, cg_start, cg_end, 0, §)); diff --git a/packages/seacas/libraries/ioss/src/cgns/Iocgns_ParallelDatabaseIO.C b/packages/seacas/libraries/ioss/src/cgns/Iocgns_ParallelDatabaseIO.C index 38e9b8981a8c..f90bd0a8b6af 100644 --- a/packages/seacas/libraries/ioss/src/cgns/Iocgns_ParallelDatabaseIO.C +++ b/packages/seacas/libraries/ioss/src/cgns/Iocgns_ParallelDatabaseIO.C @@ -2066,8 +2066,10 @@ namespace Iocgns { if (size[1] > 0) { CGNS_ENUMT(ElementType_t) type = Utils::map_topology_to_cgns(eb->topology()->name()); - int sect = 0; - CGCHECKM(cgp_section_write(get_file_pointer(), base, zone, "HexElements", type, 1, + int sect = 0; + std::string element_type = + fmt::format("{}Elements", Ioss::Utils::shape_to_string(eb->topology()->shape())); + CGCHECKM(cgp_section_write(get_file_pointer(), base, zone, element_type.c_str(), type, 1, size[1], 0, §)); int64_t start = 0; @@ -2432,8 +2434,10 @@ namespace Iocgns { CGCHECKM( cg_goto(get_file_pointer(), base, "Zone_t", zone, "ZoneBC_t", 1, "BC_t", sect, "end")); CGCHECKM(cg_famname_write(name.c_str())); - CGCHECKM(cg_boco_gridlocation_write(get_file_pointer(), base, zone, sect, - CGNS_ENUMV(FaceCenter))); + + int phys_dimension = get_region()->get_property("spatial_dimension").get_int(); + auto location = phys_dimension == 2 ? CGNS_ENUMV(EdgeCenter) : CGNS_ENUMV(FaceCenter); + CGCHECKM(cg_boco_gridlocation_write(get_file_pointer(), base, zone, sect, location)); CGCHECKM(cgp_section_write(get_file_pointer(), base, zone, sb_name.c_str(), type, cg_start, cg_end, 0, §)); diff --git a/packages/seacas/libraries/ioss/src/cgns/Iocgns_Utils.C b/packages/seacas/libraries/ioss/src/cgns/Iocgns_Utils.C index 44b833a13345..a98c78af80db 100644 --- a/packages/seacas/libraries/ioss/src/cgns/Iocgns_Utils.C +++ b/packages/seacas/libraries/ioss/src/cgns/Iocgns_Utils.C @@ -176,8 +176,7 @@ namespace { int min_proc = -1; for (int i = 0; i < static_cast(work.size()); i++) { if (work[i] < min_work && - proc_adam_map.find(std::make_pair(zone->m_adam->m_zone, static_cast(i))) == - proc_adam_map.end()) { + proc_adam_map.find(std::make_pair(zone->m_adam->m_zone, i)) == proc_adam_map.end()) { min_work = work[i]; min_proc = i; if (min_work == 0) { @@ -1580,6 +1579,9 @@ int Iocgns::Utils::find_solution_index(int cgns_file_ptr, int base, int zone, in void Iocgns::Utils::add_sidesets(int cgns_file_ptr, Ioss::DatabaseIO *db) { + static int fake_id = + std::numeric_limits::max(); // Used in case CGNS file does not specify an id. + int base = 1; int num_families = 0; CGCHECKNP(cg_nfamilies(cgns_file_ptr, base, &num_families)); @@ -1623,6 +1625,11 @@ void Iocgns::Utils::add_sidesets(int cgns_file_ptr, Ioss::DatabaseIO *db) } if (id == 0) { id = Ioss::Utils::extract_id(ss_name); + if (id == 0) { + // Assign a fake_id to this sideset. No checking to make + // sure there are no duplicates... + id = fake_id--; + } } if (id != 0) { auto *ss = new Ioss::SideSet(db, ss_name); @@ -2394,6 +2401,12 @@ void Iocgns::Utils::set_line_decomposition(int cgns_file_ptr, const std::string if (verbose && rank == 0) { fmt::print(Ioss::DEBUG(), "Setting line ordinal to {} on {} for surface: {}\n", zone->m_lineOrdinal, zone->m_name, boconame); + if (zone->m_lineOrdinal == 7) { + fmt::print(Ioss::DEBUG(), + "NOTE: Zone {} with work {} will not be decomposed due to line ordinal " + "setting.\n", + zone->m_name, fmt::group_digits(zone->work())); + } } } } @@ -2624,16 +2637,18 @@ int Iocgns::Utils::pre_split(std::vector &zones, d std::vector splits(zones.size()); for (size_t i = 0; i < zones.size(); i++) { - auto zone = zones[i]; - double work = zone->work(); - total_work += work; - if (load_balance <= 1.2) { - splits[i] = int(std::ceil(work / avg_work)); - } - else { - splits[i] = int(std::round(work / avg_work + 0.2)); + auto zone = zones[i]; + if (zone->m_lineOrdinal != 7) { + double work = zone->work(); + total_work += work; + if (load_balance <= 1.2) { + splits[i] = int(std::ceil(work / avg_work)); + } + else { + splits[i] = int(std::round(work / avg_work + 0.2)); + } + splits[i] = splits[i] == 0 ? 1 : splits[i]; } - splits[i] = splits[i] == 0 ? 1 : splits[i]; } int num_splits = std::accumulate(splits.begin(), splits.end(), 0); diff --git a/packages/seacas/libraries/ioss/src/exodus/Ioex_BaseDatabaseIO.C b/packages/seacas/libraries/ioss/src/exodus/Ioex_BaseDatabaseIO.C index 6266e3941e33..27982540fd26 100644 --- a/packages/seacas/libraries/ioss/src/exodus/Ioex_BaseDatabaseIO.C +++ b/packages/seacas/libraries/ioss/src/exodus/Ioex_BaseDatabaseIO.C @@ -95,6 +95,84 @@ namespace { void generate_block_truth_table(Ioex::VariableNameMap &variables, Ioss::IntVector &truth_table, std::vector &blocks, char field_suffix_separator); + void insert_sort_and_unique(const std::vector &src, std::vector &dest); + + class AssemblyTreeFilter + { + public: + AssemblyTreeFilter() = delete; + AssemblyTreeFilter(const AssemblyTreeFilter &) = delete; + + AssemblyTreeFilter(Ioss::Region *region, const Ioss::EntityType filterType, + const std::vector &assemblies) + : m_region(region), m_type(filterType), m_assemblies(assemblies), + m_visitedAssemblies(assemblies.size(), false) + { + } + + void update_list_from_assembly_tree(size_t assemblyIndex, std::vector &list) + { + // Walk the tree without cyclic dependency + if (assemblyIndex < m_assemblies.size()) { + if (m_visitedAssemblies[assemblyIndex] == false) { + m_visitedAssemblies[assemblyIndex] = true; + + const auto &assembly = m_assemblies[assemblyIndex]; + const Ioss::EntityType assemblyType = Ioex::map_exodus_type(assembly.type); + if (m_type == assemblyType) { + for (int j = 0; j < assembly.entity_count; j++) { + Ioss::GroupingEntity *ge = m_region->get_entity(assembly.entity_list[j], m_type); + if (nullptr != ge) { + list.push_back(ge->name()); + } + } + } + + if (Ioss::ASSEMBLY == assemblyType) { + for (int i = 0; i < assembly.entity_count; i++) { + // Find the sub assembly with the same id + int64_t subAssemblyId = assembly.entity_list[i]; + bool found = false; + for (size_t j = 0; j < m_assemblies.size(); j++) { + if (m_assemblies[j].id == subAssemblyId) { + found = true; + update_list_from_assembly_tree(j, list); + break; + } + } + + if(!found) { + std::ostringstream errmsg; + fmt::print(errmsg, + "ERROR: Could not find sub-assembly with id: {} and name: {}", + assembly.id, assembly.name); + IOSS_ERROR(errmsg); + } + } + } + } + } + } + + void update_assembly_filter_list(std::vector &assemblyFilterList) + { + for (size_t i = 0; i < m_assemblies.size(); ++i) { + if (m_visitedAssemblies[i]) { + assemblyFilterList.push_back(m_assemblies[i].name); + } + } + + std::sort(assemblyFilterList.begin(), assemblyFilterList.end(), std::less()); + auto endIter = std::unique(assemblyFilterList.begin(), assemblyFilterList.end()); + assemblyFilterList.resize(endIter - assemblyFilterList.begin()); + } + + private: + Ioss::Region *m_region = nullptr; + Ioss::EntityType m_type = Ioss::INVALID_TYPE; + const std::vector &m_assemblies; + mutable std::vector m_visitedAssemblies; + }; } // namespace namespace Ioex { @@ -563,10 +641,83 @@ namespace Ioex { return step; } + void BaseDatabaseIO::update_block_omissions_from_assemblies() + { + Ioss::SerializeIO serializeIO__(this); + + if (!assemblyOmissions.empty()) { + assert(blockInclusions.empty()); + } + + if (!assemblyInclusions.empty()) { + assert(blockOmissions.empty()); + } + + std::vector exclusions; + std::vector inclusions; + + // Query number of assemblies... + int nassem = ex_inquire_int(get_file_pointer(), EX_INQ_ASSEMBLY); + + if (nassem > 0) { + std::vector assemblies(nassem); + int max_name_length = ex_inquire_int(m_exodusFilePtr, EX_INQ_DB_MAX_USED_NAME_LENGTH); + for (auto &assembly : assemblies) { + assembly.name = new char[max_name_length + 1]; + } + + int ierr = ex_get_assemblies(get_file_pointer(), assemblies.data()); + if (ierr < 0) { + Ioex::exodus_error(get_file_pointer(), __LINE__, __func__, __FILE__); + } + + // Now allocate space for member list and get assemblies again... + for (auto &assembly : assemblies) { + assembly.entity_list = new int64_t[assembly.entity_count]; + } + + ierr = ex_get_assemblies(get_file_pointer(), assemblies.data()); + if (ierr < 0) { + Ioex::exodus_error(get_file_pointer(), __LINE__, __func__, __FILE__); + } + + AssemblyTreeFilter inclusionFilter(get_region(), Ioss::ELEMENTBLOCK, assemblies); + AssemblyTreeFilter exclusionFilter(get_region(), Ioss::ELEMENTBLOCK, assemblies); + + for (size_t i = 0; i < assemblies.size(); ++i) { + const auto &assembly = assemblies[i]; + + bool omitAssembly = + std::binary_search(assemblyOmissions.begin(), assemblyOmissions.end(), assembly.name); + bool includeAssembly = + std::binary_search(assemblyInclusions.begin(), assemblyInclusions.end(), assembly.name); + + if (omitAssembly) { + exclusionFilter.update_list_from_assembly_tree(i, exclusions); + } + + if (includeAssembly) { + inclusionFilter.update_list_from_assembly_tree(i, inclusions); + } + } + + exclusionFilter.update_assembly_filter_list(assemblyOmissions); + inclusionFilter.update_assembly_filter_list(assemblyInclusions); + + for (auto &assembly : assemblies) { + delete[] assembly.entity_list; + delete[] assembly.name; + } + + insert_sort_and_unique(exclusions, blockOmissions); + insert_sort_and_unique(inclusions, blockInclusions); + } + } + void BaseDatabaseIO::get_assemblies() { Ioss::SerializeIO serializeIO__(this); - // Query number of coordinate frames... + // Query number of assemblies... int nassem = ex_inquire_int(get_file_pointer(), EX_INQ_ASSEMBLY); if (nassem > 0) { @@ -601,22 +752,26 @@ namespace Ioex { for (const auto &assembly : assemblies) { Ioss::Assembly *assem = get_region()->get_assembly(assembly.name); assert(assem != nullptr); - auto type = Ioex::map_exodus_type(assembly.type); + auto type = Ioex::map_exodus_type(assembly.type); + size_t num_added_entities = 0; + for (int j = 0; j < assembly.entity_count; j++) { auto *ge = get_region()->get_entity(assembly.entity_list[j], type); - if (ge != nullptr) { - assem->add(ge); - } - else { + if (ge == nullptr) { std::ostringstream errmsg; fmt::print(errmsg, - "Error: Failed to find entity of type {} with id {} for Assembly {}.\n", + "Error: Failed to find entity of type {} with id {} for assembly {}.\n", type, assembly.entity_list[j], assem->name()); IOSS_ERROR(errmsg); } + + if (!Ioss::Utils::block_is_omitted(ge)) { + assem->add(ge); + num_added_entities++; + } } - SMART_ASSERT(assem->member_count() == (size_t)assembly.entity_count) - (assem->member_count())(assembly.entity_count); + SMART_ASSERT(assem->member_count() == num_added_entities) + (assem->member_count())(num_added_entities); add_mesh_reduction_fields(EX_ASSEMBLY, assembly.id, assem); // Check for additional variables. @@ -637,13 +792,40 @@ namespace Ioex { delete[] assembly.entity_list; delete[] assembly.name; } + + assert(assemblyOmissions.empty() || assemblyInclusions.empty()); // Only one can be non-empty + + // Handle all assembly omissions or inclusions... + if (!assemblyOmissions.empty()) { + for (const auto &name : assemblyOmissions) { + auto assembly = get_region()->get_assembly(name); + if (assembly != nullptr) { + assembly->property_add(Ioss::Property(std::string("omitted"), 1)); + } + } + } + + if (!assemblyInclusions.empty()) { + const auto &assemblies = get_region()->get_assemblies(); + for (auto &assembly : assemblies) { + assembly->property_add(Ioss::Property(std::string("omitted"), 1)); + } + + // Now, erase the property on any assemblies in the inclusion list... + for (const auto &name : assemblyInclusions) { + auto assembly = get_region()->get_assembly(name); + if (assembly != nullptr) { + assembly->property_erase("omitted"); + } + } + } } } void BaseDatabaseIO::get_blobs() { Ioss::SerializeIO serializeIO__(this); - // Query number of coordinate frames... + // Query number of blobs... int nblob = ex_inquire_int(get_file_pointer(), EX_INQ_BLOB); if (nblob > 0) { @@ -2848,4 +3030,12 @@ namespace { } #endif } + + void insert_sort_and_unique(const std::vector &src, std::vector &dest) + { + dest.insert(dest.end(), src.begin(), src.end()); + std::sort(dest.begin(), dest.end(), std::less()); + auto endIter = std::unique(dest.begin(), dest.end()); + dest.resize(endIter - dest.begin()); + } } // namespace diff --git a/packages/seacas/libraries/ioss/src/exodus/Ioex_BaseDatabaseIO.h b/packages/seacas/libraries/ioss/src/exodus/Ioex_BaseDatabaseIO.h index c085fef524f0..3977f748641b 100644 --- a/packages/seacas/libraries/ioss/src/exodus/Ioex_BaseDatabaseIO.h +++ b/packages/seacas/libraries/ioss/src/exodus/Ioex_BaseDatabaseIO.h @@ -230,6 +230,8 @@ namespace Ioex { void get_assemblies(); void get_blobs(); + void update_block_omissions_from_assemblies(); + void add_attribute_fields(ex_entity_type entity_type, Ioss::GroupingEntity *block, int attribute_count, const std::string &type); diff --git a/packages/seacas/libraries/ioss/src/exodus/Ioex_DatabaseIO.C b/packages/seacas/libraries/ioss/src/exodus/Ioex_DatabaseIO.C index f452aa9a39e0..f6bdd7964536 100644 --- a/packages/seacas/libraries/ioss/src/exodus/Ioex_DatabaseIO.C +++ b/packages/seacas/libraries/ioss/src/exodus/Ioex_DatabaseIO.C @@ -666,23 +666,17 @@ namespace Ioex { // Since we can't access the Region's stateCount directly, we just add // all of the steps and assume the Region is dealing with them directly... tsteps.resize(timestep_count); + int error = ex_get_all_times(get_file_pointer(), tsteps.data()); if (error < 0) { Ioex::exodus_error(get_file_pointer(), __LINE__, __func__, __FILE__); } - int max_step = timestep_count; - if (properties.exists("APPEND_OUTPUT_AFTER_STEP")) { - max_step = properties.get("APPEND_OUTPUT_AFTER_STEP").get_int(); - } - if (max_step > timestep_count) { - max_step = timestep_count; - } + int max_step = properties.get_optional("APPEND_OUTPUT_AFTER_STEP", timestep_count); + max_step = std::min(max_step, timestep_count); - double max_time = std::numeric_limits::max(); - if (properties.exists("APPEND_OUTPUT_AFTER_TIME")) { - max_time = properties.get("APPEND_OUTPUT_AFTER_TIME").get_real(); - } + double max_time = + properties.get_optional("APPEND_OUTPUT_AFTER_TIME", std::numeric_limits::max()); Ioss::Region *this_region = get_region(); for (int i = 0; i < max_step; i++) { @@ -703,9 +697,26 @@ namespace Ioex { // For an exodus file, timesteps are global and are stored in the region. // Read the timesteps and add to the region tsteps.resize(timestep_count); - int error = ex_get_all_times(get_file_pointer(), tsteps.data()); - if (error < 0) { - Ioex::exodus_error(get_file_pointer(), __LINE__, __func__, __FILE__); + + // The `EXODUS_CALL_GET_ALL_TIMES=NO` is typically only used in + // isSerialParallel mode and the client is responsible for + // making sure that the step times are handled correctly. All + // databases will know about the number of timesteps, but if + // this is skipped, then the times will all be zero. Use case + // is that in isSerialParallel, each call to + // `ex_get_all_times` for all files is performed sequentially, + // so if you have hundreds to thousands of files, the time for + // the call is additive and since timesteps are record + // variables in netCDF, accessing the data for all timesteps + // involves lseeks throughout the file. + bool call_ex_get_all_times = true; + Ioss::Utils::check_set_bool_property(properties, "EXODUS_CALL_GET_ALL_TIMES", + call_ex_get_all_times); + if (call_ex_get_all_times) { + int error = ex_get_all_times(get_file_pointer(), tsteps.data()); + if (error < 0) { + Ioex::exodus_error(get_file_pointer(), __LINE__, __func__, __FILE__); + } } // See if the "last_written_time" attribute exists and if it @@ -731,21 +742,12 @@ namespace Ioex { // One use case is that job is restarting at a time prior to what has been // written to the results file, so want to start appending after // restart time instead of at end time on database. - int max_step = timestep_count; - if (properties.exists("APPEND_OUTPUT_AFTER_STEP")) { - max_step = properties.get("APPEND_OUTPUT_AFTER_STEP").get_int(); - } - if (max_step > timestep_count) { - max_step = timestep_count; - } + int max_step = properties.get_optional("APPEND_OUTPUT_AFTER_STEP", timestep_count); + max_step = std::min(max_step, timestep_count); - double max_time = std::numeric_limits::max(); - if (properties.exists("APPEND_OUTPUT_AFTER_TIME")) { - max_time = properties.get("APPEND_OUTPUT_AFTER_TIME").get_real(); - } - if (last_time > max_time) { - last_time = max_time; - } + double max_time = + properties.get_optional("APPEND_OUTPUT_AFTER_TIME", std::numeric_limits::max()); + last_time = std::min(last_time, max_time); Ioss::Region *this_region = get_region(); for (int i = 0; i < max_step; i++) { @@ -1292,6 +1294,10 @@ namespace Ioex { m_groupCount[entity_type] = used_blocks; if (entity_type == EX_ELEM_BLOCK) { + if (!assemblyOmissions.empty() || !assemblyInclusions.empty()) { + update_block_omissions_from_assemblies(); + } + assert(blockOmissions.empty() || blockInclusions.empty()); // Only one can be non-empty // Handle all block omissions or inclusions... @@ -1371,6 +1377,36 @@ namespace Ioex { nodeConnectivityStatusCalculated = true; } + namespace { + void get_element_sides_lists(int exoid, int64_t id, int int_byte_size, int64_t number_sides, + Ioss::Int64Vector &element, Ioss::Int64Vector &sides) + { + // Check whether we already populated the element/sides vectors. + if (element.empty() && sides.empty() && number_sides > 0) { + element.resize(number_sides); + sides.resize(number_sides); + // Easier below here if the element and sides are a known 64-bit size... + // Kluge here to do that... + if (int_byte_size == 4) { + Ioss::IntVector e32(number_sides); + Ioss::IntVector s32(number_sides); + int ierr = ex_get_set(exoid, EX_SIDE_SET, id, e32.data(), s32.data()); + if (ierr < 0) { + Ioex::exodus_error(exoid, __LINE__, __func__, __FILE__); + } + std::copy(e32.begin(), e32.end(), element.begin()); + std::copy(s32.begin(), s32.end(), sides.begin()); + } + else { + int ierr = ex_get_set(exoid, EX_SIDE_SET, id, element.data(), sides.data()); + if (ierr < 0) { + Ioex::exodus_error(exoid, __LINE__, __func__, __FILE__); + } + } + } + } + } // namespace + void DatabaseIO::get_sidesets() { // This function creates all sidesets (surfaces) for a @@ -1523,30 +1559,12 @@ namespace Ioex { int64_t number_sides = set_param[0].num_entry; - Ioss::Int64Vector element(number_sides); - Ioss::Int64Vector sides(number_sides); - - // Easier below here if the element and sides are a known 64-bit size... - // Kluge here to do that... - if (int_byte_size_api() == 4) { - Ioss::IntVector e32(number_sides); - Ioss::IntVector s32(number_sides); - int ierr = ex_get_set(get_file_pointer(), EX_SIDE_SET, id, e32.data(), s32.data()); - if (ierr < 0) { - Ioex::exodus_error(get_file_pointer(), __LINE__, __func__, __FILE__); - } - std::copy(e32.begin(), e32.end(), element.begin()); - std::copy(s32.begin(), s32.end(), sides.begin()); - } - else { - int ierr = - ex_get_set(get_file_pointer(), EX_SIDE_SET, id, element.data(), sides.data()); - if (ierr < 0) { - Ioex::exodus_error(get_file_pointer(), __LINE__, __func__, __FILE__); - } - } + Ioss::Int64Vector element; + Ioss::Int64Vector sides; if (!blockOmissions.empty() || !blockInclusions.empty()) { + get_element_sides_lists(get_file_pointer(), id, int_byte_size_api(), number_sides, + element, sides); Ioex::filter_element_list(get_region(), element, sides, true); number_sides = element.size(); SMART_ASSERT(element.size() == sides.size())(element.size())(sides.size()); @@ -1601,6 +1619,8 @@ namespace Ioex { side_map[std::make_pair(elem.first->name(), elem.second)] = 0; } + get_element_sides_lists(get_file_pointer(), id, int_byte_size_api(), number_sides, + element, sides); Ioex::separate_surface_element_sides(element, sides, get_region(), topo_map, side_map, split_type, side_set_name); } @@ -1641,6 +1661,8 @@ namespace Ioex { } } } + get_element_sides_lists(get_file_pointer(), id, int_byte_size_api(), number_sides, + element, sides); Ioex::separate_surface_element_sides(element, sides, get_region(), topo_map, side_map, split_type, side_set_name); } diff --git a/packages/seacas/libraries/ioss/src/exodus/Ioex_DatabaseIO.h b/packages/seacas/libraries/ioss/src/exodus/Ioex_DatabaseIO.h index 951216345a89..335ef4cc698f 100644 --- a/packages/seacas/libraries/ioss/src/exodus/Ioex_DatabaseIO.h +++ b/packages/seacas/libraries/ioss/src/exodus/Ioex_DatabaseIO.h @@ -228,7 +228,7 @@ namespace Ioex { int64_t put_side_field(const Ioss::SideBlock *sd_blk, const Ioss::Field &field, void *data, size_t data_size) const; - mutable bool isSerialParallel{ - false}; //!< true if application code is controlling the processor id. + //!< true if application code is controlling the processor id. + mutable bool isSerialParallel{false}; }; } // namespace Ioex diff --git a/packages/seacas/libraries/ioss/src/exodus/Ioex_DecompositionData.C b/packages/seacas/libraries/ioss/src/exodus/Ioex_DecompositionData.C index 5e7979a02985..eba1c20d845e 100644 --- a/packages/seacas/libraries/ioss/src/exodus/Ioex_DecompositionData.C +++ b/packages/seacas/libraries/ioss/src/exodus/Ioex_DecompositionData.C @@ -513,7 +513,7 @@ namespace Ioex { // * Broadcast data to other processors // * Each processor extracts the entities it manages. m_decomposition.show_progress("\tBroadcast entitylist begin"); - Ioss::ParallelUtils pu(comm_); + Ioss::ParallelUtils pu(comm_); pu.broadcast(entitylist, root); m_decomposition.show_progress("\tBroadcast entitylist end"); @@ -736,9 +736,9 @@ namespace Ioex { pu.broadcast(df_valcon, root); m_decomposition.show_progress("\tBroadcast df_valcon end"); for (size_t i = 0; i < set_count; i++) { - side_sets[i].distributionFactorValue = df_valcon[3 * i + 0]; - side_sets[i].distributionFactorConstant = (df_valcon[3 * i + 1] == 1.0); - side_sets[i].distributionFactorValsPerEntity = static_cast(df_valcon[3 * i + 2]); + side_sets[i].distributionFactorValue = df_valcon[3 * i + 0]; + side_sets[i].distributionFactorConstant = (df_valcon[3 * i + 1] == 1.0); + side_sets[i].distributionFactorValsPerEntity = static_cast(df_valcon[3 * i + 2]); } } @@ -770,27 +770,27 @@ namespace Ioex { } { - // Broadcast this data to all other processors... - m_decomposition.show_progress("\tBroadcast nodes_per_face begin"); - Ioss::ParallelUtils pu(comm_); - pu.broadcast(nodes_per_face, root); - m_decomposition.show_progress("\tBroadcast nodes_per_face end"); - - // Each processor now has a list of the number of nodes per - // face for all sidesets that have a variable number. This can - // be used to determine the df field size on the ioss_decomp. - size_t offset = 0; - for (size_t i = 0; i < set_count; i++) { - if (side_sets[i].distributionFactorValsPerEntity < 0) { - int *npf = &nodes_per_face[offset]; - offset += side_sets[i].file_count(); - size_t my_count = 0; - for (size_t j = 0; j < side_sets[i].ioss_count(); j++) { - my_count += npf[side_sets[i].entitylist_map[j]]; - } - side_sets[i].distributionFactorCount = my_count; - } - } + // Broadcast this data to all other processors... + m_decomposition.show_progress("\tBroadcast nodes_per_face begin"); + Ioss::ParallelUtils pu(comm_); + pu.broadcast(nodes_per_face, root); + m_decomposition.show_progress("\tBroadcast nodes_per_face end"); + + // Each processor now has a list of the number of nodes per + // face for all sidesets that have a variable number. This can + // be used to determine the df field size on the ioss_decomp. + size_t offset = 0; + for (size_t i = 0; i < set_count; i++) { + if (side_sets[i].distributionFactorValsPerEntity < 0) { + int *npf = &nodes_per_face[offset]; + offset += side_sets[i].file_count(); + size_t my_count = 0; + for (size_t j = 0; j < side_sets[i].ioss_count(); j++) { + my_count += npf[side_sets[i].entitylist_map[j]]; + } + side_sets[i].distributionFactorCount = my_count; + } + } } } ex_set_parallel(filePtr, old_par_setting); diff --git a/packages/seacas/libraries/ioss/src/exodus/Ioex_ParallelDatabaseIO.C b/packages/seacas/libraries/ioss/src/exodus/Ioex_ParallelDatabaseIO.C index 9b700953712b..1d710fa86acd 100644 --- a/packages/seacas/libraries/ioss/src/exodus/Ioex_ParallelDatabaseIO.C +++ b/packages/seacas/libraries/ioss/src/exodus/Ioex_ParallelDatabaseIO.C @@ -884,21 +884,12 @@ namespace Ioex { // One use case is that job is restarting at a time prior to what has been // written to the results file, so want to start appending after // restart time instead of at end time on database. - int max_step = timestep_count; - if (properties.exists("APPEND_OUTPUT_AFTER_STEP")) { - max_step = properties.get("APPEND_OUTPUT_AFTER_STEP").get_int(); - } - if (max_step > timestep_count) { - max_step = timestep_count; - } + int max_step = properties.get_optional("APPEND_OUTPUT_AFTER_STEP", timestep_count); + max_step = std::min(max_step, timestep_count); - double max_time = std::numeric_limits::max(); - if (properties.exists("APPEND_OUTPUT_AFTER_TIME")) { - max_time = properties.get("APPEND_OUTPUT_AFTER_TIME").get_real(); - } - if (last_time > max_time) { - last_time = max_time; - } + double max_time = + properties.get_optional("APPEND_OUTPUT_AFTER_TIME", std::numeric_limits::max()); + last_time = std::min(last_time, max_time); Ioss::Region *this_region = get_region(); for (int i = 0; i < max_step; i++) { @@ -1219,6 +1210,11 @@ namespace Ioex { Ioex::add_map_fields(get_file_pointer(), dynamic_cast(io_block), decomp->el_blocks[iblk].ioss_count(), maximumNameLength); } + + if (!assemblyOmissions.empty() || !assemblyInclusions.empty()) { + update_block_omissions_from_assemblies(); + } + assert(blockOmissions.empty() || blockInclusions.empty()); // Only one can be non-empty // Handle all block omissions or inclusions... @@ -1298,6 +1294,42 @@ namespace Ioex { nodeConnectivityStatusCalculated = true; } + namespace { + void get_element_sides_lists(const std::unique_ptr &decomp, int exoid, + int64_t id, int int_byte_size, int64_t number_sides, + Ioss::Int64Vector &element, Ioss::Int64Vector &sides) + { + // Check whether we already populated the element/sides vectors. + if (element.empty() && sides.empty() && number_sides > 0) { + element.resize(number_sides); + sides.resize(number_sides); + + // Easier below here if the element and sides are a known 64-bit size... + // Kluge here to do that... + if (int_byte_size == 4) { + Ioss::Field side_field("sides", Ioss::Field::INTEGER, IOSS_SCALAR(), Ioss::Field::MESH, + number_sides); + Ioss::Field elem_field("ids_raw", Ioss::Field::INTEGER, IOSS_SCALAR(), Ioss::Field::MESH, + number_sides); + + Ioss::IntVector e32(number_sides); + decomp->get_set_mesh_var(exoid, EX_SIDE_SET, id, elem_field, e32.data()); + std::copy(e32.begin(), e32.end(), element.begin()); + decomp->get_set_mesh_var(exoid, EX_SIDE_SET, id, side_field, e32.data()); + std::copy(e32.begin(), e32.end(), sides.begin()); + } + else { + Ioss::Field side_field("sides", Ioss::Field::INT64, IOSS_SCALAR(), Ioss::Field::MESH, + number_sides); + Ioss::Field elem_field("ids_raw", Ioss::Field::INT64, IOSS_SCALAR(), Ioss::Field::MESH, + number_sides); + decomp->get_set_mesh_var(exoid, EX_SIDE_SET, id, elem_field, element.data()); + decomp->get_set_mesh_var(exoid, EX_SIDE_SET, id, side_field, sides.data()); + } + } + } + } // namespace + void ParallelDatabaseIO::get_sidesets() { // This function creates all sidesets (surfaces) for a @@ -1421,34 +1453,12 @@ namespace Ioex { int64_t number_sides = decomp->side_sets[iss].ioss_count(); // FIXME: Support- number_distribution_factors = decomp->side_sets[iss].df_count(); - Ioss::Int64Vector element(number_sides); - Ioss::Int64Vector sides(number_sides); - - // Easier below here if the element and sides are a known 64-bit size... - // Kluge here to do that... - if (int_byte_size_api() == 4) { - Ioss::Field side_field("sides", Ioss::Field::INTEGER, IOSS_SCALAR(), Ioss::Field::MESH, - number_sides); - Ioss::Field elem_field("ids_raw", Ioss::Field::INTEGER, IOSS_SCALAR(), - Ioss::Field::MESH, number_sides); - - Ioss::IntVector e32(number_sides); - decomp->get_set_mesh_var(get_file_pointer(), EX_SIDE_SET, id, elem_field, e32.data()); - std::copy(e32.begin(), e32.end(), element.begin()); - decomp->get_set_mesh_var(get_file_pointer(), EX_SIDE_SET, id, side_field, e32.data()); - std::copy(e32.begin(), e32.end(), sides.begin()); - } - else { - Ioss::Field side_field("sides", Ioss::Field::INT64, IOSS_SCALAR(), Ioss::Field::MESH, - number_sides); - Ioss::Field elem_field("ids_raw", Ioss::Field::INT64, IOSS_SCALAR(), Ioss::Field::MESH, - number_sides); - decomp->get_set_mesh_var(get_file_pointer(), EX_SIDE_SET, id, elem_field, - element.data()); - decomp->get_set_mesh_var(get_file_pointer(), EX_SIDE_SET, id, side_field, sides.data()); - } + Ioss::Int64Vector element; + Ioss::Int64Vector sides; if (!blockOmissions.empty() || !blockInclusions.empty()) { + get_element_sides_lists(decomp, get_file_pointer(), id, int_byte_size_api(), + number_sides, element, sides); Ioex::filter_element_list(get_region(), element, sides, true); number_sides = element.size(); assert(element.size() == sides.size()); @@ -1503,6 +1513,8 @@ namespace Ioex { side_map[std::make_pair(side_topo.first->name(), side_topo.second)] = 0; } + get_element_sides_lists(decomp, get_file_pointer(), id, int_byte_size_api(), + number_sides, element, sides); Ioex::separate_surface_element_sides(element, sides, get_region(), topo_map, side_map, split_type, side_set_name); } @@ -1543,6 +1555,8 @@ namespace Ioex { } } } + get_element_sides_lists(decomp, get_file_pointer(), id, int_byte_size_api(), + number_sides, element, sides); Ioex::separate_surface_element_sides(element, sides, get_region(), topo_map, side_map, split_type, side_set_name); } @@ -2979,9 +2993,9 @@ int64_t ParallelDatabaseIO::read_ss_transient_field(const Ioss::Field &field, in void *variables, Ioss::IntVector &is_valid_side) const { - size_t num_valid_sides = 0; - size_t my_side_count = is_valid_side.size(); - std::vector temp(my_side_count); + size_t num_valid_sides = 0; + size_t my_side_count = is_valid_side.size(); + std::vector temp(my_side_count); size_t step = get_current_state(); @@ -4078,7 +4092,7 @@ void ParallelDatabaseIO::write_nodal_transient_field(ex_entity_type /* type */, // exodus fields. These fields were already defined in // "write_results_metadata". - std::vector temp(count); + std::vector temp(count); int step = get_current_state(); step = get_database_step(step); @@ -4161,8 +4175,8 @@ void ParallelDatabaseIO::write_entity_transient_field(ex_entity_type type, const const Ioss::GroupingEntity *ge, int64_t count, void *variables) const { - static Ioss::Map non_element_map; // Used as an empty map for ge->type() != element block. - std::vector temp(count); + static Ioss::Map non_element_map; // Used as an empty map for ge->type() != element block. + std::vector temp(count); int step = get_current_state(); step = get_database_step(step); diff --git a/packages/seacas/libraries/ioss/src/main/CMakeLists.txt b/packages/seacas/libraries/ioss/src/main/CMakeLists.txt index 73da641ffbdb..6210659f374a 100644 --- a/packages/seacas/libraries/ioss/src/main/CMakeLists.txt +++ b/packages/seacas/libraries/ioss/src/main/CMakeLists.txt @@ -522,6 +522,15 @@ TRIBITS_ADD_ADVANCED_TEST(structured_cgns_embedded_nodeblock_fields COMM mpi serial ) +TRIBITS_ADD_ADVANCED_TEST(unstructured_2d_cgns + TEST_0 EXEC io_shell ARGS ${CMAKE_CURRENT_SOURCE_DIR}/test/circle-square-2d.cgns 2d-out.cgns + NUM_MPI_PROCS 1-4 + NOEXEPREFIX NOEXESUFFIX + TEST_1 CMND ${CGNS_CGNSDIFF_BINARY} ARGS -d ${CMAKE_CURRENT_SOURCE_DIR}/test/circle-square-2d.cgns 2d-out.cgns + NUM_MPI_PROCS 1 + COMM mpi serial + ) + TRIBITS_ADD_ADVANCED_TEST(structured_cgns_roundtrip_fpp_vertex_cell_fields TEST_0 EXEC io_shell ARGS --compose external ${CMAKE_CURRENT_SOURCE_DIR}/test/sparc_fields.cgns sparc_fields.cgns NUM_MPI_PROCS 1-4 diff --git a/packages/seacas/libraries/ioss/src/main/cgns_decomp.C b/packages/seacas/libraries/ioss/src/main/cgns_decomp.C index 8c0b38f37353..2f836b344d67 100644 --- a/packages/seacas/libraries/ioss/src/main/cgns_decomp.C +++ b/packages/seacas/libraries/ioss/src/main/cgns_decomp.C @@ -225,8 +225,6 @@ namespace { std::string codename; std::string version = "0.97"; - int term_width(); - void cleanup(std::vector &zones) { for (auto &zone : zones) { @@ -428,7 +426,7 @@ namespace { int pw = Ioss::Utils::number_width(proc_count, false); // Two tabs at beginning ~16 spaces. Each entry is "[pw->pw] " which is 6+2pw - int npl = (term_width() - 16) / (6 + 2 * pw); + int npl = (Ioss::Utils::term_width() - 16) / (6 + 2 * pw); npl = npl < 1 ? 1 : npl; int line = 0; @@ -758,6 +756,13 @@ int main(int argc, char *argv[]) if (in_type == "cgns") { Iocgns::Utils::set_line_decomposition(dbi->get_file_pointer(), interFace.line_decomposition, zones, 0, interFace.verbose); + for (const auto &z : zones) { + if (z->m_lineOrdinal == 7) { + fmt::print( + "WARNING: Zone {} with work {} will not be decomposed due to line ordinal setting.\n", + z->m_name, fmt::group_digits(z->work())); + } + } } region.output_summary(std::cout, false); @@ -795,29 +800,3 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } } - -#if defined(_MSC_VER) -#include -#define isatty _isatty -#endif - -namespace { - int term_width() - { - int cols = 100; - if (isatty(fileno(stdout))) { -#ifdef TIOCGSIZE - struct ttysize ts - { - }; - ioctl(STDIN_FILENO, TIOCGSIZE, &ts); - cols = ts.ts_cols; -#elif defined(TIOCGWINSZ) - struct winsize ts; - ioctl(STDIN_FILENO, TIOCGWINSZ, &ts); - cols = ts.ws_col; -#endif /* TIOCGSIZE */ - } - return cols; - } -} // namespace diff --git a/packages/seacas/libraries/ioss/src/main/info_interface.C b/packages/seacas/libraries/ioss/src/main/info_interface.C index b9dfd30c8d6f..6783e8553e1a 100644 --- a/packages/seacas/libraries/ioss/src/main/info_interface.C +++ b/packages/seacas/libraries/ioss/src/main/info_interface.C @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -82,7 +82,7 @@ void Info::Interface::enroll_options() options_.enroll("surface_split_scheme", Ioss::GetLongOption::MandatoryValue, "Method used to split sidesets into homogeneous blocks\n" "\t\tOptions are: TOPOLOGY, BLOCK, NO_SPLIT", - "TOPOLOGY", nullptr, true); + nullptr, nullptr, true); #if defined(SEACAS_HAVE_MPI) #if !defined(NO_ZOLTAN_SUPPORT) @@ -269,33 +269,7 @@ bool Info::Interface::parse_options(int argc, char **argv) #endif if (options_.retrieve("copyright") != nullptr) { - fmt::print(stderr, "\n" - "Copyright(C) 1999-2021 National Technology & Engineering Solutions\n" - "of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with\n" - "NTESS, the U.S. Government retains certain rights in this software.\n\n" - "Redistribution and use in source and binary forms, with or without\n" - "modification, are permitted provided that the following conditions are\n" - "met:\n\n " - " * Redistributions of source code must retain the above copyright\n" - " notice, this list of conditions and the following disclaimer.\n\n" - " * Redistributions in binary form must reproduce the above\n" - " copyright notice, this list of conditions and the following\n" - " disclaimer in the documentation and/or other materials provided\n" - " with the distribution.\n\n" - " * Neither the name of NTESS nor the names of its\n" - " contributors may be used to endorse or promote products derived\n" - " from this software without specific prior written permission.\n\n" - "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" - "\" AS IS \" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" - "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" - "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" - "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" - "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" - "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" - "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" - "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" - "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" - "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"); + Ioss::Utils::copyright(std::cerr, "1999-2022"); exit(EXIT_SUCCESS); } diff --git a/packages/seacas/libraries/ioss/src/main/info_interface.h b/packages/seacas/libraries/ioss/src/main/info_interface.h index 194dd0409fb0..3f6eb1c1af20 100644 --- a/packages/seacas/libraries/ioss/src/main/info_interface.h +++ b/packages/seacas/libraries/ioss/src/main/info_interface.h @@ -64,6 +64,6 @@ namespace Info { char fieldSuffixSeparator_{'_'}; - int surfaceSplitScheme_{1}; + int surfaceSplitScheme_{-1}; }; } // namespace Info diff --git a/packages/seacas/libraries/ioss/src/main/io_info.C b/packages/seacas/libraries/ioss/src/main/io_info.C index 28f78197b100..a57313f0e785 100644 --- a/packages/seacas/libraries/ioss/src/main/io_info.C +++ b/packages/seacas/libraries/ioss/src/main/io_info.C @@ -7,6 +7,7 @@ #include "io_info.h" #include #include +#define FMT_DEPRECATED_OSTREAM #include #include #if defined(SEACAS_HAVE_CGNS) @@ -549,7 +550,9 @@ namespace Ioss { dbi->set_use_generic_canonical_name(true); } - dbi->set_surface_split_type(Ioss::int_to_surface_split(interFace.surface_split_scheme())); + if (interFace.surface_split_scheme() != Ioss::SPLIT_INVALID) { + dbi->set_surface_split_type(Ioss::int_to_surface_split(interFace.surface_split_scheme())); + } dbi->set_field_separator(interFace.field_suffix_separator()); dbi->set_field_recognition(!interFace.disable_field_recognition()); if (interFace.ints_64_bit()) { diff --git a/packages/seacas/libraries/ioss/src/main/io_modify.C b/packages/seacas/libraries/ioss/src/main/io_modify.C index 02de0852472f..3a5bc64c687b 100644 --- a/packages/seacas/libraries/ioss/src/main/io_modify.C +++ b/packages/seacas/libraries/ioss/src/main/io_modify.C @@ -69,7 +69,7 @@ #include #endif -#if defined(_MSC_VER) +#if defined(__IOSS_WINDOWS__) #include #define isatty _isatty #endif @@ -200,13 +200,13 @@ namespace { fmt::print(stderr, fg(fmt::color::yellow), "WARNING: Unrecognized entity type '{}'.\n", tokens[1]); } - glob::glob glob(tokens[3]); - Ioss::NameList names = get_name_list(region, entity_type); + Ioss::glob::glob glob(tokens[3]); + Ioss::NameList names = get_name_list(region, entity_type); // Check for match against all names in list... bool matched = false; for (const auto &name : names) { - if (glob::glob_match(name, glob)) { + if (Ioss::glob::glob_match(name, glob)) { const auto *entity = region.get_entity(name, entity_type); const T *ge = dynamic_cast(entity); if (ge != nullptr) { @@ -337,7 +337,7 @@ int main(int argc, char *argv[]) } // NOTE: getline_int returns the trailing '\n' - auto tokens = Ioss::tokenize(std::string(input), " ,\n"); + auto tokens = Ioss::tokenize(input, " ,\n"); if (tokens.empty()) { continue; } @@ -1319,11 +1319,11 @@ namespace { // Get list of all names for this entity type... Ioss::NameList names = get_name_list(region, type); - glob::glob glob(tokens[5]); + Ioss::glob::glob glob(tokens[5]); // Check for match against all names in list... for (const auto &name : names) { - if (glob::glob_match(name, glob)) { + if (Ioss::glob::glob_match(name, glob)) { const auto *entity = region.get_entity(name, type); if (entity != nullptr) { if (assem->add(entity)) { diff --git a/packages/seacas/libraries/ioss/src/main/io_shell.C b/packages/seacas/libraries/ioss/src/main/io_shell.C index e8f2fd928324..1b25dc444f73 100644 --- a/packages/seacas/libraries/ioss/src/main/io_shell.C +++ b/packages/seacas/libraries/ioss/src/main/io_shell.C @@ -204,7 +204,7 @@ namespace { // by element block, then output is much easier. dbi->set_surface_split_type(Ioss::SPLIT_BY_ELEMENT_BLOCK); } - else { + else if (interFace.surface_split_type != Ioss::SPLIT_INVALID) { dbi->set_surface_split_type(Ioss::int_to_surface_split(interFace.surface_split_type)); } dbi->set_field_separator(interFace.fieldSuffixSeparator); diff --git a/packages/seacas/libraries/ioss/src/main/modify_interface.C b/packages/seacas/libraries/ioss/src/main/modify_interface.C index 48c4f2782639..5ad46e87b1eb 100644 --- a/packages/seacas/libraries/ioss/src/main/modify_interface.C +++ b/packages/seacas/libraries/ioss/src/main/modify_interface.C @@ -94,33 +94,7 @@ bool Modify::Interface::parse_options(int argc, char **argv) filetype_ = options_.get_option_value("db_type", filetype_); if (options_.retrieve("copyright") != nullptr) { - fmt::print(stderr, "\n" - "Copyright(C) 2020-2021 National Technology & Engineering Solutions\n" - "of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with\n" - "NTESS, the U.S. Government retains certain rights in this software.\n\n" - "Redistribution and use in source and binary forms, with or without\n" - "modification, are permitted provided that the following conditions are\n" - "met:\n\n " - " * Redistributions of source code must retain the above copyright\n" - " notice, this list of conditions and the following disclaimer.\n\n" - " * Redistributions in binary form must reproduce the above\n" - " copyright notice, this list of conditions and the following\n" - " disclaimer in the documentation and/or other materials provided\n" - " with the distribution.\n\n" - " * Neither the name of NTESS nor the names of its\n" - " contributors may be used to endorse or promote products derived\n" - " from this software without specific prior written permission.\n\n" - "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" - "\" AS IS \" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" - "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" - "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" - "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" - "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" - "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" - "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" - "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" - "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" - "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"); + Ioss::Utils::copyright(std::cerr, "2020-2022"); exit(EXIT_SUCCESS); } diff --git a/packages/seacas/libraries/ioss/src/main/shell_interface.C b/packages/seacas/libraries/ioss/src/main/shell_interface.C index 4ea3bb8213b5..81d230d8690f 100644 --- a/packages/seacas/libraries/ioss/src/main/shell_interface.C +++ b/packages/seacas/libraries/ioss/src/main/shell_interface.C @@ -1,5 +1,5 @@ /* - * Copyright(C) 1999-2021 National Technology & Engineering Solutions + * Copyright(C) 1999-2022 National Technology & Engineering Solutions * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with * NTESS, the U.S. Government retains certain rights in this software. * @@ -255,7 +255,7 @@ void IOShell::Interface::enroll_options() options_.enroll("surface_split_scheme", Ioss::GetLongOption::MandatoryValue, "Method used to split sidesets into homogeneous blocks\n" "\t\tOptions are: TOPOLOGY, BLOCK, NO_SPLIT", - "TOPOLOGY"); + nullptr); options_.enroll("native_variable_names", Ioss::GetLongOption::NoValue, "Do not lowercase variable names and replace spaces with underscores.\n" @@ -598,34 +598,7 @@ bool IOShell::Interface::parse_options(int argc, char **argv, int my_processor) if (options_.retrieve("copyright") != nullptr) { if (my_processor == 0) { - fmt::print(stderr, - "\n" - "Copyright(C) 1999-2021 National Technology & Engineering Solutions\n" - "of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with\n" - "NTESS, the U.S. Government retains certain rights in this software.\n\n" - "Redistribution and use in source and binary forms, with or without\n" - "modification, are permitted provided that the following conditions are\n" - "met:\n\n " - " * Redistributions of source code must retain the above copyright\n" - " notice, this list of conditions and the following disclaimer.\n\n" - " * Redistributions in binary form must reproduce the above\n" - " copyright notice, this list of conditions and the following\n" - " disclaimer in the documentation and/or other materials provided\n" - " with the distribution.\n\n" - " * Neither the name of NTESS nor the names of its\n" - " contributors may be used to endorse or promote products derived\n" - " from this software without specific prior written permission.\n\n" - "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" - "\" AS IS \" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" - "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" - "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" - "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" - "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" - "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" - "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" - "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" - "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" - "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"); + Ioss::Utils::copyright(std::cerr, "1999-2022"); } exit(EXIT_SUCCESS); } diff --git a/packages/seacas/libraries/ioss/src/main/shell_interface.h b/packages/seacas/libraries/ioss/src/main/shell_interface.h index 284b9256d226..39f821b04c9f 100644 --- a/packages/seacas/libraries/ioss/src/main/shell_interface.h +++ b/packages/seacas/libraries/ioss/src/main/shell_interface.h @@ -45,7 +45,7 @@ namespace IOShell { double append_time{std::numeric_limits::max()}; double timestep_delay{0.0}; int append_step{std::numeric_limits::max()}; - int surface_split_type{1}; + int surface_split_type{-1}; int data_storage_type{0}; int compression_level{0}; int serialize_io_size{0}; diff --git a/packages/seacas/libraries/ioss/src/main/skinner_interface.C b/packages/seacas/libraries/ioss/src/main/skinner_interface.C index b1265d517349..50da6abd1f9f 100644 --- a/packages/seacas/libraries/ioss/src/main/skinner_interface.C +++ b/packages/seacas/libraries/ioss/src/main/skinner_interface.C @@ -253,33 +253,7 @@ bool Skinner::Interface::parse_options(int argc, char **argv) } if (options_.retrieve("copyright") != nullptr) { - fmt::print(stderr, "\n" - "Copyright(C) 1999-2017 National Technology & Engineering Solutions\n" - "of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with\n" - "NTESS, the U.S. Government retains certain rights in this software.\n\n" - "Redistribution and use in source and binary forms, with or without\n" - "modification, are permitted provided that the following conditions are\n" - "met:\n\n " - " * Redistributions of source code must retain the above copyright\n" - " notice, this list of conditions and the following disclaimer.\n\n" - " * Redistributions in binary form must reproduce the above\n" - " copyright notice, this list of conditions and the following\n" - " disclaimer in the documentation and/or other materials provided\n" - " with the distribution.\n\n" - " * Neither the name of NTESS nor the names of its\n" - " contributors may be used to endorse or promote products derived\n" - " from this software without specific prior written permission.\n\n" - "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n" - "\" AS IS \" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n" - "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n" - "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" - "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" - "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n" - "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" - "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" - "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" - "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" - "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n"); + Ioss::Utils::copyright(std::cerr, "1999-2022"); exit(EXIT_SUCCESS); } diff --git a/packages/seacas/libraries/ioss/src/main/test/circle-square-2d.cgns b/packages/seacas/libraries/ioss/src/main/test/circle-square-2d.cgns new file mode 100644 index 0000000000000000000000000000000000000000..c6646cb569ab8ac3e15f99d458b0b15a2807cd39 GIT binary patch literal 95113 zcmeI52YeJo`^P7gND007BlH%!(sV)sA@q(^AtaX&NOE`yp<0mM5kabOGzA0{6a_(0 z0a1}&gGdd%N>M?O|IW_yyUQJSdwY4$|I6`upAS5l+1c4C-{;wx*=Keqgf|Jxk*#R9 z3|X=;{GQNnLZY7_91KwM$;kZW>2VQ#jd6D8Kb77P78_?|hG>&HJ|c-3`UR9obNQs91Lfs2(&bxs zQvS$0F4K{OGzhwkQoD*Uv8ycWiw`BnU(ry%$6mu^1ojV zYHy@v8|Asa`2VkyPBm^D8s1X$>|)Vs%CE5$%)h8oe}KVWpf;~2n?y-t9FTIrUAqbn z#1B%dT{*QY()x0{?wPZXqg|I%8#a?o!Td{!c11G=82Uv;*G)E>6Jt#YV@SCe+q7@v zZRZ-hLTW6|chppbZ5q46UtYKYU0+*cLz}hf*ebTKIl?@&i!2nK1|d+nPF1oXG7tVp zBY(_Q-C}Kn7vzEZblkt3Xam$X@6#7OM=&xrw`1?KA{#fB;^{1UC$SE7Sf_qQL$qQu z4BD1LNf}UEnxX)v7=`G#h?qnsOn|JaK{XR-^t5u@!;7`tsX^NGq6ISMXMTAMrL1`u z%EAi0rNpN-Gkr)MtQzJvEUQtz`3F%)rt%1pGh>A#xn4DQwFK~8L zuqOXmsToqb$;KVfUCMV!+W4=b04sjUQZQ})Ln0E5%pL!y2+I54z5ZNfdmw>+vvd#&K zN#;S3NrTMBsG4DMgJPpvoQtd|{E9Q{T9Af>$W_&aWlPo#y!;RjqJ6@DskJ%cu!sdSB=3kIky% zKldu%GWC^B(-W`ok6-9HGl%I*{6x=$+{4rWbDTZSTCCGhUGyx?CIRpZ^-)@>=D#QySdh*9#5) zpwNM1{LcJ$C;$B51aCe0P`}k>PjloOMfEClI$&A+!2O(kwWRW&JvLbDExABDr1Bi+ zKE68d)+N4IZJ1O(>cN{|j4yDF>V28VY|686f4~hsZN-%gWfi%Z%F#9O*5bu$cJkD* z*(USHJ9w|74|lfhwTFM1b@f=j%%cdU+jp~1ee`gw7xn+loeDi^I zeHv~&%YW#%@`o>ur;r3?UG?`-j?+b^HvSV&S+ZjAV1vt$^EkiP zFuLyAAt(8Q{;xEwA9|7x95|)J`-2YgU3Yt&Jy>lΠ`(z#?VTSO4LwgRdnY=93ED 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 literal 0 HcmV?d00001 diff --git a/packages/seacas/libraries/ioss/src/main/test/exodus_Q2_bc_parents.gold b/packages/seacas/libraries/ioss/src/main/test/exodus_Q2_bc_parents.gold index 2f04e856526a49fd5024665a48ed460674f8aa2e..6020ad82cc38bdedf7aa3ab3dd47813c76ba9948 100644 GIT binary patch literal 1966313 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

F(4Ccq@InBxk(xF{lrr}=bGt?_y(lM;apC>}* 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

C1{^YUE|h-~m<6%SCN+^WS2?6F(-rD_EE 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%0D=7ut&#CEG>B~V^ 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 z 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 z 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 z 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