From ebc7c1be825e1e7033647fe84a8ee86556ecd35a Mon Sep 17 00:00:00 2001
From: renchao_lu <renchao.lu@gmail.com>
Date: Tue, 9 Jun 2020 23:38:54 +0200
Subject: [PATCH] [PL] Interpolate process solutions to int_pts.

---
 .../ComponentTransportFEM.h                   | 15 ++++
 .../ComponentTransportProcess.cpp             | 71 +++++++++++++++++++
 .../ComponentTransportProcess.h               |  3 +
 ProcessLib/LocalAssemblerInterface.h          |  6 ++
 ProcessLib/Process.h                          |  6 ++
 ProcessLib/TimeLoop.cpp                       | 10 +++
 6 files changed, 111 insertions(+)

diff --git a/ProcessLib/ComponentTransport/ComponentTransportFEM.h b/ProcessLib/ComponentTransport/ComponentTransportFEM.h
index af86f986468..2425bfefe41 100644
--- a/ProcessLib/ComponentTransport/ComponentTransportFEM.h
+++ b/ProcessLib/ComponentTransport/ComponentTransportFEM.h
@@ -916,6 +916,21 @@ public:
         return flux;
     }
 
+    std::vector<double> interpolateNodalValuesToIntegrationPoints(
+        std::vector<double> const& local_x) override
+    {
+        unsigned const n_integration_points =
+            _integration_method.getNumberOfPoints();
+
+        std::vector<double> interpolated_values(n_integration_points);
+        for (unsigned ip(0); ip < n_integration_points; ++ip)
+        {
+            NumLib::shapeFunctionInterpolate(local_x, _ip_data[ip].N,
+                                             interpolated_values[ip]);
+        }
+        return interpolated_values;
+    }
+
     std::vector<double> const& getInterpolatedLocalSolution(
         const double /*t*/,
         std::vector<GlobalVector*> const& int_pt_x,
diff --git a/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp b/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp
index e7c0af35970..d824b58ebc6 100644
--- a/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp
+++ b/ProcessLib/ComponentTransport/ComponentTransportProcess.cpp
@@ -174,6 +174,77 @@ void ComponentTransportProcess::
         _local_assemblers, pv.getActiveElementIDs(), _coupled_solutions);
 }
 
