From b7d8f2cc34a155fb122876a26dba12fffaad1f4c Mon Sep 17 00:00:00 2001
From: Anthony Royer <anthony.royer@uliege.be>
Date: Wed, 15 Dec 2021 10:27:19 +0100
Subject: [PATCH] Add 'SubdomainCompoundField' and 'InterfaceCompoundField'

---
 examples/helmholtz/crossPoints/README.md |   2 +-
 examples/helmholtz/crossPoints/mesh.cpp  |   2 -
 src/field/CMakeLists.txt                 |   5 +-
 src/field/InterfaceCompoundField.cpp     | 167 +++++++++++++++++++++++
 src/field/InterfaceCompoundField.h       |  55 ++++++++
 src/field/InterfaceField.cpp             |  56 ++------
 src/field/InterfaceField.h               |  17 +--
 src/field/InterfaceFieldInterface.cpp    |  45 ++++++
 src/field/InterfaceFieldInterface.h      |  48 +++++++
 src/field/SubdomainCompoundField.cpp     | 133 ++++++++++++++++++
 src/field/SubdomainCompoundField.h       |  53 +++++++
 src/field/SubdomainField.h               |   6 +-
 12 files changed, 522 insertions(+), 67 deletions(-)
 create mode 100644 src/field/InterfaceCompoundField.cpp
 create mode 100644 src/field/InterfaceCompoundField.h
 create mode 100644 src/field/InterfaceFieldInterface.cpp
 create mode 100644 src/field/InterfaceFieldInterface.h
 create mode 100644 src/field/SubdomainCompoundField.cpp
 create mode 100644 src/field/SubdomainCompoundField.h

diff --git a/examples/helmholtz/crossPoints/README.md b/examples/helmholtz/crossPoints/README.md
index 93a68a74..53be3ed7 100644
--- a/examples/helmholtz/crossPoints/README.md
+++ b/examples/helmholtz/crossPoints/README.md
@@ -9,7 +9,7 @@ Dependency(ies):
 ## Project description
 
 In this work, we present a non-overlapping substructured DDM with PML transmission conditions or HABC 
-transmission conditionz forvcheckerboard (Cartesian) decompositions that takes cross-points into account. 
+transmission conditions for checkerboard (Cartesian) decompositions that takes cross-points into account. 
 In such decompositions, each subdomain is surrounded by PMLs associated to edges and corners. 
 
 ## Installation
diff --git a/examples/helmholtz/crossPoints/mesh.cpp b/examples/helmholtz/crossPoints/mesh.cpp
index a7423d4b..537d5a9a 100755
--- a/examples/helmholtz/crossPoints/mesh.cpp
+++ b/examples/helmholtz/crossPoints/mesh.cpp
@@ -146,14 +146,12 @@ namespace D2 {
     squarePoints[2] = newPoint(posX[2], posY[2], 0., lc);
     squarePoints[3] = newPoint(posX[3], posY[3], 0., lc);
     gmsh::model::geo::synchronize();
-//    gmshfem::msg::error << "Points : " << squarePoints[0] << " " << squarePoints[1] << " " << squarePoints[2] << " " << squarePoints[3] << gmshfem::msg::endl;
     
     std::vector< int > squareLines(4);
     for(unsigned int i = 0; i < 4; ++i) {
       squareLines[i] = newLine(squarePoints[i], squarePoints[(i+1)%4]);
     }
     gmsh::model::geo::synchronize();
-//    gmshfem::msg::error << "Lines : " << squareLines[0] << " " << squareLines[1] << " " << squareLines[2] << " " << squareLines[3] << gmshfem::msg::endl;
     
     int squareCurveLoop = gmsh::model::geo::addCurveLoop(squareLines);
     int omega = 0;
diff --git a/src/field/CMakeLists.txt b/src/field/CMakeLists.txt
index 9628d5db..9bc24f08 100644
--- a/src/field/CMakeLists.txt
+++ b/src/field/CMakeLists.txt
@@ -4,8 +4,11 @@
 ## issues on https://gitlab.onelab.info/gmsh/ddm/issues
 
 set(SRC
-  SubdomainField.cpp
+  InterfaceCompoundField.cpp
   InterfaceField.cpp
+  InterfaceFieldInterface.cpp
+  SubdomainCompoundField.cpp
+  SubdomainField.cpp
 )
 
 file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h)
