From 2ece6496a2647caa90640197a97c84b8f84ad738 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com>
Date: Mon, 13 Mar 2023 08:04:46 +0100
Subject: [PATCH] Allow to post process item_array (SubItemArrayPerItem)

---
 src/language/modules/WriterModule.cpp | 13 +++++
 src/output/INamedDiscreteData.hpp     |  1 +
 src/output/NamedItemArrayVariant.hpp  | 47 +++++++++++++++++
 src/output/WriterBase.cpp             | 72 ++++++++++++++++++++++-----
 4 files changed, 120 insertions(+), 13 deletions(-)
 create mode 100644 src/output/NamedItemArrayVariant.hpp

diff --git a/src/language/modules/WriterModule.cpp b/src/language/modules/WriterModule.cpp
index aa479c0eb..af7d0cb4b 100644
--- a/src/language/modules/WriterModule.cpp
+++ b/src/language/modules/WriterModule.cpp
@@ -4,12 +4,14 @@
 #include <language/utils/TypeDescriptor.hpp>
 #include <mesh/Connectivity.hpp>
 #include <mesh/GmshReader.hpp>
+#include <mesh/ItemArrayVariant.hpp>
 #include <mesh/ItemValueVariant.hpp>
 #include <mesh/Mesh.hpp>
 #include <output/GnuplotWriter.hpp>
 #include <output/GnuplotWriter1D.hpp>
 #include <output/IWriter.hpp>
 #include <output/NamedDiscreteFunction.hpp>
+#include <output/NamedItemArrayVariant.hpp>
 #include <output/NamedItemValueVariant.hpp>
 #include <output/VTKWriter.hpp>
 #include <scheme/DiscreteFunctionVariant.hpp>
@@ -80,6 +82,7 @@ WriterModule::WriterModule()
                                              }
 
                                              ));
+
   this->_addBuiltinFunction("name_output", std::function(
 
                                              [](std::shared_ptr<const ItemValueVariant> item_value_variant,
@@ -90,6 +93,16 @@ WriterModule::WriterModule()
 
                                              ));
 
+  this->_addBuiltinFunction("name_output", std::function(
+
+                                             [](std::shared_ptr<const ItemArrayVariant> item_array_variant,
+                                                const std::string& name) -> std::shared_ptr<const INamedDiscreteData> {
+                                               return std::make_shared<const NamedItemArrayVariant>(item_array_variant,
+                                                                                                    name);
+                                             }
+
+                                             ));
+
   this->_addBuiltinFunction("write_mesh",
                             std::function(
 
diff --git a/src/output/INamedDiscreteData.hpp b/src/output/INamedDiscreteData.hpp
index 5d22e82c2..b4fae2b34 100644
--- a/src/output/INamedDiscreteData.hpp
+++ b/src/output/INamedDiscreteData.hpp
@@ -8,6 +8,7 @@ class INamedDiscreteData
  public:
   enum class Type
   {
+    item_array,
     item_value,
     discrete_function
   };
diff --git a/src/output/NamedItemArrayVariant.hpp b/src/output/NamedItemArrayVariant.hpp
new file mode 100644
index 000000000..4b92d5585
--- /dev/null
+++ b/src/output/NamedItemArrayVariant.hpp
@@ -0,0 +1,47 @@
+#ifndef NAMED_ITEM_ARRAY_VARIANT_HPP
+#define NAMED_ITEM_ARRAY_VARIANT_HPP
+
+#include <output/INamedDiscreteData.hpp>
+
+#include <memory>
+#include <string>
+
+class ItemArrayVariant;
+
+class NamedItemArrayVariant final : public INamedDiscreteData
+{
+ private:
+  std::shared_ptr<const ItemArrayVariant> m_item_array_variant;
+  std::string m_name;
+
+ public:
+  Type
+  type() const final
+  {
+    return INamedDiscreteData::Type::item_array;
+  }
+
+  const std::string&
+  name() const final
+  {
+    return m_name;
+  }
+
+  const std::shared_ptr<const ItemArrayVariant>
+  itemArrayVariant() const
+  {
+    return m_item_array_variant;
+  }
+
+  NamedItemArrayVariant(const std::shared_ptr<const ItemArrayVariant>& item_array_variant, const std::string& name)
+    : m_item_array_variant{item_array_variant}, m_name{name}
+  {}
+
+  NamedItemArrayVariant(const NamedItemArrayVariant&) = default;
+  NamedItemArrayVariant(NamedItemArrayVariant&&)      = default;
+
+  NamedItemArrayVariant()  = default;
+  ~NamedItemArrayVariant() = default;
+};
+
+#endif   // NAMED_ITEM_ARRAY_VARIANT_HPP
diff --git a/src/output/WriterBase.cpp b/src/output/WriterBase.cpp
index b5cbee4c4..a96da1e4e 100644
--- a/src/output/WriterBase.cpp
+++ b/src/output/WriterBase.cpp
@@ -1,8 +1,10 @@
 #include <output/WriterBase.hpp>
 
 #include <mesh/IMesh.hpp>
+#include <mesh/ItemArrayVariant.hpp>
 #include <mesh/ItemValueVariant.hpp>
 #include <output/NamedDiscreteFunction.hpp>
+#include <output/NamedItemArrayVariant.hpp>
 #include <output/NamedItemValueVariant.hpp>
 #include <output/OutputNamedItemValueSet.hpp>
 #include <scheme/DiscreteFunctionP0.hpp>
@@ -94,6 +96,21 @@ WriterBase::_checkSignature(
         named_item_value.itemValueVariant()->itemValue());
       break;
     }
+    case INamedDiscreteData::Type::item_array: {
+      const NamedItemArrayVariant& named_item_array = dynamic_cast<const NamedItemArrayVariant&>(*named_discrete_data);
+      std::visit(
+        [&](auto&& item_value) {
+          using ItemValueT = std::decay_t<decltype(item_value)>;
+          using DataType   = std::decay_t<typename ItemValueT::data_type>;
+
+          std::ostringstream type_name;
+          type_name << "item_array(" << dataTypeName(ast_node_data_type_from<DataType>) << ')';
+
+          name_type_map[named_discrete_data->name()] = type_name.str();
+        },
+        named_item_array.itemArrayVariant()->itemArray());
+      break;
+    }
     case INamedDiscreteData::Type::discrete_function: {
       const NamedDiscreteFunction& named_discrete_function =
         dynamic_cast<const NamedDiscreteFunction&>(*named_discrete_data);
@@ -107,9 +124,6 @@ WriterBase::_checkSignature(
         named_discrete_function.discreteFunctionVariant()->discreteFunction());
       break;
     }
-    default: {
-      throw UnexpectedError("unexpected discrete data type");
-    }
     }
   }
 
