From 4443321275eba8e6dcf6013b867abe39607f6a57 Mon Sep 17 00:00:00 2001
From: Sebastiaan van der Tol <tol@astron.nl>
Date: Fri, 31 Jan 2020 12:17:01 +0100
Subject: [PATCH] use Element and AntennaModel as basic building blocks

---
 Antenna.h                                  |  31 +++
 ElementResponseModel.cc => AntennaModel.cc |   2 +-
 AntennaModel.h                             |  47 +++++
 BeamFormer.h                               |  24 +++
 CMakeLists.txt                             |  95 +++++-----
 Constants.h                                |   3 -
 Element.h                                  |  21 +++
 ElementResponse.h                          |  17 --
 ElementResponseModel.h                     |  15 --
 LofarMetaDataUtil.h                        |   2 +-
 MathUtil.cc                                |   3 -
 MathUtil.h                                 |   3 -
 MutablePtr.h                               |  11 +-
 Singleton.h                                |   6 +-
 Station.cc                                 | 210 ++++++++++-----------
 Station.h                                  |  44 ++---
 Types.cc                                   |   3 -
 Types.h                                    |   3 -
 hamaker/HamakerElementResponse.cc          |  23 ++-
 hamaker/HamakerElementResponse.h           |  10 +-
 lobes/LOBESElementResponse.cc              |  25 +++
 lobes/LOBESElementResponse.h               |  22 +++
 oskar/OSKARElementResponse.cc              |  33 ++++
 oskar/OSKARElementResponse.h               |  22 +++
 24 files changed, 439 insertions(+), 236 deletions(-)
 create mode 100644 Antenna.h
 rename ElementResponseModel.cc => AntennaModel.cc (91%)
 create mode 100644 AntennaModel.h
 create mode 100644 BeamFormer.h
 create mode 100644 Element.h
 delete mode 100644 ElementResponse.h
 delete mode 100644 ElementResponseModel.h
 create mode 100644 lobes/LOBESElementResponse.cc
 create mode 100644 lobes/LOBESElementResponse.h
 create mode 100644 oskar/OSKARElementResponse.cc
 create mode 100644 oskar/OSKARElementResponse.h

diff --git a/Antenna.h b/Antenna.h
new file mode 100644
index 00000000..ca671dbf
--- /dev/null
+++ b/Antenna.h
@@ -0,0 +1,31 @@
+#ifndef ANTENNA_H
+#define ANTENNA_H
+
+#include <complex>
+
+class Antenna : public Element
+{
+public:
+
+    Antenna(int id, AntennaModel::Ptr model) :
+        m_id(id),
+        m_model(model)
+    {}
+
+    virtual void response(
+        double time,
+        double freq,
+        double theta,
+        double phi,
+        std::complex<double> (&result)[2][2]) override
+    {
+        m_antenna_model->response(freq, theta, phi, std::complex<double> (&result)[2][2]);
+    }
+
+private:
+    int m_antenna_id;
+    AntennaModel::Ptr m_antenna_model;
+
+};
+
+#endif
diff --git a/ElementResponseModel.cc b/AntennaModel.cc
similarity index 91%
rename from ElementResponseModel.cc
rename to AntennaModel.cc
index fde636c4..556dfb56 100644
--- a/ElementResponseModel.cc
+++ b/AntennaModel.cc
@@ -1,4 +1,4 @@
-#include "ElementResponseModel.h"
+#include "AntennaModel.h"
 
 std::ostream& operator<<(std::ostream& os, ElementResponseModel model)
 {
diff --git a/AntennaModel.h b/AntennaModel.h
new file mode 100644
index 00000000..ae6b87f4
--- /dev/null
+++ b/AntennaModel.h
@@ -0,0 +1,47 @@
+#ifndef ANTENNAMODEL_H
+#define ANTENNAMODEL_H
+
+#include <complex>
+#include <ostream>
+
+#include "MutablePtr.h"
+
+namespace StationResponse
+{
+
+enum AntennaModelID {
+    Unknown,
+    Hamaker,
+    LOBES,
+    OSKAR
+};
+
+std::ostream& operator<<(std::ostream& os, AntennaModelID model);
+
+class AntennaModel
+{
+public:
+
+    typedef MutablePtr<AntennaModel> Ptr;
+
+    virtual void response(
+        double freq,
+        double theta,
+        double phi,
+        std::complex<double> (&result)[2][2]) const = 0;
+
+    virtual void response(
+        int    element_id,
+        double freq,
+        double theta,
+        double phi,
+        std::complex<double> (&result)[2][2]) const
+    {
+        response(freq, theta, phi, result);
+    }
+
+};
+
+} // namespace StationResponse
+
+#endif
diff --git a/BeamFormer.h b/BeamFormer.h
new file mode 100644
index 00000000..bd724d41
--- /dev/null
+++ b/BeamFormer.h
@@ -0,0 +1,24 @@
+#ifndef BEAMFORMER_H
+#define BEAMFORMER_H
+
+#include <complex>
+
+class BeamFormer : public Element
+{
+public:
+
+    virtual void response(
+        double time,
+        double freq,
+        double theta,
+        double phi,
+        std::complex<double> (&result)[2][2]) override;
+
+    add_element(Element::Ptr element) {m_elements->insert(element);}
+
+private:
+    std::vector<Element::Ptr> m_elements;
+
+};
+
+#endif
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5596166d..43a8a241 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,20 +29,21 @@ include_directories(${CASACORE_INCLUDE_DIR})
 add_compile_options(-std=c++11 -Wall -DNDEBUG -Wl,--no-undefined)
 
 add_library(stationresponse SHARED
-  AntennaField.cc
-  AntennaFieldHBA.cc
-  AntennaFieldLBA.cc
-  AntennaModelHBA.cc
-  AntennaModelLBA.cc
-  DualDipoleAntenna.cc
-  ElementResponseModel.cc
-  ITRFConverter.cc
-  ITRFDirection.cc
-  LofarMetaDataUtil.cc
-  MathUtil.cc
+#   AntennaField.cc
+#   AntennaFieldHBA.cc
+#   AntennaFieldLBA.cc
+#   AntennaModelHBA.cc
+#   AntennaModelLBA.cc
+#   DualDipoleAntenna.cc
+#   ElementResponseModel.cc
+#   ITRFConverter.cc
+#   ITRFDirection.cc
+#   LofarMetaDataUtil.cc
+#   MathUtil.cc
   Station.cc
-  TileAntenna.cc
-  Types.cc)
+#   TileAntenna.cc
+  Types.cc
+  )
 
 set_target_properties(stationresponse PROPERTIES VERSION 3)
 
