From 69525cf1bd3a2608e34cd2a499fda2a552403df7 Mon Sep 17 00:00:00 2001 From: Christoph Lehmann <christoph.lehmann@ufz.de> Date: Fri, 3 Dec 2021 09:13:52 +0100 Subject: [PATCH] [PL] Added class ProcessOutputData --- ProcessLib/Output/ProcessOutputData.cpp | 219 ++++++++++++++++++++++++ ProcessLib/Output/ProcessOutputData.h | 134 +++++++++++++++ 2 files changed, 353 insertions(+) create mode 100644 ProcessLib/Output/ProcessOutputData.cpp create mode 100644 ProcessLib/Output/ProcessOutputData.h diff --git a/ProcessLib/Output/ProcessOutputData.cpp b/ProcessLib/Output/ProcessOutputData.cpp new file mode 100644 index 00000000000..49063a2642e --- /dev/null +++ b/ProcessLib/Output/ProcessOutputData.cpp @@ -0,0 +1,219 @@ +/** + * \file + * \copyright + * Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "ProcessOutputData.h" + +#include "ProcessLib/Process.h" + +namespace +{ +/// Checks if the given \c mesh is the simulation domain of the given \c +/// process. +bool isSimulationDomain(MeshLib::Mesh const& mesh, + ProcessLib::Process const& process) +{ + return mesh == process.getMesh(); +} + +std::vector<std::unique_ptr<NumLib::LocalToGlobalIndexMap>> +computeDofTablesForSubmesh(ProcessLib::Process const& process, + MeshLib::Mesh const& submesh, + std::size_t const n_processes) +{ + std::vector<std::unique_ptr<NumLib::LocalToGlobalIndexMap>> + submesh_dof_tables; + submesh_dof_tables.reserve(n_processes); + + for (std::size_t i = 0; i < n_processes; ++i) + { + submesh_dof_tables.push_back( + process.getDOFTable(i).deriveBoundaryConstrainedMap( + MeshLib::MeshSubset{submesh, submesh.getNodes()})); + } + + return submesh_dof_tables; +} + +std::vector<NumLib::LocalToGlobalIndexMap const*> toNonOwning( + std::vector<std::unique_ptr<NumLib::LocalToGlobalIndexMap>> const& + dof_tables) +{ + std::vector<NumLib::LocalToGlobalIndexMap const*> dof_table_pointers; + + dof_table_pointers.reserve(dof_tables.size()); + transform(cbegin(dof_tables), cend(dof_tables), + back_inserter(dof_table_pointers), + [](std::unique_ptr<NumLib::LocalToGlobalIndexMap> const& p) + { return p.get(); }); + + return dof_table_pointers; +} + +std::vector<NumLib::LocalToGlobalIndexMap const*> getDofTablesOfAllProcesses( + ProcessLib::Process const& process, std::size_t const n_processes) +{ + std::vector<NumLib::LocalToGlobalIndexMap const*> dof_tables_of_all_procs( + n_processes); + + for (std::size_t proc_id = 0; proc_id < n_processes; ++proc_id) + { + dof_tables_of_all_procs[proc_id] = &process.getDOFTable(proc_id); + } + + return dof_tables_of_all_procs; +} + +/// Computes the d.o.f. tables for the given \c output_mesh. +/// +/// These are the passed \c bulk_mesh_dof_tables for output of the entire +/// simulation domain of the given \c process. In the case of submesh output +/// d.o.f. tables for the submesh will be computed. +/// +/// \return A pair of (vector of d.o.f. table pointers, vector of d.o.f. table +/// storage), where the latter is populated in the case of submesh output only. +/// +/// Each element in the returned vectors corresponds to a specific \c process_id +/// of the \c process. +decltype(auto) computeOutputMeshDofTables( + ProcessLib::Process const& process, + MeshLib::Mesh const& output_mesh, + std::vector<NumLib::LocalToGlobalIndexMap const*> const& + bulk_mesh_dof_tables) +{ + if (isSimulationDomain(output_mesh, process)) + { + return std::pair( + bulk_mesh_dof_tables /* will be copied */, + std::vector<std::unique_ptr<NumLib::LocalToGlobalIndexMap>>{}); + } + + auto const n_processes = bulk_mesh_dof_tables.size(); + + // TODO Currently these d.o.f. tables will be recomputed everytime we write + // output. That should be avoided in the future. + auto container_that_owns_output_mesh_dof_tables = + computeDofTablesForSubmesh(process, output_mesh, n_processes); + + auto output_mesh_dof_tables = + toNonOwning(container_that_owns_output_mesh_dof_tables); + + return std::pair(std::move(output_mesh_dof_tables), + std::move(container_that_owns_output_mesh_dof_tables)); +} + +std::vector<std::reference_wrapper< + const std::vector<std::reference_wrapper<ProcessLib::ProcessVariable>>>> +getProcessVariablesOfAllProcesses(ProcessLib::Process const& process, + std::size_t const n_processes) +{ + std::vector<std::reference_wrapper< + const std::vector<std::reference_wrapper<ProcessLib::ProcessVariable>>>> + pvs_of_all_procs; + pvs_of_all_procs.reserve(n_processes); + + for (std::size_t proc_id = 0; proc_id < n_processes; ++proc_id) + { + pvs_of_all_procs.emplace_back(process.getProcessVariables(proc_id)); + } + + return pvs_of_all_procs; +} + +std::vector<std::unique_ptr<ProcessLib::IntegrationPointWriter>> const* +getIntegrationPointWriters(ProcessLib::Process const& process, + MeshLib::Mesh const& output_mesh) +{ + return isSimulationDomain(output_mesh, process) + ? &process.getIntegrationPointWriters() + : nullptr; +} + +} // namespace + +namespace ProcessLib +{ + +ProcessOutputData createProcessOutputData(Process const& process, + std::size_t const n_processes, + MeshLib::Mesh& output_mesh) +{ + auto bulk_mesh_dof_tables = + getDofTablesOfAllProcesses(process, n_processes); + + auto [output_mesh_dof_tables, container_that_owns_output_mesh_dof_tables] = + computeOutputMeshDofTables(process, output_mesh, bulk_mesh_dof_tables); + + return {getProcessVariablesOfAllProcesses(process, n_processes), + process.getSecondaryVariables(), + ::getIntegrationPointWriters(process, output_mesh), + std::move(bulk_mesh_dof_tables), + std::move(output_mesh_dof_tables), + std::move(container_that_owns_output_mesh_dof_tables), + output_mesh}; +} + +ProcessOutputData::ProcessOutputData( + std::vector<std::reference_wrapper< + const std::vector<std::reference_wrapper<ProcessVariable>>>>&& + process_variables_of_all_processes, + const SecondaryVariableCollection& secondary_variables, + const std::vector<std::unique_ptr<IntegrationPointWriter>>* + integration_point_writers, + std::vector<const NumLib::LocalToGlobalIndexMap*>&& + bulk_mesh_dof_tables_of_all_processes, + std::vector<const NumLib::LocalToGlobalIndexMap*>&& + output_mesh_dof_tables_of_all_processes, + std::vector<std::unique_ptr<NumLib::LocalToGlobalIndexMap>>&& + container_that_owns_output_mesh_dof_tables, + MeshLib::Mesh& output_mesh) + : process_variables_of_all_processes_( + std::move(process_variables_of_all_processes)), + secondary_variables_(secondary_variables), + integration_point_writers_(integration_point_writers), + bulk_mesh_dof_tables_of_all_processes_( + std::move(bulk_mesh_dof_tables_of_all_processes)), + output_mesh_dof_tables_of_all_processes_( + std::move(output_mesh_dof_tables_of_all_processes)), + container_that_owns_output_mesh_dof_tables_( + std::move(container_that_owns_output_mesh_dof_tables)), + output_mesh_(output_mesh) +{ + auto const n_proc_pvs = process_variables_of_all_processes_.size(); + auto const n_proc_bulk = bulk_mesh_dof_tables_of_all_processes_.size(); + auto const n_proc_out = output_mesh_dof_tables_of_all_processes_.size(); + auto const n_proc_own = container_that_owns_output_mesh_dof_tables_.size(); + + if (n_proc_pvs != n_proc_bulk) + { + OGS_FATAL( + "Mismatch in number of processes (PVs vs. bulk mesh d.o.f. " + "tables): {} != {}", + n_proc_pvs, n_proc_bulk); + } + + if (n_proc_pvs != n_proc_out) + { + OGS_FATAL( + "Mismatch in number of processes (PVs vs. output mesh d.o.f. " + "tables): {} != {}", + n_proc_pvs, n_proc_out); + } + + // n_proc_own is nonzero only for submesh output + if (n_proc_own != 0 && n_proc_pvs != n_proc_own) + { + OGS_FATAL( + "Mismatch in number of processes (PVs vs. output mesh d.o.f. " + "tables, owning): {} != {}", + n_proc_pvs, n_proc_own); + } +} + +} // namespace ProcessLib diff --git a/ProcessLib/Output/ProcessOutputData.h b/ProcessLib/Output/ProcessOutputData.h new file mode 100644 index 00000000000..8ef51f65a02 --- /dev/null +++ b/ProcessLib/Output/ProcessOutputData.h @@ -0,0 +1,134 @@ +/** + * \file + * \copyright + * Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include "MathLib/LinAlg/GlobalMatrixVectorTypes.h" +#include "NumLib/DOF/LocalToGlobalIndexMap.h" + +namespace ProcessLib +{ +class Process; +class ProcessVariable; +class SecondaryVariableCollection; +struct IntegrationPointWriter; + +/// Holds all data of a process that are needed for output. +class ProcessOutputData final +{ +public: + ProcessOutputData( + std::vector<std::reference_wrapper< + const std::vector<std::reference_wrapper<ProcessVariable>>>>&& + process_variables_of_all_processes, + const SecondaryVariableCollection& secondary_variables, + const std::vector<std::unique_ptr<IntegrationPointWriter>>* + integration_point_writers, + std::vector<const NumLib::LocalToGlobalIndexMap*>&& + bulk_mesh_dof_tables_of_all_processes, + std::vector<const NumLib::LocalToGlobalIndexMap*>&& + output_mesh_dof_tables_of_all_processes, + std::vector<std::unique_ptr<NumLib::LocalToGlobalIndexMap>>&& + container_that_owns_output_mesh_dof_tables, + MeshLib::Mesh& output_mesh); + + std::vector<std::reference_wrapper<ProcessVariable>> const& + getProcessVariables(int const process_id) const + { + return process_variables_of_all_processes_[process_id].get(); + } + + SecondaryVariableCollection const& getSecondaryVariables() const + { + return secondary_variables_; + } + + std::vector<std::unique_ptr<IntegrationPointWriter>> const* + getIntegrationPointWriters() const + { + return integration_point_writers_; + } + + NumLib::LocalToGlobalIndexMap const& getBulkMeshDofTable( + int const process_id) const + { + return *bulk_mesh_dof_tables_of_all_processes_[process_id]; + } + + NumLib::LocalToGlobalIndexMap const& getOutputMeshDofTable( + int const process_id) const + { + return *output_mesh_dof_tables_of_all_processes_[process_id]; + } + + std::vector<const NumLib::LocalToGlobalIndexMap*> const& + getOutputMeshDofTablesOfAllProcesses() const + { + return output_mesh_dof_tables_of_all_processes_; + } + + MeshLib::Mesh& getOutputMesh() const { return output_mesh_; } + +private: + /// Process variables of all processes. + /// + /// Each element of the container corresponds to a specific \c process_id of + /// the Process. + std::vector<std::reference_wrapper< + const std::vector<std::reference_wrapper<ProcessVariable>>>> + process_variables_of_all_processes_; + + SecondaryVariableCollection const& secondary_variables_; + + /// The list of integration point writers or \c nullptr if there are no + /// integration point writers defined on the #output_mesh_. + /// + /// The latter is the case for output on submeshes. + std::vector<std::unique_ptr<IntegrationPointWriter>> const* + integration_point_writers_; + + /// D.o.f. tables for the full simulation domain of the Process this + /// ProcessOutputData is associated with. + /// + /// Each element of the container corresponds to a specific \c process_id of + /// the Process. + std::vector<NumLib::LocalToGlobalIndexMap const*> + bulk_mesh_dof_tables_of_all_processes_; + + /// D.o.f tables for the given #output_mesh_. + /// + /// In the case of submesh output these d.o.f. tables are different from the + /// #bulk_mesh_dof_tables_of_all_processes_. + /// + /// Each element of the container corresponds to a specific \c process_id of + /// the Process this ProcessOutputData is associated with. + std::vector<NumLib::LocalToGlobalIndexMap const*> + output_mesh_dof_tables_of_all_processes_; + + /// Actual data backing the pointers in + /// #output_mesh_dof_tables_of_all_processes_. + /// + /// This container is populated in the case of submesh output only. + std::vector<std::unique_ptr<NumLib::LocalToGlobalIndexMap>> + container_that_owns_output_mesh_dof_tables_; + + /// The mesh to which output shall be written. + /// + /// This can be the entire simulation domain of the Process this + /// ProcessOutputData is associated with or a submesh thereof. + MeshLib::Mesh& output_mesh_; +}; + +/// Extracts data necessary for output from the given \c process. +ProcessOutputData createProcessOutputData(Process const& process, + std::size_t const n_processes, + MeshLib::Mesh& output_mesh); + +} // namespace ProcessLib -- GitLab