@@ -204,6 +218,17 @@ WriterBase::_getMesh(const std::vector<std::shared_ptr<const INamedDiscreteData>
                    auto&&
                      item_value) { connectivity_set[item_value.connectivity_ptr()] = named_item_value_variant.name(); },
                  named_item_value_variant.itemValueVariant()->itemValue());
+      break;
+    }
+    case INamedDiscreteData::Type::item_array: {
+      const NamedItemArrayVariant& named_item_array_variant =
+        dynamic_cast<const NamedItemArrayVariant&>(*named_discrete_data);
+
+      std::visit([&](
+                   auto&&
+                     item_array) { connectivity_set[item_array.connectivity_ptr()] = named_item_array_variant.name(); },
+                 named_item_array_variant.itemArrayVariant()->itemArray());
+      break;
     }
     }
   }
@@ -271,8 +296,26 @@ WriterBase::_getOutputNamedItemDataSet(
                  item_value_variant.itemValue());
       break;
     }
-    default: {
-      throw UnexpectedError("invalid discrete data type");
+    case INamedDiscreteData::Type::item_array: {
+      const NamedItemArrayVariant& named_item_array_variant =
+        dynamic_cast<const NamedItemArrayVariant&>(*named_discrete_data);
+
+      const std::string& name = named_item_array_variant.name();
+
+      const ItemArrayVariant& item_value_variant = *named_item_array_variant.itemArrayVariant();
+
+      std::visit(
+        [&](auto&& item_array) {
+          using ItemArrayType = std::decay_t<decltype(item_array)>;
+          using DataType      = std::decay_t<typename ItemArrayType::data_type>;
+          if constexpr (std::is_arithmetic_v<DataType>) {
+            named_item_data_set.add(NamedItemData{name, item_array});
+          } else {
+            throw NormalError("can only write item_array containing scalar values");
+          }
+        },
+        item_value_variant.itemArray());
+      break;
     }
     }
   }
@@ -340,8 +383,8 @@ WriterBase::writeOnMesh(const std::shared_ptr<const IMesh>& mesh,
   if (m_period_manager.has_value()) {
     throw NormalError("this writer requires time value");
   } else {
-    _checkMesh(mesh, named_discrete_data_list);
-    _checkConnectivity(mesh, named_discrete_data_list);
+    this->_checkMesh(mesh, named_discrete_data_list);
+    this->_checkConnectivity(mesh, named_discrete_data_list);
     this->_write(*mesh, named_discrete_data_list);
   }
 }
@@ -352,10 +395,12 @@ WriterBase::writeOnMeshIfNeeded(const std::shared_ptr<const IMesh>& mesh,
                                 double time) const
 {
   if (m_period_manager.has_value()) {
-    if (time == m_period_manager->getLastTime())
+    if (time == m_period_manager->getLastTime()) {
       return;   // output already performed
-    _checkMesh(mesh, named_discrete_data_list);
-    _checkConnectivity(mesh, named_discrete_data_list);
+    }
+
+    this->_checkMesh(mesh, named_discrete_data_list);
+    this->_checkConnectivity(mesh, named_discrete_data_list);
     this->_writeAtTime(*mesh, named_discrete_data_list, time);
     m_period_manager->setSaveTime(time);
   } else {
@@ -369,10 +414,11 @@ WriterBase::writeOnMeshForced(const std::shared_ptr<const IMesh>& mesh,
                               double time) const
 {
   if (m_period_manager.has_value()) {
-    if (time == m_period_manager->getLastTime())
+    if (time == m_period_manager->getLastTime()) {
       return;   // output already performed
-    _checkMesh(mesh, named_discrete_data_list);
-    _checkConnectivity(mesh, named_discrete_data_list);
+    }
+    this->_checkMesh(mesh, named_discrete_data_list);
+    this->_checkConnectivity(mesh, named_discrete_data_list);
     this->_writeAtTime(*mesh, named_discrete_data_list, time);
     m_period_manager->setSaveTime(time);
   } else {
-- 
GitLab