@@ -80,37 +81,37 @@ elseif(DOXYGEN_FOUND)
 
 endif(DOXYGEN_FOUND)
 
-find_package (Python COMPONENTS Development)
-message("Compiling Python ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} support. If this is not the intended target use 'DPYTHON_EXECUTABLE' to control.")
-# bind against boost-python for compilation of the python API
-# depending on major release version of the python libraries
-if (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
-  find_package (Boost REQUIRED COMPONENTS python numpy)
-  find_package (Casacore REQUIRED COMPONENTS python)
-  message(STATUS "Boost python library: ${Boost_PYTHON_LIBRARY}")
-  message(STATUS "Boost numpy library: ${Boost_NUMPY_LIBRARY}")
-  message(STATUS "Python library ${PYTHON_LIBRARIES}")
-  set(BOOST_PY_FOUND TRUE)
-else (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
-  find_package (Boost REQUIRED COMPONENTS python numpy)
-  find_package (Casacore REQUIRED COMPONENTS python3)
-  message(STATUS "Boost python library: ${Boost_PYTHON3_LIBRARY}")
-  message(STATUS "Boost numpy library: ${Boost_NUMPY3_LIBRARY}")
-  message(STATUS "Python library ${PYTHON_LIBRARIES}")
-  set(BOOST_PY_FOUND TRUE)
-endif (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
-
-
-if(BOOST_PY_FOUND)
-    add_library(_stationresponse MODULE pystationresponse.cc)
-    set_target_properties(_stationresponse PROPERTIES PREFIX "")
-    target_include_directories(_stationresponse PRIVATE ${PYTHON_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
-    if (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
-      target_link_libraries(_stationresponse stationresponse ${CASA_PYTHON_LIBRARY} ${Boost_PYTHON_LIBRARY} ${Boost_NUMPY_LIBRARY} ${PYTHON_LIBRARIES})
-    else (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
-      target_link_libraries(_stationresponse stationresponse ${CASA_PYTHON3_LIBRARY} ${Boost_PYTHON3_LIBRARY} ${Boost_NUMPY3_LIBRARY} ${PYTHON_LIBRARIES})
-    endif (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
-    install(TARGETS _stationresponse DESTINATION ${PYTHON_INSTALL_DIR}/lofar/stationresponse)
-    install(FILES __init__.py DESTINATION ${PYTHON_INSTALL_DIR}/lofar/stationresponse)
-endif(BOOST_PY_FOUND)
-
+# find_package (Python COMPONENTS Development)
+# message("Compiling Python ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR} support. If this is not the intended target use 'DPYTHON_EXECUTABLE' to control.")
+# # bind against boost-python for compilation of the python API
+# # depending on major release version of the python libraries
+# if (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
+#   find_package (Boost REQUIRED COMPONENTS python numpy)
+#   find_package (Casacore REQUIRED COMPONENTS python)
+#   message(STATUS "Boost python library: ${Boost_PYTHON_LIBRARY}")
+#   message(STATUS "Boost numpy library: ${Boost_NUMPY_LIBRARY}")
+#   message(STATUS "Python library ${PYTHON_LIBRARIES}")
+#   set(BOOST_PY_FOUND TRUE)
+# else (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
+#   find_package (Boost REQUIRED COMPONENTS python numpy)
+#   find_package (Casacore REQUIRED COMPONENTS python3)
+#   message(STATUS "Boost python library: ${Boost_PYTHON3_LIBRARY}")
+#   message(STATUS "Boost numpy library: ${Boost_NUMPY3_LIBRARY}")
+#   message(STATUS "Python library ${PYTHON_LIBRARIES}")
+#   set(BOOST_PY_FOUND TRUE)
+# endif (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
+#
+#
+# if(BOOST_PY_FOUND)
+#     add_library(_stationresponse MODULE pystationresponse.cc)
+#     set_target_properties(_stationresponse PROPERTIES PREFIX "")
+#     target_include_directories(_stationresponse PRIVATE ${PYTHON_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
+#     if (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
+#       target_link_libraries(_stationresponse stationresponse ${CASA_PYTHON_LIBRARY} ${Boost_PYTHON_LIBRARY} ${Boost_NUMPY_LIBRARY} ${PYTHON_LIBRARIES})
+#     else (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
+#       target_link_libraries(_stationresponse stationresponse ${CASA_PYTHON3_LIBRARY} ${Boost_PYTHON3_LIBRARY} ${Boost_NUMPY3_LIBRARY} ${PYTHON_LIBRARIES})
+#     endif (${PYTHON_VERSION_MAJOR} VERSION_LESS "3")
+#     install(TARGETS _stationresponse DESTINATION ${PYTHON_INSTALL_DIR}/lofar/stationresponse)
+#     install(FILES __init__.py DESTINATION ${PYTHON_INSTALL_DIR}/lofar/stationresponse)
+# endif(BOOST_PY_FOUND)
+#
diff --git a/Constants.h b/Constants.h
index 4bb1ce4e..c299bf18 100644
--- a/Constants.h
+++ b/Constants.h
@@ -28,8 +28,6 @@
 
 #include "Types.h"
 
-namespace LOFAR
-{
 namespace StationResponse
 {
 
@@ -55,6 +53,5 @@ const real_t c = 2.99792458e+08;
 // @}
 
 } //# namespace StationResponse
-} //# namespace LOFAR
 
 #endif
diff --git a/Element.h b/Element.h
new file mode 100644
index 00000000..8cdfe5b0
--- /dev/null
+++ b/Element.h
@@ -0,0 +1,21 @@
+#ifndef ELEMENT_H
+#define ELEMENT_H
+
+#include <complex>
+
+class Element
+{
+public:
+
+    virtual void response(
+        double time,
+        double freq,
+        double theta,
+        double phi,
+        std::complex<double> (&result)[2][2]) const = 0;
+
+    double m_position[3];
+
+};
+
+#endif
diff --git a/ElementResponse.h b/ElementResponse.h
deleted file mode 100644
index 05bbbca3..00000000
--- a/ElementResponse.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef ELEMENT_RESPONSE_H
-#define ELEMENT_RESPONSE_H
-
-#include <complex>
-#include "Response.h"
-
-class ElementResponse : private Response
-{
-public:
-    virtual void element_response(
-        double freq,
-        double theta,
-        double phi,
-        std::complex<double> (&response)[2][2]) const = 0;
-};
-
-#endif
diff --git a/ElementResponseModel.h b/ElementResponseModel.h
deleted file mode 100644
index 444a8773..00000000
--- a/ElementResponseModel.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef ELEMENT_RESPONSE_MODEL_H
-#define ELEMENT_RESPONSE_MODEL_H
-
-#include <ostream>
-
-enum ElementResponseModel {
-    Unknown,
-    Hamaker,
-    LOBES,
-    OSKAR
-};
-
-std::ostream& operator<<(std::ostream& os, ElementResponseModel model);
-
-#endif
diff --git a/LofarMetaDataUtil.h b/LofarMetaDataUtil.h
index c73bd97e..e30fbeab 100644
--- a/LofarMetaDataUtil.h
+++ b/LofarMetaDataUtil.h
@@ -29,7 +29,7 @@
 // LOFAR observations stored in MS format.
 
 #include "Station.h"
-#include "ElementResponseModel.h"
+#include "AntennaModel.h"
 
 #include <casacore/ms/MeasurementSets/MeasurementSet.h>
 #include <casacore/ms/MeasurementSets/MSAntennaColumns.h>
diff --git a/MathUtil.cc b/MathUtil.cc
index 5f352dde..66b5d12b 100644
--- a/MathUtil.cc
+++ b/MathUtil.cc
@@ -22,10 +22,7 @@
 
 #include "MathUtil.h"
 
-namespace LOFAR
-{
 namespace StationResponse
 {
 
 } //# namespace StationResponse
-} //# namespace LOFAR
diff --git a/MathUtil.h b/MathUtil.h
index 487183e5..a25dfd92 100644
--- a/MathUtil.h
+++ b/MathUtil.h
@@ -29,8 +29,6 @@
 #include "Constants.h"
 #include "Types.h"
 
-namespace LOFAR
-{
 namespace StationResponse
 {
 
@@ -166,6 +164,5 @@ inline diag22c_t normalize(const raw_array_factor_t &raw)
 // @}
 
 } //# namespace StationResponse
-} //# namespace LOFAR
 
 #endif
diff --git a/MutablePtr.h b/MutablePtr.h
index 09dbb2c4..42863060 100644
--- a/MutablePtr.h
+++ b/MutablePtr.h
@@ -23,8 +23,8 @@
 #ifndef LOFAR_STATIONRESPONSE_MUTABLEPTR_H
 #define LOFAR_STATIONRESPONSE_MUTABLEPTR_H
 
-namespace LOFAR
-{
+#include <memory>
+
 namespace StationResponse
 {
 
@@ -74,15 +74,14 @@ namespace StationResponse
  * \endcode
  */
 template<typename T>
-class MutablePtr : public std::shared_ptr<T*> {
+class MutablePtr : public std::shared_ptr<std::shared_ptr<T>> {
 public:
-    MutablePtr(T* ptr) : std::shared_ptr<T*>(new T*(ptr)) {}
+    MutablePtr(std::shared_ptr<T> ptr) : std::shared_ptr<std::shared_ptr<T>>(new std::shared_ptr<T>(ptr)) {}
     T& operator*() const { return **(this->get()); }
     T* operator->() const { return *(this->get()); }
-    void set(T* ptr) { *(this->get()) = ptr;}
+    void set(std::shared_ptr<T> ptr) { *(this->get()) = ptr;}
 };
 
 } //# namespace StationResponse
-} //# namespace LOFAR
 
 #endif
diff --git a/Singleton.h b/Singleton.h
index 2f559bcc..4c3d7eb3 100644
--- a/Singleton.h
+++ b/Singleton.h
@@ -2,10 +2,10 @@ template<typename T>
 class Singleton
 {
     public:
-        static T& getInstance()
+        static std::shared_ptr<T> getInstance()
         {
-            static T    instance; // Guaranteed to be destroyed.
-                                  // Instantiated on first use.
+            static std::shared_ptr<T>  instance(new T()); // Guaranteed to be destroyed.
+                                                          // Instantiated on first use.
             return instance;
         }
     private:
diff --git a/Station.cc b/Station.cc
index 5dc3db51..1ac2ebd1 100644
--- a/Station.cc
+++ b/Station.cc
@@ -26,37 +26,36 @@
 #include "hamaker/HamakerElementResponse.h"
 #include "oskar/OSKARElementResponse.h"
 #include "lobes/LOBESElementResponse.h"
-#include "DualDipoleAntenna.h"
-#include "TileAntenna.h"
+// #include "DualDipoleAntenna.h"
+// #include "TileAntenna.h"
 
-namespace LOFAR
-{
 namespace StationResponse
 {
 
 Station::Station(
-    const string &name,
+    const std::string &name,
     const vector3r_t &position,
-    const ElementResponseModel model)
+    const AntennaModelID model)
     :   itsName(name),
         itsPosition(position),
         itsPhaseReference(position),
+        itsAntennaModel(nullptr)
 {
     setModel(model);
 }
 
-void Station::setModel(const ElementResponseModel model)
+void Station::setModel(const AntennaModelID model)
 {
     switch (model)
     {
         case Hamaker:
-            itsElementResponse = HamakerElementResponse.getInstance(itsName);
-            break;
-        case OSKAR:
-            itsElementResponse = OSKARElementResponse.getInstance();
+            itsAntennaModel.set(HamakerElementResponse::getInstance(itsName));
             break;
+//         case OSKAR:
+//             itsAntennaModel.set(OSKARElementResponse::getInstance());
+//             break;
         case LOBES:
-            itsElementResponse = LOBESElementResponse.getInstance();
+            itsAntennaModel.set(LOBESElementResponse::getInstance(itsName));
             break;
         default:
             std::stringstream message;
@@ -66,7 +65,7 @@ void Station::setModel(const ElementResponseModel model)
     }
 }
 
-const string &Station::name() const
+const std::string &Station::name() const
 {
     return itsName;
 }
@@ -86,53 +85,53 @@ const vector3r_t &Station::phaseReference() const
     return itsPhaseReference;
 }
 
-void Station::addField(const AntennaField::ConstPtr &field)
-{
-    itsFields.push_back(field);
-}
+// void Station::addField(const AntennaField::ConstPtr &field)
+// {
+//     itsFields.push_back(field);
+// }
 
-size_t Station::nFields() const
-{
-    return itsFields.size();
-}
+// size_t Station::nFields() const
+// {
+//     return itsFields.size();
+// }
 
-AntennaField::ConstPtr Station::field(size_t i) const
-{
-    return (i < itsFields.size() ? itsFields[i] : AntennaField::ConstPtr());
-}
+// AntennaField::ConstPtr Station::field(size_t i) const
+// {
+//     return (i < itsFields.size() ? itsFields[i] : AntennaField::ConstPtr());
+// }
 
-Station::FieldList::const_iterator Station::beginFields() const
-{
-    return itsFields.begin();
-}
+// Station::FieldList::const_iterator Station::beginFields() const
+// {
+//     return itsFields.begin();
+// }
 
-Station::FieldList::const_iterator Station::endFields() const
-{
-    return itsFields.end();
-}
+// Station::FieldList::const_iterator Station::endFields() const
+// {
+//     return itsFields.end();
+// }
 
 matrix22c_t Station::response(real_t time, real_t freq,
     const vector3r_t &direction, real_t freq0, const vector3r_t &station0,
     const vector3r_t &tile0, const bool rotate) const
 {
     raw_response_t result = {{{{{}}, {{}}}}, {{}}};
-    for(FieldList::const_iterator field_it = beginFields(),
-        field_end = endFields(); field_it != field_end; ++field_it)
-    {
-        raw_array_factor_t field = fieldArrayFactor(*field_it, time, freq,
-            direction, freq0, phaseReference(), station0);
-
-        raw_response_t antenna = (*field_it)->rawResponse(time, freq,
-            direction, tile0, rotate);
-
-        result.response[0][0] += field.factor[0] * antenna.response[0][0];
-        result.response[0][1] += field.factor[0] * antenna.response[0][1];
-        result.response[1][0] += field.factor[1] * antenna.response[1][0];
-        result.response[1][1] += field.factor[1] * antenna.response[1][1];
-
-        result.weight[0] += field.weight[0] * antenna.weight[0];
-        result.weight[1] += field.weight[1] * antenna.weight[1];
-    }
+//     for(FieldList::const_iterator field_it = beginFields(),
+//         field_end = endFields(); field_it != field_end; ++field_it)
+//     {
+//         raw_array_factor_t field = fieldArrayFactor(*field_it, time, freq,
+//             direction, freq0, phaseReference(), station0);
+//
+//         raw_response_t antenna = (*field_it)->rawResponse(time, freq,
+//             direction, tile0, rotate);
+//
+//         result.response[0][0] += field.factor[0] * antenna.response[0][0];
+//         result.response[0][1] += field.factor[0] * antenna.response[0][1];
+//         result.response[1][0] += field.factor[1] * antenna.response[1][0];
+//         result.response[1][1] += field.factor[1] * antenna.response[1][1];
+//
+//         result.weight[0] += field.weight[0] * antenna.weight[0];
+//         result.weight[1] += field.weight[1] * antenna.weight[1];
+//     }
 
     return normalize(result);
 }
@@ -142,65 +141,64 @@ diag22c_t Station::arrayFactor(real_t time, real_t freq,
     const vector3r_t &tile0) const
 {
     raw_array_factor_t af = {{{}}, {{}}};
-    for(FieldList::const_iterator field_it = beginFields(),
-        field_end = endFields(); field_it != field_end; ++field_it)
-    {
-        raw_array_factor_t field = fieldArrayFactor(*field_it, time, freq,
-            direction, freq0, phaseReference(), station0);
-
-        raw_array_factor_t antenna = (*field_it)->rawArrayFactor(time, freq,
-            direction, tile0);
-
-        af.factor[0] += field.factor[0] * antenna.factor[0];
-        af.factor[1] += field.factor[1] * antenna.factor[1];
-        af.weight[0] += field.weight[0] * antenna.weight[0];
-        af.weight[1] += field.weight[1] * antenna.weight[1];
-    }
+//     for(FieldList::const_iterator field_it = beginFields(),
+//         field_end = endFields(); field_it != field_end; ++field_it)
+//     {
+//         raw_array_factor_t field = fieldArrayFactor(*field_it, time, freq,
+//             direction, freq0, phaseReference(), station0);
+//
+//         raw_array_factor_t antenna = (*field_it)->rawArrayFactor(time, freq,
+//             direction, tile0);
+//
+//         af.factor[0] += field.factor[0] * antenna.factor[0];
+//         af.factor[1] += field.factor[1] * antenna.factor[1];
+//         af.weight[0] += field.weight[0] * antenna.weight[0];
+//         af.weight[1] += field.weight[1] * antenna.weight[1];
+//     }
 
     return normalize(af);
 }
 
-raw_array_factor_t
-Station::fieldArrayFactor(const AntennaField::ConstPtr &field,
-    real_t, real_t freq, const vector3r_t &direction, real_t freq0,
-    const vector3r_t &position0, const vector3r_t &direction0) const
-{
-    real_t k = Constants::_2pi * freq / Constants::c;
-    real_t k0 = Constants::_2pi * freq0 / Constants::c;
-
-    vector3r_t offset = field->position() - position0;
-
-    raw_array_factor_t af = {{{}}, {{}}};
-    typedef AntennaField::AntennaList AntennaList;
-    for(AntennaList::const_iterator antenna_it = field->beginAntennae(),
-        antenna_end = field->endAntennae(); antenna_it != antenna_end;
-        ++antenna_it)
-    {
-        if(!antenna_it->enabled[0] && !antenna_it->enabled[1])
-        {
-            continue;
-        }
-
-        vector3r_t position = offset + antenna_it->position;
-        real_t phase = k * dot(position, direction) - k0 * dot(position,
-            direction0);
-        complex_t shift = complex_t(cos(phase), sin(phase));
-
-        if(antenna_it->enabled[0])
-        {
-            af.factor[0] += shift;
-            ++af.weight[0];
-        }
-
-        if(antenna_it->enabled[1])
-        {
-            af.factor[1] += shift;
-            ++af.weight[1];
-        }
-    }
-
-    return af;
-}
+// raw_array_factor_t
+// Station::fieldArrayFactor(const AntennaField::ConstPtr &field,
+//     real_t, real_t freq, const vector3r_t &direction, real_t freq0,
+//     const vector3r_t &position0, const vector3r_t &direction0) const
+// {
+//     real_t k = Constants::_2pi * freq / Constants::c;
+//     real_t k0 = Constants::_2pi * freq0 / Constants::c;
+//
+//     vector3r_t offset = field->position() - position0;
+//
+//     raw_array_factor_t af = {{{}}, {{}}};
+//     typedef AntennaField::AntennaList AntennaList;
+//     for(AntennaList::const_iterator antenna_it = field->beginAntennae(),
+//         antenna_end = field->endAntennae(); antenna_it != antenna_end;
+//         ++antenna_it)
+//     {
+//         if(!antenna_it->enabled[0] && !antenna_it->enabled[1])
+//         {
+//             continue;
+//         }
+//
+//         vector3r_t position = offset + antenna_it->position;
+//         real_t phase = k * dot(position, direction) - k0 * dot(position,
+//             direction0);
+//         complex_t shift = complex_t(cos(phase), sin(phase));
+//
+//         if(antenna_it->enabled[0])
+//         {
+//             af.factor[0] += shift;
+//             ++af.weight[0];
+//         }
+//
+//         if(antenna_it->enabled[1])
+//         {
+//             af.factor[1] += shift;
+//             ++af.weight[1];
+//         }
+//     }
+//
+//     return af;
+// }
 
 } //# namespace StationResponse
-} //# namespace LOFAR
diff --git a/Station.h b/Station.h
index fb6870ac..17d418f7 100644
--- a/Station.h
+++ b/Station.h
@@ -26,28 +26,25 @@
 // \file
 // Representation of the station beam former.
 
-#include "AntennaField.h"
+#include "Element.h"
+#include "AntennaModel.h"
 #include "Types.h"
-#include "ElementResponseModel.h"
-#include "Response.h"
 
 #include <memory>
 #include <vector>
 
-namespace LOFAR
-{
 namespace StationResponse
 {
 
 // \addtogroup StationResponse
 // @{
 
-class Station : private Response
+class Station : public Element
 {
 public:
     typedef std::shared_ptr<Station>             Ptr;
     typedef std::shared_ptr<const Station>       ConstPtr;
-    typedef std::vector<AntennaField::ConstPtr>  FieldList;
+//     typedef std::vector<AntennaField::ConstPtr>  FieldList;
 
     /*!
      *  \brief Construct a new Station instance.
@@ -56,14 +53,16 @@ public:
      *  \param position Position of the station (ITRF, m).
      */
     Station(
-        const string &name,
+        const std::string &name,
         const vector3r_t &position,
-        const ElementResponseModel model);
+        const AntennaModelID model);
+
+    void setModel(const AntennaModelID model);
 
     /*!
      *  \brief Return the name of the station.
      */
-    const string &name() const;
+    const std::string &name() const;
 
     /*!
      *  \brief Return the position of the station (ITRF, m).
@@ -99,7 +98,7 @@ public:
      *
      *  Use this method to add the appropriate antenna fields to the station.
      */
-    void addField(const AntennaField::ConstPtr &field);
+//     void addField(const AntennaField::ConstPtr &field);
 
 
     /*!
@@ -114,19 +113,19 @@ public:
      *  \return An AntennaField::ConstPtr to the requested AntennaField
      *  instance, or an empty AntennaField::ConstPtr if \p i is out of bounds.
      */
-    AntennaField::ConstPtr field(size_t i) const;
+//     AntennaField::ConstPtr field(size_t i) const;
 
     /*!
      *  \brief Return an iterator that points to the beginning of the list of
      *  antenna fields.
      */
-    FieldList::const_iterator beginFields() const;
+//     FieldList::const_iterator beginFields() const;
 
     /*!
      *  \brief Return an iterator that points to the end of the list of antenna
      *  fields.
      */
-    FieldList::const_iterator endFields() const;
+//     FieldList::const_iterator endFields() const;
 
     /*!
      *  \brief Compute the response of the station for a plane wave of frequency
@@ -162,6 +161,7 @@ public:
         const;
 
     virtual void response(
+        double time,
         double freq,
         double theta,
         double phi,
@@ -307,17 +307,20 @@ public:
 
     // @}
 
+    const AntennaModel::Ptr get_antenna_model() {return itsAntennaModel;}
+
 private:
-    raw_array_factor_t fieldArrayFactor(const AntennaField::ConstPtr &field,
-        real_t time, real_t freq, const vector3r_t &direction, real_t freq0,
-        const vector3r_t &position0, const vector3r_t &direction0) const;
+//     raw_array_factor_t fieldArrayFactor(const AntennaField::ConstPtr &field,
+//         real_t time, real_t freq, const vector3r_t &direction, real_t freq0,
+//         const vector3r_t &position0, const vector3r_t &direction0) const;
 
 private:
-    string      itsName;
+    std::string itsName;
     vector3r_t  itsPosition;
     vector3r_t  itsPhaseReference;
-    FieldList   itsFields;
-    ElementResponseModel itsModel = ElementResponseModel::Unknown;
+//     FieldList   itsFields;
+    AntennaModelID itsAntennaModelID = AntennaModelID::Unknown;
+    AntennaModel::Ptr itsAntennaModel;
 };
 
 // @}
@@ -375,6 +378,5 @@ void Station::arrayFactor(unsigned int count, real_t time, T freq,
 }
 
 } //# namespace StationResponse
-} //# namespace LOFAR
 
 #endif
diff --git a/Types.cc b/Types.cc
index 872658d1..143db8f0 100644
--- a/Types.cc
+++ b/Types.cc
@@ -22,10 +22,7 @@
 
 #include "Types.h"
 
-namespace LOFAR
-{
 namespace StationResponse
 {
 
 } //# namespace StationResponse
-} //# namespace LOFAR
diff --git a/Types.h b/Types.h
index c3633f68..14a4fc4f 100644
--- a/Types.h
+++ b/Types.h
@@ -31,8 +31,6 @@
 #include <ostream>
 #include <complex>
 
-namespace LOFAR
-{
 namespace StationResponse
 {
 
@@ -110,6 +108,5 @@ std::ostream &operator<<(std::ostream &out, const std::array<T, N> &obj)
 }
 
 } //# namespace StationResponse
-} //# namespace LOFAR
 
 #endif
diff --git a/hamaker/HamakerElementResponse.cc b/hamaker/HamakerElementResponse.cc
index e64bff58..7e750ba4 100644
--- a/hamaker/HamakerElementResponse.cc
+++ b/hamaker/HamakerElementResponse.cc
@@ -2,13 +2,33 @@
 //# Functions to compute the (idealized) response of a LOFAR
 //# LBA or HBA dual dipole antenna.
 
+
+#include<stdexcept>
+
 #include "config.h"
 
 #include "HamakerElementResponse.h"
+#include "../Singleton.h"
+
+namespace StationResponse {
 
 // PI / 2.0
 const double pi_2 = 1.570796326794896619231322;
 
+std::shared_ptr<HamakerElementResponse> HamakerElementResponse::getInstance(const std::string &name)
+{
+    if (name.length() >= 3) {
+        if (name.substr(name.length()-3, 3) == "LBA") {
+            return Singleton<HamakerElementResponseLBA>::getInstance();
+        }
+        if (name.substr(name.length()-3, 3) == "HBA") {
+            return Singleton<HamakerElementResponseHBA>::getInstance();
+        }
+    }
+    throw std::invalid_argument("HamakerElementResponse::getInstance: name should end in either 'LBA' or 'HBA'");
+}
+
+
 std::string HamakerElementResponse::get_path(
     const char* filename) const
 {
@@ -18,7 +38,7 @@ std::string HamakerElementResponse::get_path(
     return ss.str();
 }
 
-void HamakerElementResponse::element_response(
+void HamakerElementResponse::response(
     double freq,
     double theta,
     double phi,
@@ -117,3 +137,4 @@ HamakerElementResponseLBA::HamakerElementResponseLBA()
     std::string path = get_path("HamakerLBACoeff.h5");
     m_coeffs.reset(new HamakerCoefficients(path));
 }
+}
diff --git a/hamaker/HamakerElementResponse.h b/hamaker/HamakerElementResponse.h
index 682e0911..48cbcb47 100644
--- a/hamaker/HamakerElementResponse.h
+++ b/hamaker/HamakerElementResponse.h
@@ -1,17 +1,20 @@
-#include "../ElementResponse.h"
+#include "../AntennaModel.h"
 #include "HamakerCoeff.h"
 
 #include <memory>
 
-class HamakerElementResponse : public ElementResponse
+namespace StationResponse {
+class HamakerElementResponse : public AntennaModel
 {
 public:
-    virtual void element_response(
+    virtual void response(
         double freq,
         double theta,
         double phi,
         std::complex<double> (&response)[2][2]) const final override;
 
+    static std::shared_ptr<HamakerElementResponse> getInstance(const std::string &name);
+
 protected:
     std::string get_path(const char*) const;
 
@@ -29,3 +32,4 @@ class HamakerElementResponseLBA : public HamakerElementResponse
 public:
     HamakerElementResponseLBA();
 };
+}
diff --git a/lobes/LOBESElementResponse.cc b/lobes/LOBESElementResponse.cc
new file mode 100644
index 00000000..139f5225
--- /dev/null
+++ b/lobes/LOBESElementResponse.cc
@@ -0,0 +1,25 @@
+#include "LOBESElementResponse.h"
+
+LOBESElementResponse::LOBESElementResponse(std::string name)
+{
+}
+
+void LOBESElementResponse::response(
+        double freq,
+        double theta,
+        double phi,
+        std::complex<double> (&response)[2][2])
+{
+}
+
+std::shared_ptr<LOBESElementResponse> LOBESElementResponse::getInstance(std::string name){
+    static std::map<std::string, std::shared_ptr<LOBESElementResponse>> name_response_map;
+
+    auto entry = name_response_map.find(name);
+    if (entry == name_response_map.end()) {
+        entry = name_response_map.insert(std::make_shared<LOBESElementResponse>(name));
+    }
+    return *entry;
+
+};
+
diff --git a/lobes/LOBESElementResponse.h b/lobes/LOBESElementResponse.h
new file mode 100644
index 00000000..f30a54fb
--- /dev/null
+++ b/lobes/LOBESElementResponse.h
@@ -0,0 +1,22 @@
+#include "../AntennaModel.h"
+
+#include <memory>
+
+namespace StationResponse {
+
+class LOBESElementResponse : public AntennaModel
+{
+public:
+
+    LOBESElementResponse(std::string name);
+
+    virtual void response(
+        double freq,
+        double theta,
+        double phi,
+        std::complex<double> (&response)[2][2]) const final override;
+
+    static std::shared_ptr<LOBESElementResponse> getInstance(std::string name);
+};
+
+} // namespace StationResponse
diff --git a/oskar/OSKARElementResponse.cc b/oskar/OSKARElementResponse.cc
new file mode 100644
index 00000000..064b863d
--- /dev/null
+++ b/oskar/OSKARElementResponse.cc
@@ -0,0 +1,33 @@
+#include "OSKARElementResponse.h"
+
+#include "oskar_vector_types.h"
+#include "oskar_helper.h"
+
+#include <iostream>
+
+namespace StationResponse{
+
+void oskar_evaluate_dipole_pattern_double(
+    const int num_points,
+    const double* theta,
+    const double* phi,
+    const double freq_hz,
+    const double dipole_length_m,
+    std::complex<double>* pattern);
+
+void OSKARElementResponseDipole::response(
+    double freq,
+    double theta,
+    double phi,
+    std::complex<double> (&response)[2][2]) const
+{
+    double dipole_length_m = 1; // TODO
+    std::complex<double>* response_ptr = (std::complex<double> *) response;
+
+    double phi_x = phi;
+    double phi_y = phi + M_PI/2;
+    oskar_evaluate_dipole_pattern_double(1, &theta, &phi_x, freq, dipole_length_m, response_ptr);
+    oskar_evaluate_dipole_pattern_double(1, &theta, &phi_y, freq, dipole_length_m, response_ptr + 2);
+}
+
+}
diff --git a/oskar/OSKARElementResponse.h b/oskar/OSKARElementResponse.h
new file mode 100644
index 00000000..6075a641
--- /dev/null
+++ b/oskar/OSKARElementResponse.h
@@ -0,0 +1,22 @@
+#include "../AntennaModel.h"
+
+#include <memory>
+
+namespace StationResponse {
+
+class OSKARElementResponse : public AntennaModel
+{
+
+};
+
+class OSKARElementResponseDipole : public OSKARElementResponse
+{
+public:
+    virtual void response(
+        double freq,
+        double theta,
+        double phi,
+        std::complex<double> (&response)[2][2]) const final override;
+};
+
+}
-- 
GitLab