diff --git a/src/field/InterfaceCompoundField.cpp b/src/field/InterfaceCompoundField.cpp
new file mode 100644
index 00000000..8d4f8c9b
--- /dev/null
+++ b/src/field/InterfaceCompoundField.cpp
@@ -0,0 +1,167 @@
+// GmshDDM - Copyright (C) 2019-2021, A. Royer, C. Geuzaine, Université de Liège
+//
+// See the LICENSE.txt file for license information. Please report all
+// issues on https://gitlab.onelab.info/gmsh/ddm/issues
+
+#include "InterfaceCompoundField.h"
+
+#include <gmshfem/Exception.h>
+
+namespace gmshddm
+{
+
+
+  namespace field
+  {
+  
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::InterfaceCompoundField() :
+      InterfaceFieldInterface< T_Scalar >(), _fields()
+    {
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::InterfaceCompoundField(const std::string &name, const domain::Interface &domains, const gmshfem::field::FunctionSpaceOfForm< T_Form > &type, const unsigned int degree) :
+      InterfaceFieldInterface< T_Scalar >(name), _fields(domains.numberOfSubdomains())
+    {
+      for(auto i = 0U; i < domains.numberOfSubdomains(); ++i) {
+        for(auto it = domains[i].begin(); it != domains[i].end(); ++it) {
+          _fields[i].insert(std::make_pair(it->first, gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields >(this->_name + "_" + std::to_string(i) + "_" + std::to_string(it->first), it->second, type, degree)));
+        }
+      }
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::InterfaceCompoundField(const std::string &name, const domain::Interface &domains, const gmshfem::field::FunctionSpaceOfForm< T_Form > &type,const std::vector<unsigned int> & degree) :
+      InterfaceFieldInterface< T_Scalar >(name), _fields(domains.numberOfSubdomains())
+    {
+      if(domains.numberOfSubdomains() > degree.size()) {
+        throw gmshfem::common::Exception("Wrong size of degree");
+      }
+      for(unsigned int i = 0; i < domains.numberOfSubdomains(); ++i) {
+        for(auto it = domains[i].begin(); it != domains[i].end(); ++it) {
+          _fields[i].insert(std::make_pair(it->first, gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields >(this->_name + "_" + std::to_string(i) + "_" + std::to_string(it->first), it->second, type, degree[i])));
+        }
+      }
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::InterfaceCompoundField(const InterfaceCompoundField< T_Scalar, T_Form, T_NumFields > &other) :
+      InterfaceFieldInterface< T_Scalar >(other._name), _fields(other._fields)
+    {
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::InterfaceCompoundField(InterfaceCompoundField< T_Scalar, T_Form, T_NumFields > &&other) :
+      InterfaceFieldInterface< T_Scalar >(other._name), _fields(std::move(other._fields))
+    {
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    InterfaceCompoundField< T_Scalar, T_Form, T_NumFields > &InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::operator=(const InterfaceCompoundField< T_Scalar, T_Form, T_NumFields > &other)
+    {
+      this->_name = other._name;
+      _fields = other._fields;
+      return *this;
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::~InterfaceCompoundField()
+    {
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    gmshfem::field::Form InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::form() const
+    {
+      return T_Form;
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    bool InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::isDefined(const unsigned int i, const unsigned int j) const
+    {
+      auto it = _fields[i].find(j);
+      if(it == _fields[i].end()) {
+        return false;
+      }
+      return true;
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    const gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields > &InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::operator()(const unsigned int i, const unsigned int j) const
+    {
+      if(i >= _fields.size()) {
+        throw gmshfem::common::Exception("Trying to access field(" + std::to_string(i) + ", " + std::to_string(j) + ") of field '" + this->_name + "'");
+      }
+      auto it = _fields[i].find(j);
+      if(it == _fields[i].end()) {
+        throw gmshfem::common::Exception("Trying to access field(" + std::to_string(i) + ", " + std::to_string(j) + ") of field '" + this->_name + "'");
+      }
+
+      return it->second;
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields > &InterfaceCompoundField< T_Scalar, T_Form, T_NumFields >::operator()(const unsigned int i, const unsigned int j)
+    {
+      if(i >= _fields.size()) {
+        throw gmshfem::common::Exception("Trying to access field(" + std::to_string(i) + ", " + std::to_string(j) + ") of field '" + this->_name + "'");
+      }
+      auto it = _fields[i].find(j);
+      if(it == _fields[i].end()) {
+        throw gmshfem::common::Exception("Try to access field(" + std::to_string(i) + ", " + std::to_string(j) + ") of field '" + this->_name + "'");
+      }
+
+      return it->second;
+    }
+
+
+    template class InterfaceCompoundField< std::complex< double >, gmshfem::field::Form::Form0, 2 >;
+    template class InterfaceCompoundField< std::complex< double >, gmshfem::field::Form::Form1, 2 >;
+    template class InterfaceCompoundField< std::complex< double >, gmshfem::field::Form::Form2, 2 >;
+    template class InterfaceCompoundField< std::complex< double >, gmshfem::field::Form::Form3, 2 >;
+
+    template class InterfaceCompoundField< double, gmshfem::field::Form::Form0, 2 >;
+    template class InterfaceCompoundField< double, gmshfem::field::Form::Form1, 2 >;
+    template class InterfaceCompoundField< double, gmshfem::field::Form::Form2, 2 >;
+    template class InterfaceCompoundField< double, gmshfem::field::Form::Form3, 2 >;
+
+
+    template class InterfaceCompoundField< std::complex< float >, gmshfem::field::Form::Form0, 2 >;
+    template class InterfaceCompoundField< std::complex< float >, gmshfem::field::Form::Form1, 2 >;
+    template class InterfaceCompoundField< std::complex< float >, gmshfem::field::Form::Form2, 2 >;
+    template class InterfaceCompoundField< std::complex< float >, gmshfem::field::Form::Form3, 2 >;
+
+    template class InterfaceCompoundField< float, gmshfem::field::Form::Form0, 2 >;
+    template class InterfaceCompoundField< float, gmshfem::field::Form::Form1, 2 >;
+    template class InterfaceCompoundField< float, gmshfem::field::Form::Form2, 2 >;
+    template class InterfaceCompoundField< float, gmshfem::field::Form::Form3, 2 >;
+    
+    
+    
+    template class InterfaceCompoundField< std::complex< double >, gmshfem::field::Form::Form0, 3 >;
+    template class InterfaceCompoundField< std::complex< double >, gmshfem::field::Form::Form1, 3 >;
+    template class InterfaceCompoundField< std::complex< double >, gmshfem::field::Form::Form2, 3 >;
+    template class InterfaceCompoundField< std::complex< double >, gmshfem::field::Form::Form3, 3 >;
+
+    template class InterfaceCompoundField< double, gmshfem::field::Form::Form0, 3 >;
+    template class InterfaceCompoundField< double, gmshfem::field::Form::Form1, 3 >;
+    template class InterfaceCompoundField< double, gmshfem::field::Form::Form2, 3 >;
+    template class InterfaceCompoundField< double, gmshfem::field::Form::Form3, 3 >;
+
+
+    template class InterfaceCompoundField< std::complex< float >, gmshfem::field::Form::Form0, 3 >;
+    template class InterfaceCompoundField< std::complex< float >, gmshfem::field::Form::Form1, 3 >;
+    template class InterfaceCompoundField< std::complex< float >, gmshfem::field::Form::Form2, 3 >;
+    template class InterfaceCompoundField< std::complex< float >, gmshfem::field::Form::Form3, 3 >;
+
+    template class InterfaceCompoundField< float, gmshfem::field::Form::Form0, 3 >;
+    template class InterfaceCompoundField< float, gmshfem::field::Form::Form1, 3 >;
+    template class InterfaceCompoundField< float, gmshfem::field::Form::Form2, 3 >;
+    template class InterfaceCompoundField< float, gmshfem::field::Form::Form3, 3 >;
+
+
+  } // namespace field
+
+
+} // namespace gmshddm
diff --git a/src/field/InterfaceCompoundField.h b/src/field/InterfaceCompoundField.h
new file mode 100644
index 00000000..44d1780a
--- /dev/null
+++ b/src/field/InterfaceCompoundField.h
@@ -0,0 +1,55 @@
+// GmshDDM - Copyright (C) 2019-2021, A. Royer, C. Geuzaine, Université de Liège
+//
+// See the LICENSE.txt file for license information. Please report all
+// issues on https://gitlab.onelab.info/gmsh/ddm/issues
+
+#ifndef H_GMSHDDM_INTERFACECOMPOUNDFIELD
+#define H_GMSHDDM_INTERFACECOMPOUNDFIELD
+
+#include "Interface.h"
+#include "InterfaceFieldInterface.h"
+
+#include <gmshfem/FieldInterface.h>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+
+namespace gmshddm
+{
+
+
+  namespace field
+  {
+
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    class InterfaceCompoundField : public InterfaceFieldInterface< T_Scalar >
+    {
+      std::vector< std::unordered_map< unsigned int, gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields > > > _fields;
+
+     public:
+      InterfaceCompoundField();
+      InterfaceCompoundField(const std::string &name, const domain::Interface &domains, const gmshfem::field::FunctionSpaceOfForm< T_Form > &type, const unsigned int degree = 1);
+      InterfaceCompoundField(const std::string &name, const domain::Interface &domains, const gmshfem::field::FunctionSpaceOfForm< T_Form > &type, const std::vector<unsigned int> & degree);
+      InterfaceCompoundField(const InterfaceCompoundField< T_Scalar, T_Form, T_NumFields > &other);
+      InterfaceCompoundField(InterfaceCompoundField< T_Scalar, T_Form, T_NumFields > &&other);
+      ~InterfaceCompoundField();
+
+      InterfaceCompoundField &operator=(const InterfaceCompoundField< T_Scalar, T_Form, T_NumFields > &other);
+
+      gmshfem::field::Form form() const;
+
+      bool isDefined(const unsigned int i, const unsigned int j) const override;
+      const gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields > &operator()(const unsigned int i, const unsigned int j) const override;
+      gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields > &operator()(const unsigned int i, const unsigned int j) override;
+    };
+
+
+  } // namespace field
+
+
+} // namespace gmshddm
+
+
+#endif // H_GMSHDDM_INTERFACECOMPOUNDFIELD
diff --git a/src/field/InterfaceField.cpp b/src/field/InterfaceField.cpp
index 2a1f8959..305c78ec 100644
--- a/src/field/InterfaceField.cpp
+++ b/src/field/InterfaceField.cpp
@@ -14,37 +14,6 @@ namespace gmshddm
   namespace field
   {
 
-    //
-    // class InterfaceFieldInterface
-    //
-
-    template< class T_Scalar >
-    InterfaceFieldInterface< T_Scalar >::InterfaceFieldInterface(const std::string &name) :
-      _name(name)
-    {
-    }
-
-    template< class T_Scalar >
-    InterfaceFieldInterface< T_Scalar >::~InterfaceFieldInterface()
-    {
-    }
-
-    template< class T_Scalar >
-    std::string InterfaceFieldInterface< T_Scalar >::name() const
-    {
-      return _name;
-    }
-
-
-    template class InterfaceFieldInterface< std::complex< double > >;
-    template class InterfaceFieldInterface< double >;
-    template class InterfaceFieldInterface< std::complex< float > >;
-    template class InterfaceFieldInterface< float >;
-
-
-    //
-    // class InterfaceField
-    //
 
     template< class T_Scalar, gmshfem::field::Form T_Form >
     InterfaceField< T_Scalar, T_Form >::InterfaceField() :
@@ -64,19 +33,18 @@ namespace gmshddm
     }
 
     template< class T_Scalar, gmshfem::field::Form T_Form >
- InterfaceField< T_Scalar, T_Form >::InterfaceField(const std::string &name, const domain::Interface &domains, const gmshfem::field::FunctionSpaceOfForm< T_Form > &type,const std::vector<unsigned int> & degree) :
-   InterfaceFieldInterface< T_Scalar >(name), _fields(domains.numberOfSubdomains())
- {
-
-   if(domains.numberOfSubdomains() > degree.size()) {
-     throw gmshfem::common::Exception("Wrong size of degree");
-   }
-   for(unsigned int i = 0; i < domains.numberOfSubdomains(); ++i) {
-     for(auto it = domains[i].begin(); it != domains[i].end(); ++it) {
-       _fields[i].insert(std::make_pair(it->first, gmshfem::field::Field< T_Scalar, T_Form >(this->_name + "_" + std::to_string(i) + "_" + std::to_string(it->first), it->second, type, degree[i])));
-     }
-   }
- }
+    InterfaceField< T_Scalar, T_Form >::InterfaceField(const std::string &name, const domain::Interface &domains, const gmshfem::field::FunctionSpaceOfForm< T_Form > &type,const std::vector<unsigned int> & degree) :
+      InterfaceFieldInterface< T_Scalar >(name), _fields(domains.numberOfSubdomains())
+    {
+      if(domains.numberOfSubdomains() > degree.size()) {
+        throw gmshfem::common::Exception("Wrong size of degree");
+      }
+      for(unsigned int i = 0; i < domains.numberOfSubdomains(); ++i) {
+        for(auto it = domains[i].begin(); it != domains[i].end(); ++it) {
+          _fields[i].insert(std::make_pair(it->first, gmshfem::field::Field< T_Scalar, T_Form >(this->_name + "_" + std::to_string(i) + "_" + std::to_string(it->first), it->second, type, degree[i])));
+        }
+      }
+    }
 
     template< class T_Scalar, gmshfem::field::Form T_Form >
     InterfaceField< T_Scalar, T_Form >::InterfaceField(const InterfaceField< T_Scalar, T_Form > &other) :
diff --git a/src/field/InterfaceField.h b/src/field/InterfaceField.h
index 0b6068db..c18adee8 100644
--- a/src/field/InterfaceField.h
+++ b/src/field/InterfaceField.h
@@ -7,6 +7,7 @@
 #define H_GMSHDDM_INTERFACEFIELD
 
 #include "Interface.h"
+#include "InterfaceFieldInterface.h"
 
 #include <gmshfem/FieldInterface.h>
 #include <string>
@@ -21,22 +22,6 @@ namespace gmshddm
   namespace field
   {
 
-    template< class T_Scalar >
-    class InterfaceFieldInterface
-    {
-     protected:
-      std::string _name;
-
-     public:
-      InterfaceFieldInterface(const std::string &name = "");
-      virtual ~InterfaceFieldInterface();
-
-      virtual bool isDefined(const unsigned int i, const unsigned int j) const = 0;
-      virtual const gmshfem::field::FieldInterface< T_Scalar > &operator()(const unsigned int i, const unsigned int j) const = 0;
-      virtual gmshfem::field::FieldInterface< T_Scalar > &operator()(const unsigned int i, const unsigned int j) = 0;
-
-      std::string name() const;
-    };
 
     template< class T_Scalar, gmshfem::field::Form T_Form >
     class InterfaceField : public InterfaceFieldInterface< T_Scalar >
diff --git a/src/field/InterfaceFieldInterface.cpp b/src/field/InterfaceFieldInterface.cpp
new file mode 100644
index 00000000..fec64474
--- /dev/null
+++ b/src/field/InterfaceFieldInterface.cpp
@@ -0,0 +1,45 @@
+// GmshDDM - Copyright (C) 2019-2021, A. Royer, C. Geuzaine, Université de Liège
+//
+// See the LICENSE.txt file for license information. Please report all
+// issues on https://gitlab.onelab.info/gmsh/ddm/issues
+
+#include "InterfaceFieldInterface.h"
+
+#include <gmshfem/Exception.h>
+
+namespace gmshddm
+{
+
+
+  namespace field
+  {
+  
+
+    template< class T_Scalar >
+    InterfaceFieldInterface< T_Scalar >::InterfaceFieldInterface(const std::string &name) :
+      _name(name)
+    {
+    }
+
+    template< class T_Scalar >
+    InterfaceFieldInterface< T_Scalar >::~InterfaceFieldInterface()
+    {
+    }
+
+    template< class T_Scalar >
+    std::string InterfaceFieldInterface< T_Scalar >::name() const
+    {
+      return _name;
+    }
+
+
+    template class InterfaceFieldInterface< std::complex< double > >;
+    template class InterfaceFieldInterface< double >;
+    template class InterfaceFieldInterface< std::complex< float > >;
+    template class InterfaceFieldInterface< float >;
+
+
+  } // namespace field
+
+
+} // namespace gmshddm
diff --git a/src/field/InterfaceFieldInterface.h b/src/field/InterfaceFieldInterface.h
new file mode 100644
index 00000000..5d8c769d
--- /dev/null
+++ b/src/field/InterfaceFieldInterface.h
@@ -0,0 +1,48 @@
+// GmshDDM - Copyright (C) 2019-2021, A. Royer, C. Geuzaine, Université de Liège
+//
+// See the LICENSE.txt file for license information. Please report all
+// issues on https://gitlab.onelab.info/gmsh/ddm/issues
+
+#ifndef H_GMSHDDM_INTERFACEFIELDINTERFACE
+#define H_GMSHDDM_INTERFACEFIELDINTERFACE
+
+#include "Interface.h"
+
+#include <gmshfem/FieldInterface.h>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+
+namespace gmshddm
+{
+
+
+  namespace field
+  {
+
+    template< class T_Scalar >
+    class InterfaceFieldInterface
+    {
+     protected:
+      std::string _name;
+
+     public:
+      InterfaceFieldInterface(const std::string &name = "");
+      virtual ~InterfaceFieldInterface();
+
+      virtual bool isDefined(const unsigned int i, const unsigned int j) const = 0;
+      virtual const gmshfem::field::FieldInterface< T_Scalar > &operator()(const unsigned int i, const unsigned int j) const = 0;
+      virtual gmshfem::field::FieldInterface< T_Scalar > &operator()(const unsigned int i, const unsigned int j) = 0;
+
+      std::string name() const;
+    };
+
+
+  } // namespace field
+
+
+} // namespace gmshddm
+
+
+#endif // H_GMSHDDM_INTERFACEFIELDINTERFACE
diff --git a/src/field/SubdomainCompoundField.cpp b/src/field/SubdomainCompoundField.cpp
new file mode 100644
index 00000000..6a7253a3
--- /dev/null
+++ b/src/field/SubdomainCompoundField.cpp
@@ -0,0 +1,133 @@
+// GmshDDM - Copyright (C) 2019-2021, A. Royer, C. Geuzaine, Université de Liège
+//
+// See the LICENSE.txt file for license information. Please report all
+// issues on https://gitlab.onelab.info/gmsh/ddm/issues
+
+#include "SubdomainCompoundField.h"
+
+#include <gmshfem/Exception.h>
+#include <string>
+
+namespace gmshddm
+{
+
+
+  namespace field
+  {
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    SubdomainCompoundField< T_Scalar, T_Form, T_NumFields >::SubdomainCompoundField() :
+      _name(), _fields()
+    {
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    SubdomainCompoundField< T_Scalar, T_Form, T_NumFields >::SubdomainCompoundField(const std::string &name, const domain::Subdomain &domains, const gmshfem::field::FunctionSpaceOfForm< T_Form > &type, const unsigned int degree) :
+      _name(name), _fields()
+    {
+      for(auto i = 0U; i < domains.numberOfSubdomains(); ++i) {
+        _fields.push_back(gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields >(_name + "_" + std::to_string(i), domains(i), type, degree));
+      }
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    SubdomainCompoundField< T_Scalar, T_Form, T_NumFields >::SubdomainCompoundField(const SubdomainCompoundField< T_Scalar, T_Form, T_NumFields > &other) :
+      _name(other._name), _fields(other._fields)
+    {
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    SubdomainCompoundField< T_Scalar, T_Form, T_NumFields >::SubdomainCompoundField(SubdomainCompoundField< T_Scalar, T_Form, T_NumFields > &&other) :
+      _name(std::move(other._name)), _fields(std::move(other._fields))
+    {
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    SubdomainCompoundField< T_Scalar, T_Form, T_NumFields > &SubdomainCompoundField< T_Scalar, T_Form, T_NumFields >::operator=(const SubdomainCompoundField< T_Scalar, T_Form, T_NumFields > &other)
+    {
+      _name = other._name;
+      _fields = other._fields;
+      return *this;
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    SubdomainCompoundField< T_Scalar, T_Form, T_NumFields >::~SubdomainCompoundField()
+    {
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    gmshfem::field::Form SubdomainCompoundField< T_Scalar, T_Form, T_NumFields >::form() const
+    {
+      return T_Form;
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    const gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields > &SubdomainCompoundField< T_Scalar, T_Form, T_NumFields >::operator()(const unsigned int i) const
+    {
+      if(i >= _fields.size()) {
+        throw gmshfem::common::Exception("Trying to access compound field(" + std::to_string(i) + ") of compound field '" + _name + "'");
+      }
+
+      return _fields[i];
+    }
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields > &SubdomainCompoundField< T_Scalar, T_Form, T_NumFields >::operator()(const unsigned int i)
+    {
+      if(i >= _fields.size()) {
+        throw gmshfem::common::Exception("Trying to access compound field(" + std::to_string(i) + ") of compound field '" + _name + "'");
+      }
+
+      return _fields[i];
+    }
+
+
+    template class SubdomainCompoundField< std::complex< double >, gmshfem::field::Form::Form0, 2 >;
+    template class SubdomainCompoundField< std::complex< double >, gmshfem::field::Form::Form1, 2 >;
+    template class SubdomainCompoundField< std::complex< double >, gmshfem::field::Form::Form2, 2 >;
+    template class SubdomainCompoundField< std::complex< double >, gmshfem::field::Form::Form3, 2 >;
+
+    template class SubdomainCompoundField< double, gmshfem::field::Form::Form0, 2 >;
+    template class SubdomainCompoundField< double, gmshfem::field::Form::Form1, 2 >;
+    template class SubdomainCompoundField< double, gmshfem::field::Form::Form2, 2 >;
+    template class SubdomainCompoundField< double, gmshfem::field::Form::Form3, 2 >;
+
+
+    template class SubdomainCompoundField< std::complex< float >, gmshfem::field::Form::Form0, 2 >;
+    template class SubdomainCompoundField< std::complex< float >, gmshfem::field::Form::Form1, 2 >;
+    template class SubdomainCompoundField< std::complex< float >, gmshfem::field::Form::Form2, 2 >;
+    template class SubdomainCompoundField< std::complex< float >, gmshfem::field::Form::Form3, 2 >;
+
+    template class SubdomainCompoundField< float, gmshfem::field::Form::Form0, 2 >;
+    template class SubdomainCompoundField< float, gmshfem::field::Form::Form1, 2 >;
+    template class SubdomainCompoundField< float, gmshfem::field::Form::Form2, 2 >;
+    template class SubdomainCompoundField< float, gmshfem::field::Form::Form3, 2 >;
+    
+    
+    
+    template class SubdomainCompoundField< std::complex< double >, gmshfem::field::Form::Form0, 3 >;
+    template class SubdomainCompoundField< std::complex< double >, gmshfem::field::Form::Form1, 3 >;
+    template class SubdomainCompoundField< std::complex< double >, gmshfem::field::Form::Form2, 3 >;
+    template class SubdomainCompoundField< std::complex< double >, gmshfem::field::Form::Form3, 3 >;
+
+    template class SubdomainCompoundField< double, gmshfem::field::Form::Form0, 3 >;
+    template class SubdomainCompoundField< double, gmshfem::field::Form::Form1, 3 >;
+    template class SubdomainCompoundField< double, gmshfem::field::Form::Form2, 3 >;
+    template class SubdomainCompoundField< double, gmshfem::field::Form::Form3, 3 >;
+
+
+    template class SubdomainCompoundField< std::complex< float >, gmshfem::field::Form::Form0, 3 >;
+    template class SubdomainCompoundField< std::complex< float >, gmshfem::field::Form::Form1, 3 >;
+    template class SubdomainCompoundField< std::complex< float >, gmshfem::field::Form::Form2, 3 >;
+    template class SubdomainCompoundField< std::complex< float >, gmshfem::field::Form::Form3, 3 >;
+
+    template class SubdomainCompoundField< float, gmshfem::field::Form::Form0, 3 >;
+    template class SubdomainCompoundField< float, gmshfem::field::Form::Form1, 3 >;
+    template class SubdomainCompoundField< float, gmshfem::field::Form::Form2, 3 >;
+    template class SubdomainCompoundField< float, gmshfem::field::Form::Form3, 3 >;
+
+
+  } // namespace field
+
+
+} // namespace gmshddm
diff --git a/src/field/SubdomainCompoundField.h b/src/field/SubdomainCompoundField.h
new file mode 100644
index 00000000..eb4bd745
--- /dev/null
+++ b/src/field/SubdomainCompoundField.h
@@ -0,0 +1,53 @@
+// GmshDDM - Copyright (C) 2019-2021, A. Royer, C. Geuzaine, Université de Liège
+//
+// See the LICENSE.txt file for license information. Please report all
+// issues on https://gitlab.onelab.info/gmsh/ddm/issues
+
+#ifndef H_GMSHDDM_SUBDOMAINCOMPOUNDFIELD
+#define H_GMSHDDM_SUBDOMAINCOMPOUNDFIELD
+
+#include "Subdomain.h"
+
+#include <gmshfem/FieldInterface.h>
+#include <string>
+#include <vector>
+
+
+namespace gmshddm
+{
+
+
+  namespace field
+  {
+
+
+    template< class T_Scalar, gmshfem::field::Form T_Form, unsigned int T_NumFields >
+    class SubdomainCompoundField
+    {
+     private:
+      std::string _name;
+      std::vector< gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields > > _fields;
+
+     public:
+      SubdomainCompoundField();
+      SubdomainCompoundField(const std::string &name, const domain::Subdomain &domains, const gmshfem::field::FunctionSpaceOfForm< T_Form > &type, const unsigned int degree = 1);
+      SubdomainCompoundField(const SubdomainCompoundField< T_Scalar, T_Form, T_NumFields > &other);
+      SubdomainCompoundField(SubdomainCompoundField< T_Scalar, T_Form, T_NumFields > &&other);
+      ~SubdomainCompoundField();
+
+      SubdomainCompoundField &operator=(const SubdomainCompoundField< T_Scalar, T_Form, T_NumFields > &other);
+
+      gmshfem::field::Form form() const;
+
+      const gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields > &operator()(const unsigned int i) const;
+      gmshfem::field::CompoundField< T_Scalar, T_Form, T_NumFields > &operator()(const unsigned int i);
+    };
+
+
+  } // namespace field
+
+
+} // namespace gmshddm
+
+
+#endif // H_GMSHDDM_SUBDOMAINCOMPOUNDFIELD
diff --git a/src/field/SubdomainField.h b/src/field/SubdomainField.h
index e0839eed..2dda8bed 100644
--- a/src/field/SubdomainField.h
+++ b/src/field/SubdomainField.h
@@ -3,8 +3,8 @@
 // See the LICENSE.txt file for license information. Please report all
 // issues on https://gitlab.onelab.info/gmsh/ddm/issues
 
-#ifndef H_GMSHDDM_VOLUMEFIELD
-#define H_GMSHDDM_VOLUMEFIELD
+#ifndef H_GMSHDDM_SUBDOMAINFIELD
+#define H_GMSHDDM_SUBDOMAINFIELD
 
 #include "Subdomain.h"
 
@@ -50,4 +50,4 @@ namespace gmshddm
 } // namespace gmshddm
 
 
-#endif // H_GMSHDDM_VOLUMEFIELD
+#endif // H_GMSHDDM_SUBDOMAINFIELD
-- 
GitLab