+std::vector<GlobalVector>
+ComponentTransportProcess::interpolateNodalValuesToIntegrationPoints(
+    std::vector<GlobalVector*> const& nodal_values_vectors) const
+{
+    // Result is for each process a vector of integration point values for each
+    // element stored consecutively.
+    auto interpolateNodalValuesToIntegrationPoints =
+        [](std::size_t mesh_item_id,
+           LocalAssemblerInterface& local_assembler,
+           std::vector<
+               std::reference_wrapper<NumLib::LocalToGlobalIndexMap>> const&
+               dof_tables,
+           std::vector<GlobalVector*> const& x,
+           std::vector<std::vector<double>>& int_pt_x) {
+            for (unsigned process_id = 0; process_id < x.size(); ++process_id)
+            {
+                auto const& dof_table = dof_tables[process_id].get();
+                auto const indices =
+                    NumLib::getIndices(mesh_item_id, dof_table);
+                auto const local_x = x[process_id]->get(indices);
+
+                std::vector<double> const interpolated_values =
+                    local_assembler.interpolateNodalValuesToIntegrationPoints(
+                        local_x);
+
+                // For each element (mesh_item_id) concatenate the integration
+                // point values.
+                int_pt_x[process_id].insert(int_pt_x[process_id].end(),
+                                            interpolated_values.begin(),
+                                            interpolated_values.end());
+            }
+        };
+
+    // Same dof table for each primary variable.
+    std::vector<std::reference_wrapper<NumLib::LocalToGlobalIndexMap>>
+        dof_tables;
+    dof_tables.reserve(nodal_values_vectors.size());
+    std::generate_n(std::back_inserter(dof_tables), nodal_values_vectors.size(),
+                    [&]() { return std::ref(*_local_to_global_index_map); });
+
+    std::vector<std::vector<double>> integration_point_values_vecs(
+        nodal_values_vectors.size());
+
+    GlobalExecutor::executeDereferenced(
+        interpolateNodalValuesToIntegrationPoints, _local_assemblers,
+        dof_tables, nodal_values_vectors, integration_point_values_vecs);
+
+    // Convert from std::vector<std::vector<double>> to
+    // std::vector<GlobalVector>
+    std::vector<GlobalVector> integration_point_values_vectors;
+    integration_point_values_vectors.reserve(nodal_values_vectors.size());
+    for (auto const& integration_point_values_vec :
+         integration_point_values_vecs)
+    {
+        GlobalIndexType const size = integration_point_values_vec.size();
+        // New vector of size (elements x integration_points_per_element)
+        GlobalVector integration_point_values_vector(size);
+
+        // Copy one by one.
+        for (GlobalIndexType i = 0; i < size; ++i)
+        {
+            integration_point_values_vector.set(
+                i, integration_point_values_vec[i]);
+        }
+        integration_point_values_vectors.push_back(
+            std::move(integration_point_values_vector));
+    }
+
+    return integration_point_values_vectors;
+}
+
 void ComponentTransportProcess::extrapolateIntegrationPointValuesToNodes(
     const double t,
     std::vector<GlobalVector*> const& integration_point_values_vectors,
diff --git a/ProcessLib/ComponentTransport/ComponentTransportProcess.h b/ProcessLib/ComponentTransport/ComponentTransportProcess.h
index 374f771f5e7..d86b67547fa 100644
--- a/ProcessLib/ComponentTransport/ComponentTransportProcess.h
+++ b/ProcessLib/ComponentTransport/ComponentTransportProcess.h
@@ -117,6 +117,9 @@ public:
     void setCoupledTermForTheStaggeredSchemeToLocalAssemblers(
         int const process_id) override;
 
+    std::vector<GlobalVector> interpolateNodalValuesToIntegrationPoints(
+        std::vector<GlobalVector*> const& nodal_values_vectors) const override;
+
     void extrapolateIntegrationPointValuesToNodes(
         const double t,
         std::vector<GlobalVector*> const& integration_point_values_vectors,
diff --git a/ProcessLib/LocalAssemblerInterface.h b/ProcessLib/LocalAssemblerInterface.h
index 2b09c451092..253fa45fe52 100644
--- a/ProcessLib/LocalAssemblerInterface.h
+++ b/ProcessLib/LocalAssemblerInterface.h
@@ -98,6 +98,12 @@ public:
                              GlobalVector const& x, double const t,
                              double const dt, bool const use_monolithic_scheme);
 
+    virtual std::vector<double> interpolateNodalValuesToIntegrationPoints(
+        std::vector<double> const& /*local_x*/)
+    {
+        return {};
+    }
+
     /// Computes the flux in the point \c p_local_coords that is given in local
     /// coordinates using the values from \c local_x.
     /// Fits to monolithic scheme.
diff --git a/ProcessLib/Process.h b/ProcessLib/Process.h
index 5838c56e19c..43f04a22d21 100644
--- a/ProcessLib/Process.h
+++ b/ProcessLib/Process.h
@@ -101,6 +101,12 @@ public:
     {
     }
 
+    virtual std::vector<GlobalVector> interpolateNodalValuesToIntegrationPoints(
+        std::vector<GlobalVector*> const& /*nodal_values_vectors*/) const
+    {
+        return {};
+    }
+
     virtual void extrapolateIntegrationPointValuesToNodes(
         const double /*t*/,
         std::vector<GlobalVector*> const& /*integration_point_values_vectors*/,
diff --git a/ProcessLib/TimeLoop.cpp b/ProcessLib/TimeLoop.cpp
index 8afb0961cb4..35d7e748bab 100644
--- a/ProcessLib/TimeLoop.cpp
+++ b/ProcessLib/TimeLoop.cpp
@@ -453,6 +453,11 @@ void TimeLoop::initialize()
     {
         BaseLib::RunTime time_phreeqc;
         time_phreeqc.start();
+
+        auto& pcs = _per_process_data[0]->process;
+        auto const interpolated_process_solutions =
+            pcs.interpolateNodalValuesToIntegrationPoints(_process_solutions);
+
         _chemical_solver_interface->executeInitialCalculation(
             _process_solutions);
         INFO("[time] Phreeqc took {:g} s.", time_phreeqc.elapsed());
@@ -815,6 +820,11 @@ TimeLoop::solveCoupledEquationSystemsByStaggeredScheme(
         // space and localized chemical equilibrium between solutes.
         BaseLib::RunTime time_phreeqc;
         time_phreeqc.start();
+
+        auto& pcs = _per_process_data[0]->process;
+        auto const interpolated_process_solutions =
+            pcs.interpolateNodalValuesToIntegrationPoints(_process_solutions);
+
         _chemical_solver_interface->doWaterChemistryCalculation(
             _process_solutions, dt);
         INFO("[time] Phreeqc took {:g} s.", time_phreeqc.elapsed());
-- 
GitLab