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