From 3b1f0bf1fae0188b61a70ce2d17bec33a3f27db4 Mon Sep 17 00:00:00 2001
From: Bram Veenboer <bram.veenboer@gmail.com>
Date: Fri, 24 Jan 2020 14:51:48 +0100
Subject: [PATCH] Add oskar spherical wave model

The implementation is not complete, the coeffficients are missing.
---
 Station.cc                                 |   6 +
 oskar/CMakeLists.txt                       |   5 +-
 oskar/OSKARElementResponse.cc              |  24 ++++
 oskar/OSKARElementResponse.h               |  10 ++
 oskar/oskar_evaluate_dipole_pattern.cc     |   1 -
 oskar/oskar_evaluate_spherical_wave_sum.cc | 131 +++++++++++++++++++++
 6 files changed, 175 insertions(+), 2 deletions(-)
 create mode 100644 oskar/oskar_evaluate_spherical_wave_sum.cc

diff --git a/Station.cc b/Station.cc
index 8395b8ca..f5b6d1ea 100644
--- a/Station.cc
+++ b/Station.cc
@@ -60,8 +60,14 @@ Station::Station(
             }
             break;
         case OSKAR:
+        std::clog << "initialize oskar!" << std::endl;
+        #if 0
             DualDipoleAntenna::itsElementResponse.reset(new OSKARElementResponseDipole());
             TileAntenna::itsElementResponse.reset(new OSKARElementResponseDipole());
+        #else
+            DualDipoleAntenna::itsElementResponse.reset(new OSKARElementResponseSphericalWave());
+            TileAntenna::itsElementResponse.reset(new OSKARElementResponseSphericalWave());
+        #endif
             break;
         default:
             std::stringstream message;
diff --git a/oskar/CMakeLists.txt b/oskar/CMakeLists.txt
index 33a47ca7..e1cd3d46 100644
--- a/oskar/CMakeLists.txt
+++ b/oskar/CMakeLists.txt
@@ -1,5 +1,8 @@
+# build liboskar.so
 add_library(oskar SHARED
     OSKARElementResponse.cc
-    oskar_evaluate_dipole_pattern.cc)
+    oskar_evaluate_dipole_pattern.cc
+    oskar_evaluate_spherical_wave_sum.cc)
 
+# install liboskar.so
 install(TARGETS oskar DESTINATION lib)
\ No newline at end of file
diff --git a/oskar/OSKARElementResponse.cc b/oskar/OSKARElementResponse.cc
index 390c05e9..eff96442 100644
--- a/oskar/OSKARElementResponse.cc
+++ b/oskar/OSKARElementResponse.cc
@@ -27,3 +27,27 @@ void OSKARElementResponseDipole::element_response(
     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);
 }
+
+void oskar_evaluate_spherical_wave_sum_double(
+    const int num_points,
+    const double* theta,
+    const double* phi_x,
+    const double* phi_y,
+    const int l_max,
+    const std::complex<double>* alpha,
+    std::complex<double>* pattern);
+
+void OSKARElementResponseSphericalWave::element_response(
+    double freq,
+    double theta,
+    double phi,
+    std::complex<double> (&response)[2][2]) const
+{
+    int l_max = 1; // TODO
+    std::complex<double>* response_ptr = (std::complex<double> *) response;
+    std::complex<double>* alpha_ptr; // TODO
+
+    double phi_x = phi;
+    double phi_y = phi + M_PI/2;
+    oskar_evaluate_spherical_wave_sum_double(1, &theta, &phi_x, &phi_y, l_max, alpha_ptr, response_ptr);
+}
\ No newline at end of file
diff --git a/oskar/OSKARElementResponse.h b/oskar/OSKARElementResponse.h
index 5fa12389..80125a93 100644
--- a/oskar/OSKARElementResponse.h
+++ b/oskar/OSKARElementResponse.h
@@ -15,3 +15,13 @@ public:
         double phi,
         std::complex<double> (&response)[2][2]) const final override;
 };
+
+class OSKARElementResponseSphericalWave : public OSKARElementResponse
+{
+public:
+    virtual void element_response(
+        double freq,
+        double theta,
+        double phi,
+        std::complex<double> (&response)[2][2]) const final override;
+};
\ No newline at end of file
diff --git a/oskar/oskar_evaluate_dipole_pattern.cc b/oskar/oskar_evaluate_dipole_pattern.cc
index 68adae88..0debc51f 100644
--- a/oskar/oskar_evaluate_dipole_pattern.cc
+++ b/oskar/oskar_evaluate_dipole_pattern.cc
@@ -28,7 +28,6 @@
 
 #include <cmath>
 #include <complex>
-#include <iostream>
 
 #include "oskar_vector_types.h"
 #include "oskar_helper.h"
diff --git a/oskar/oskar_evaluate_spherical_wave_sum.cc b/oskar/oskar_evaluate_spherical_wave_sum.cc
new file mode 100644
index 00000000..2cb2b4c2
--- /dev/null
+++ b/oskar/oskar_evaluate_spherical_wave_sum.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2019, The University of Oxford
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 3. Neither the name of the University of Oxford nor the names of its
+ *    contributors may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmath>
+#include <complex>
+
+#include "oskar_vector_types.h"
+#include "oskar_helper.h"
+
+template<typename FP, typename FP2, typename FP4c>
+void oskar_evaluate_spherical_wave_sum(
+    int num_points, const FP* theta,
+    const FP* phi_x, const FP* phi_y, int l_max,
+    const FP4c* alpha, int offset, FP4c* pattern)
+{
+    FP2 Xp, Xt, Yp, Yt;
+    make_zero2(Xp); make_zero2(Xt);
+    make_zero2(Yp); make_zero2(Yt);
+
+    #pragma omp parallel for
+    for (int i = 0; i < num_points; i++) {
+        const FP phi_x_ = phi_x[i], theta_ = theta[i];
+        const FP phi_y_ = phi_y[i];
+        /* Propagate NAN. */
+        if (phi_x_ != phi_x_) {
+            Xp.x = Xp.y = Xt.x = Xt.y = phi_x_;
+            Yp.x = Yp.y = Yt.x = Yt.y = phi_x_;
+        }
+        else {
+            FP sin_t, cos_t;
+            oskar_sincos(theta_, &sin_t, &cos_t);
+            for (int l = 1; l <= l_max; ++l) {
+                const int ind0 = l * l - 1 + l;
+                const FP f_ = (2 * l + 1) / (4 * ((FP)M_PI) * l * (l + 1));
+                for (int abs_m = l; abs_m >=0; --abs_m) {
+                    FP p, pds, dpms, sin_p, cos_p;
+                    oskar_legendre2(l, abs_m, cos_t, sin_t, p, pds, dpms);
+                    if (abs_m == 0) {
+                        sin_p = (FP)0; cos_p = sqrt(f_);
+                        const FP4c alpha_ = alpha[ind0];
+                        oskar_sph_wave(pds, dpms, sin_p, cos_p, 0, alpha_.a, alpha_.b, Xt, Xp);
+                        oskar_sph_wave(pds, dpms, sin_p, cos_p, 0, alpha_.c, alpha_.d, Yt, Yp);
+                    }
+                    else {
+                        FP d_fact = (FP)1, s_fact = (FP)1;
+                        const int d_ = l - abs_m, s_ = l + abs_m;
+                        for (int i_ = 2; i_ <= d_; ++i_) d_fact *= i_;
+                        for (int i_ = 2; i_ <= s_; ++i_) s_fact *= i_;
+                        const FP ff = f_ * d_fact / s_fact;
+                        const FP nf = sqrt(ff);
+                        const FP4c alpha_m = alpha[ind0 - abs_m];
+                        const FP4c alpha_p = alpha[ind0 + abs_m];
+                        p = -abs_m * phi_x_;
+                        oskar_sincos(p, &sin_p, &cos_p);
+                        sin_p *= nf; cos_p *= nf;
+                        oskar_sph_wave(pds, dpms, sin_p, cos_p, -abs_m, alpha_m.a, alpha_m.b, Xt, Xp);
+                        sin_p = -sin_p;
+                        oskar_sph_wave(pds, dpms, sin_p, cos_p,  abs_m, alpha_p.a, alpha_p.b, Xt, Xp);
+                        p = -abs_m * phi_y_;
+                        oskar_sincos(p, &sin_p, &cos_p);
+                        sin_p *= nf; cos_p *= nf;
+                        oskar_sph_wave(pds, dpms, sin_p, cos_p, -abs_m, alpha_m.c, alpha_m.d, Yt, Yp);
+                        sin_p = -sin_p;
+                        oskar_sph_wave(pds, dpms, sin_p, cos_p,  abs_m, alpha_p.c, alpha_p.d, Yt, Yp);
+                    }
+                }
+            }
+        }
+        pattern[i + offset].a = Xt;
+        pattern[i + offset].b = Xp;
+        pattern[i + offset].c = Yt;
+        pattern[i + offset].d = Yp;
+    }
+}
+
+void oskar_evaluate_spherical_wave_sum_double(
+    const int num_points,
+    const double* theta,
+    const double* phi_x,
+    const double* phi_y,
+    const int l_max,
+    const std::complex<double>* alpha,
+    std::complex<double>* pattern)
+{
+    double4c* alpha_ptr = (double4c *) alpha;
+    double4c* pattern_ptr = (double4c *) pattern;
+
+    oskar_evaluate_spherical_wave_sum<double, double2, double4c>(
+        num_points, theta, phi_x, phi_y, l_max, alpha_ptr, 0, pattern_ptr);
+}
+
+void oskar_evaluate_spherical_wave_sum_float(
+    const int num_points,
+    const float* theta,
+    const float* phi_x,
+    const float* phi_y,
+    const int l_max,
+    const std::complex<float>* alpha,
+    std::complex<float>* pattern)
+{
+    float4c* alpha_ptr = (float4c *) alpha;
+    float4c* pattern_ptr = (float4c *) pattern;
+
+    oskar_evaluate_spherical_wave_sum<float, float2, float4c>(
+        num_points, theta, phi_x, phi_y, l_max, alpha_ptr, 0, pattern_ptr);
+}
-- 
GitLab