diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 0265fb93bc18d19cc0322be530ded251107fe5c0..bcc721e533894259cb89b211d209e063b84d33c8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -31,14 +31,15 @@ test-and-coverage:
     - pip3 install gcovr
   script:
     - mkdir build
-    # Download LOFAR Mock measurement set
-    - ./scripts/download_lofar_ms.sh
-    - cd test_data/LOFAR_MOCK.ms/ && export LOFAR_MOCK_MS=$PWD
-    - cd ../../build
+    # Download LOFAR/VLA Mock measurement set
+    - ./scripts/download_lofar_ms.sh && cd test_data/LOFAR_MOCK.ms/ && export LOFAR_MOCK_MS=$PWD && cd ../../
+    - ./scripts/download_vla_ms.sh && cd test_data/VLA_MOCK.ms/ && export VLA_MOCK_MS=$PWD && cd ../../build
     # Build in Debug mode and add LOFAR_MOCK_MS
-    - cmake -DCMAKE_INSTALL_PREFIX=.. -DLOFAR_MOCK_MS=$LOFAR_MOCK_MS -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-coverage" -DCMAKE_EXE_LINKER_FLAGS="-coverage" ..
+    - cmake -DCMAKE_INSTALL_PREFIX=.. -DLOFAR_MOCK_MS=$LOFAR_MOCK_MS -DVLA_MOCK_MS=$VLA_MOCK_MS -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-coverage" -DCMAKE_EXE_LINKER_FLAGS="-coverage" ..
     - make install -j8
     - ctest -T test
+    # Explicit test that vla is checked
+    - ./cpp/test/runtests --log_level=test_suite --run_test=load_vla
     - gcovr -r .. -e '.*/external/.*' -e '.*/CompilerIdCXX/.*' -e '.*/test/.*' -e '.*/demo/.*'
     - gcovr -r .. -e '.*/external/.*' -e '.*/CompilerIdCXX/.*' -e '.*/test/.*' -e '.*/demo/.*' --xml > coverage.xml
   artifacts:
diff --git a/CMake/config.h.in b/CMake/config.h.in
index 7074966eb17c8e2639d9a5b1effdcf887ef385fc..29fe68a0093c1fd592cba6628021bd23fe03b328 100644
--- a/CMake/config.h.in
+++ b/CMake/config.h.in
@@ -4,5 +4,6 @@
 #define EVERYBEAM_DATA_DIR "@CMAKE_INSTALL_DATA_DIR@"
 #define TEST_MEASUREMENTSET "@TEST_MEASUREMENTSET@"
 #define LOFAR_MOCK_MS "@LOFAR_MOCK_MS@"
+#define VLA_MOCK_MS "@VLA_MOCK_MS@"
 
 #endif
diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt
index a614621860a9e19419c3980fbdfc95bda370ccea..c1746ca68264a01002eb35586498c5c3adc1057f 100644
--- a/cpp/CMakeLists.txt
+++ b/cpp/CMakeLists.txt
@@ -6,6 +6,7 @@ add_subdirectory(hamaker)
 add_subdirectory(lobes)
 add_subdirectory(oskar)
 add_subdirectory(telescope)
+add_subdirectory(circularsymmetric)
 
 #------------------------------------------------------------------------------
 add_library(everybeam SHARED
@@ -19,7 +20,11 @@ add_library(everybeam SHARED
   lofarreadutils.cc
   station.cc
   telescope/lofar.cc
+  telescope/dish.cc
   griddedresponse/lofargrid.cc
+  griddedresponse/dishgrid.cc
+  circularsymmetric/voltagepattern.cc
+  circularsymmetric/vlabeam.cc
 )
 
 target_include_directories(everybeam PUBLIC ${CASACORE_INCLUDE_DIR})
diff --git a/cpp/circularsymmetric/CMakeLists.txt b/cpp/circularsymmetric/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1dbf27541ad0d67e7ac7abcc2d7f06af305a285a
--- /dev/null
+++ b/cpp/circularsymmetric/CMakeLists.txt
@@ -0,0 +1,4 @@
+install (FILES
+  vlabeam.h
+  voltagepattern.h
+DESTINATION "include/${CMAKE_PROJECT_NAME}/circularsymmetric")
\ No newline at end of file
diff --git a/cpp/circularsymmetric/vlabeam.cc b/cpp/circularsymmetric/vlabeam.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e5d9145b958caa420ed987fe32ffe905e58100f1
--- /dev/null
+++ b/cpp/circularsymmetric/vlabeam.cc
@@ -0,0 +1,383 @@
+#include "vlabeam.h"
+
+#include <cmath>
+#include <vector>
+
+using namespace everybeam::circularsymmetric;
+
+std::array<double, 5> VLABeam::GetCoefficients(const std::string& bandName,
+                                               double freq) {
+  char band = '?';
+
+  size_t sharp = bandName.find('#');
+  if (sharp != std::string::npos) {
+    if (sharp > 5 && bandName.substr(0, 5) == "EVLA_") band = bandName[5];
+  }
+  if (band == '?') {
+    band = DetermineFeed(freq);
+  }
+  LimitFreqForBand(band, freq);
+
+  auto coeffmap = GetCoefficients();
+
+  const std::array<double, 5>* coeff;
+  double freqMHz = freq * 1e-6;
+  double freqUsed = freq * 1e-6;
+  std::map<int, std::array<double, 5>>::iterator low, prev;
+  low = coeffmap.lower_bound(freqMHz);
+  if (low == coeffmap.end()) {
+    --low;
+    coeff = &low->second;
+    freqUsed = low->first;
+  } else if (low == coeffmap.begin()) {
+    coeff = &low->second;
+    freqUsed = low->first;
+  } else {
+    prev = low;
+    --prev;
+    if (std::fabs(freqMHz - prev->first) < std::fabs(low->first - freqMHz)) {
+      coeff = &prev->second;
+      freqUsed = prev->first;
+    } else {
+      coeff = &low->second;
+      freqUsed = low->first;
+    }
+  }
+  return *coeff;
+}
+
+char VLABeam::DetermineFeed(double freq, double freqCenter) {
+  if ((freqCenter > 224e6 && freqCenter < 480e6) ||
+      (freq > 224e6 && freq < 480e6))
+    return 'P';
+  if ((freqCenter > 900e6 && freqCenter < 2003.0e6) ||
+      (freq > 900e6 && freq < 2003e6))
+    return 'L';
+  if ((freqCenter > 1990e6 && freqCenter < 4001.0e6) ||
+      (freq > 1990e6 && freq < 4001e6))
+    return 'S';
+  if ((freqCenter > 3990e6 && freqCenter < 8001.0e6) ||
+      (freq > 3990e6 && freq < 8001e6))
+    return 'C';
+  if ((freqCenter > 7990e6 && freqCenter < 12001.0e6) ||
+      (freq > 7990e6 && freq < 12001e6))
+    return 'X';
+  if ((freqCenter > 12000e6 && freqCenter < 18000.0e6) ||
+      (freq > 12000e6 && freq < 18000e6))
+    return 'U';
+  if ((freqCenter > 19000e6 && freqCenter < 26000.0e6) ||
+      (freq > 19000e6 && freq < 26000e6))
+    return 'K';
+  if ((freqCenter > 28000e6 && freqCenter < 38000.0e6) ||
+      (freq > 28000e6 && freq < 38000e6))
+    return 'A';
+  if ((freqCenter > 41000e6 && freqCenter < 50000.0e6) ||
+      (freq > 41000e6 && freq < 50000e6))
+    return 'Q';
+
+  return '?';
+}
+
+// From PBMath1DEVLA::limitFreqForBand
+void VLABeam::LimitFreqForBand(char band, double& freq) {
+  if (band == 'P') {
+    if (freq <= 224e6) freq = 232e6;
+    if (freq >= 480e6) freq = 470e6;
+  } else if (band == 'L') {
+    if (freq <= 900e6) freq = 1040e6;
+    if (freq >= 2000e6) freq = 2000e6;
+  } else if (band == 'S') {
+    if (freq < 2052e6) freq = 2052e6;
+    if (freq >= 3948e6) freq = 3948e6;
+  } else if (band == 'C') {
+    if (freq < 4052e6) freq = 4052e6;
+    if (freq >= 7948e6) freq = 7948e6;
+  } else if (band == 'X') {
+    if (freq < 8052e6) freq = 8052e6;
+    if (freq >= 11948e6) freq = 11948e6;
+  } else if (band == 'U') {
+    if (freq < 12052e6) freq = 12052e6;
+    if (freq >= 17948e6) freq = 17948e6;
+  } else if (band == 'K') {
+    if (freq < 19052e6) freq = 19052e6;
+    if (freq >= 25948e6) freq = 25948e6;
+  } else if (band == 'A') {
+    if (freq < 28052e6) freq = 28052e6;
+    if (freq >= 38048e6) freq = 38048e6;
+  } else if (band == 'Q') {
+    if (freq < 41052e6) freq = 41052e6;
+    if (freq >= 43948e6) freq = 43948e6;
+  }
+}
+
+std::map<char, double> VLABeam::GetFeedConf() {
+  std::map<char, double> feed_conf;
+  feed_conf['L'] =
+      (-185.9) * M_PI / 180.0;  // squint orientation, rads, North of +AZ axis
+  feed_conf['S'] = (-11.61) * M_PI / 180.0;
+  feed_conf['C'] = (-104.8) * M_PI / 180.0;
+  feed_conf['X'] = (-113.7) * M_PI / 180.0;
+  feed_conf['U'] = (42.4) * M_PI / 180.0;
+  feed_conf['K'] = (64.4) * M_PI / 180.0;
+  feed_conf['A'] = (106.9) * M_PI / 180.0;
+  feed_conf['Q'] = (85.5) * M_PI / 180.0;
+  return feed_conf;
+}
+
+std::map<int, std::array<double, 5>> VLABeam::GetCoefficients() {
+  // This comes from PBMath1DEVLA::init()
+  // Also see https://library.nrao.edu/public/memos/evla/EVLAM_195.pdf
+  std::vector<double> wFreqs_p{232., 246., 281., 296., 312., 328., 344., 357.,
+                               382., 392., 403., 421., 458., 470., 1040, 1104,
+                               1168, 1232, 1296, 1360, 1424, 1488, 1552, 1680,
+                               1744, 1808, 1872, 1936, 2000};
+  for (double& f : wFreqs_p) f *= 1e6;
+
+  std::map<int, std::array<double, 5>> coeffmap;
+  ////P
+  coeffmap[232] = {1.0, -1.137e-3, 5.19e-7, -1.04e-10, 0.71e-14};
+  coeffmap[246] = {1.0, -1.130e-3, 5.04e-7, -1.02e-10, 0.77e-14};
+  coeffmap[281] = {1.0, -1.106e-3, 5.11e-7, -1.10e-10, 0.91e-14};
+  coeffmap[296] = {1.0, -1.125e-3, 5.27e-7, -1.14e-10, 0.96e-14};
+  coeffmap[312] = {1.0, -1.030e-3, 4.44e-7, -0.89e-10, 0.68e-14};
+  coeffmap[328] = {1.0, -0.980e-3, 4.25e-7, -0.87e-10, 0.69e-14};
+  coeffmap[344] = {1.0, -0.974e-3, 4.09e-7, -0.76e-10, 0.53e-14};
+  coeffmap[357] = {1.0, -0.996e-3, 4.23e-7, -0.79e-10, 0.51e-14};
+  coeffmap[382] = {1.0, -1.002e-3, 4.39e-7, -0.88e-10, 0.64e-14};
+  coeffmap[392] = {1.0, -1.067e-3, 5.13e-7, -1.12e-10, 0.90e-14};
+  coeffmap[403] = {1.0, -1.057e-3, 4.90e-7, -1.06e-10, 0.87e-14};
+  coeffmap[421] = {1.0, -1.154e-3, 5.85e-7, -1.33e-10, 1.08e-14};
+  coeffmap[458] = {1.0, -0.993e-3, 4.67e-7, -1.04e-10, 0.88e-14};
+  coeffmap[470] = {1.0, -1.010e-3, 4.85e-7, -1.07e-10, 0.86e-14};
+  /////////L
+  coeffmap[1040] = {1.000, -1.529e-3, 8.69e-7, -1.88e-10};
+  coeffmap[1104] = {1.000, -1.486e-3, 8.15e-7, -1.68e-10};
+  coeffmap[1168] = {1.000, -1.439e-3, 7.53e-7, -1.45e-10};
+  coeffmap[1232] = {1.000, -1.450e-3, 7.87e-7, -1.63e-10};
+  coeffmap[1296] = {1.000, -1.428e-3, 7.62e-7, -1.54e-10};
+  coeffmap[1360] = {1.000, -1.449e-3, 8.02e-7, -1.74e-10};
+  coeffmap[1424] = {1.000, -1.462e-3, 8.23e-7, -1.83e-10};
+  coeffmap[1488] = {1.000, -1.455e-3, 7.92e-7, -1.63e-10};
+  coeffmap[1552] = {1.000, -1.435e-3, 7.54e-7, -1.49e-10};
+  coeffmap[1680] = {1.000, -1.443e-3, 7.74e-7, -1.57e-10};
+  coeffmap[1744] = {1.000, -1.462e-3, 8.02e-7, -1.69e-10};
+  coeffmap[1808] = {1.000, -1.488e-3, 8.38e-7, -1.83e-10};
+  coeffmap[1872] = {1.000, -1.486e-3, 8.26e-7, -1.75e-10};
+  coeffmap[1936] = {1.000, -1.459e-3, 7.93e-7, -1.62e-10};
+  coeffmap[2000] = {1.000, -1.508e-3, 8.31e-7, -1.68e-10};
+  ////////S
+  coeffmap[2052] = {1.000, -1.429e-3, 7.52e-7, -1.47e-10};
+  coeffmap[2180] = {1.000, -1.389e-3, 7.06e-7, -1.33e-10};
+  coeffmap[2436] = {1.000, -1.377e-3, 6.90e-7, -1.27e-10};
+  coeffmap[2564] = {1.000, -1.381e-3, 6.92e-7, -1.26e-10};
+  coeffmap[2692] = {1.000, -1.402e-3, 7.23e-7, -1.40e-10};
+  coeffmap[2820] = {1.000, -1.433e-3, 7.62e-7, -1.54e-10};
+  coeffmap[2948] = {1.000, -1.433e-3, 7.46e-7, -1.42e-10};
+  coeffmap[3052] = {1.000, -1.467e-3, 8.05e-7, -1.70e-10};
+  coeffmap[3180] = {1.000, -1.497e-3, 8.38e-7, -1.80e-10};
+  coeffmap[3308] = {1.000, -1.504e-3, 8.37e-7, -1.77e-10};
+  coeffmap[3436] = {1.000, -1.521e-3, 8.63e-7, -1.88e-10};
+  coeffmap[3564] = {1.000, -1.505e-3, 8.37e-7, -1.75e-10};
+  coeffmap[3692] = {1.000, -1.521e-3, 8.51e-7, -1.79e-10};
+  coeffmap[3820] = {1.000, -1.534e-3, 8.57e-7, -1.77e-10};
+  coeffmap[3948] = {1.000, -1.516e-3, 8.30e-7, -1.66e-10};
+  /// C
+  coeffmap[4052] = {1.000, -1.406e-3, 7.41e-7, -1.48e-10};
+  coeffmap[4180] = {1.000, -1.385e-3, 7.09e-7, -1.36e-10};
+  coeffmap[4308] = {1.000, -1.380e-3, 7.08e-7, -1.37e-10};
+  coeffmap[4436] = {1.000, -1.362e-3, 6.95e-7, -1.35e-10};
+  coeffmap[4564] = {1.000, -1.365e-3, 6.92e-7, -1.31e-10};
+  coeffmap[4692] = {1.000, -1.339e-3, 6.56e-7, -1.17e-10};
+  coeffmap[4820] = {1.000, -1.371e-3, 7.06e-7, -1.40e-10};
+  coeffmap[4948] = {1.000, -1.358e-3, 6.91e-7, -1.34e-10};
+  coeffmap[5052] = {1.000, -1.360e-3, 6.91e-7, -1.33e-10};
+  coeffmap[5180] = {1.000, -1.353e-3, 6.74e-7, -1.25e-10};
+  coeffmap[5308] = {1.000, -1.359e-3, 6.82e-7, -1.27e-10};
+  coeffmap[5436] = {1.000, -1.380e-3, 7.05e-7, -1.37e-10};
+  coeffmap[5564] = {1.000, -1.376e-3, 6.99e-7, -1.31e-10};
+  coeffmap[5692] = {1.000, -1.405e-3, 7.39e-7, -1.47e-10};
+  coeffmap[5820] = {1.000, -1.394e-3, 7.29e-7, -1.45e-10};
+  coeffmap[5948] = {1.000, -1.428e-3, 7.57e-7, -1.57e-10};
+  coeffmap[6052] = {1.000, -1.445e-3, 7.68e-7, -1.50e-10};
+  coeffmap[6148] = {1.000, -1.422e-3, 7.38e-7, -1.38e-10};
+  coeffmap[6308] = {1.000, -1.463e-3, 7.94e-7, -1.62e-10};
+  coeffmap[6436] = {1.000, -1.478e-3, 8.22e-7, -1.74e-10};
+  coeffmap[6564] = {1.000, -1.473e-3, 8.00e-7, -1.62e-10};
+  coeffmap[6692] = {1.000, -1.455e-3, 7.76e-7, -1.53e-10};
+  coeffmap[6820] = {1.000, -1.487e-3, 8.22e-7, -1.72e-10};
+  coeffmap[6948] = {1.000, -1.472e-3, 8.05e-7, -1.67e-10};
+  coeffmap[7052] = {1.000, -1.470e-3, 8.01e-7, -1.64e-10};
+  coeffmap[7180] = {1.000, -1.503e-3, 8.50e-7, -1.84e-10};
+  coeffmap[7308] = {1.000, -1.482e-3, 8.19e-7, -1.72e-10};
+  coeffmap[7436] = {1.000, -1.498e-3, 8.22e-7, -1.66e-10};
+  coeffmap[7564] = {1.000, -1.490e-3, 8.18e-7, -1.66e-10};
+  coeffmap[7692] = {1.000, -1.481e-3, 7.98e-7, -1.56e-10};
+  coeffmap[7820] = {1.000, -1.474e-3, 7.94e-7, -1.57e-10};
+  coeffmap[7948] = {1.000, -1.448e-3, 7.69e-7, -1.51e-10};
+  //////X
+  coeffmap[8052] = {1.000, -1.403e-3, 7.21e-7, -1.37e-10};
+  coeffmap[8180] = {1.000, -1.398e-3, 7.10e-7, -1.32e-10};
+  coeffmap[8308] = {1.000, -1.402e-3, 7.16e-7, -1.35e-10};
+  coeffmap[8436] = {1.000, -1.400e-3, 7.12e-7, -1.32e-10};
+  coeffmap[8564] = {1.000, -1.391e-3, 6.95e-7, -1.25e-10};
+  coeffmap[8692] = {1.000, -1.409e-3, 7.34e-7, -1.49e-10};
+  coeffmap[8820] = {1.000, -1.410e-3, 7.36e-7, -1.45e-10};
+  coeffmap[8948] = {1.000, -1.410e-3, 7.34e-7, -1.43e-10};
+  coeffmap[9052] = {1.000, -1.403e-3, 7.20e-7, -1.36e-10};
+  coeffmap[9180] = {1.000, -1.396e-3, 7.09e-7, -1.31e-10};
+  coeffmap[9308] = {1.000, -1.432e-3, 7.68e-7, -1.55e-10};
+  coeffmap[9436] = {1.000, -1.414e-3, 7.43e-7, -1.47e-10};
+  coeffmap[9564] = {1.000, -1.416e-3, 7.45e-7, -1.47e-10};
+  coeffmap[9692] = {1.000, -1.406e-3, 7.26e-7, -1.39e-10};
+  coeffmap[9820] = {1.000, -1.412e-3, 7.36e-7, -1.43e-10};
+  coeffmap[9948] = {1.000, -1.409e-3, 7.29e-7, -1.39e-10};
+  coeffmap[10052] = {1.000, -1.421e-3, 7.46e-7, -1.45e-10};
+  coeffmap[10180] = {1.000, -1.409e-3, 7.25e-7, -1.36e-10};
+  coeffmap[10308] = {1.000, -1.402e-3, 7.13e-7, -1.31e-10};
+  coeffmap[10436] = {1.000, -1.399e-3, 7.09e-7, -1.29e-10};
+  coeffmap[10564] = {1.000, -1.413e-3, 7.37e-7, -1.43e-10};
+  coeffmap[10692] = {1.000, -1.412e-3, 7.34e-7, -1.41e-10};
+  coeffmap[10820] = {1.000, -1.401e-3, 7.12e-7, -1.31e-10};
+  coeffmap[10948] = {1.000, -1.401e-3, 7.12e-7, -1.31e-10};
+  coeffmap[10052] = {1.000, -1.401e-3, 7.12e-7, -1.31e-10};
+  coeffmap[11180] = {1.000, -1.394e-3, 6.99e-7, -1.24e-10};
+  coeffmap[11308] = {1.000, -1.394e-3, 7.01e-7, -1.26e-10};
+  coeffmap[11436] = {1.000, -1.391e-3, 6.94e-7, -1.22e-10};
+  coeffmap[11564] = {1.000, -1.389e-3, 6.92e-7, -1.22e-10};
+  coeffmap[11692] = {1.000, -1.386e-3, 6.80e-7, -1.15e-10};
+  coeffmap[11820] = {1.000, -1.391e-3, 6.88e-7, -1.19e-10};
+  coeffmap[11948] = {1.000, -1.399e-3, 6.97e-7, -1.22e-10};
+  /// U
+  coeffmap[12052] = {1.000, -1.399e-3, 7.17e-7, -1.34e-10};
+  coeffmap[12180] = {1.000, -1.392e-3, 7.07e-7, -1.31e-10};
+  coeffmap[12308] = {1.000, -1.393e-3, 7.19e-7, -1.38e-10};
+  coeffmap[12436] = {1.000, -1.393e-3, 7.20e-7, -1.40e-10};
+  coeffmap[12564] = {1.000, -1.395e-3, 7.19e-7, -1.38e-10};
+  coeffmap[12692] = {1.000, -1.397e-3, 7.20e-7, -1.37e-10};
+  coeffmap[12820] = {1.000, -1.388e-3, 7.06e-7, -1.32e-10};
+  coeffmap[12948] = {1.000, -1.397e-3, 7.18e-7, -1.36e-10};
+  coeffmap[13052] = {1.000, -1.400e-3, 7.27e-7, -1.40e-10};
+  coeffmap[13180] = {1.000, -1.406e-3, 7.44e-7, -1.50e-10};
+  coeffmap[13308] = {1.000, -1.403e-3, 7.37e-7, -1.47e-10};
+  coeffmap[13436] = {1.000, -1.392e-3, 7.08e-7, -1.31e-10};
+  coeffmap[13564] = {1.000, -1.384e-3, 6.94e-7, -1.24e-10};
+  coeffmap[13692] = {1.000, -1.382e-3, 6.95e-7, -1.25e-10};
+  coeffmap[13820] = {1.000, -1.376e-3, 6.88e-7, -1.24e-10};
+  coeffmap[13948] = {1.000, -1.384e-3, 6.98e-7, -1.28e-10};
+  coeffmap[14052] = {1.000, -1.400e-3, 7.36e-7, -1.48e-10};
+  coeffmap[14180] = {1.000, -1.397e-3, 7.29e-7, -1.45e-10};
+  coeffmap[14308] = {1.000, -1.399e-3, 7.32e-7, -1.45e-10};
+  coeffmap[14436] = {1.000, -1.396e-3, 7.25e-7, -1.42e-10};
+  coeffmap[14564] = {1.000, -1.393e-3, 7.20e-7, -1.39e-10};
+  coeffmap[14692] = {1.000, -1.384e-3, 7.03e-7, -1.31e-10};
+  coeffmap[14820] = {1.000, -1.388e-3, 7.06e-7, -1.32e-10};
+  coeffmap[14948] = {1.000, -1.393e-3, 7.16e-7, -1.37e-10};
+  coeffmap[15052] = {1.000, -1.402e-3, 7.38e-7, -1.48e-10};
+  coeffmap[15180] = {1.000, -1.407e-3, 7.47e-7, -1.53e-10};
+  coeffmap[15308] = {1.000, -1.406e-3, 7.41e-7, -1.48e-10};
+  coeffmap[15436] = {1.000, -1.399e-3, 7.31e-7, -1.44e-10};
+  coeffmap[15564] = {1.000, -1.397e-3, 7.28e-7, -1.43e-10};
+  coeffmap[15692] = {1.000, -1.401e-3, 7.35e-7, -1.46e-10};
+  coeffmap[15820] = {1.000, -1.402e-3, 7.34e-7, -1.45e-10};
+  coeffmap[15948] = {1.000, -1.399e-3, 7.30e-7, -1.44e-10};
+  coeffmap[16052] = {1.000, -1.419e-3, 7.59e-7, -1.54e-10};
+  coeffmap[16180] = {1.000, -1.419e-3, 7.59e-7, -1.52e-10};
+  coeffmap[16308] = {1.000, -1.412e-3, 7.40e-7, -1.44e-10};
+  coeffmap[16436] = {1.000, -1.407e-3, 7.32e-7, -1.40e-10};
+  coeffmap[16564] = {1.000, -1.408e-3, 7.32e-7, -1.41e-10};
+  coeffmap[16692] = {1.000, -1.410e-3, 7.34e-7, -1.40e-10};
+  coeffmap[16820] = {1.000, -1.407e-3, 7.27e-7, -1.38e-10};
+  coeffmap[16948] = {1.000, -1.423e-3, 7.63e-7, -1.55e-10};
+  coeffmap[17052] = {1.000, -1.437e-3, 7.87e-7, -1.66e-10};
+  coeffmap[17180] = {1.000, -1.438e-3, 7.84e-7, -1.64e-10};
+  coeffmap[17308] = {1.000, -1.445e-3, 7.98e-7, -1.71e-10};
+  coeffmap[17436] = {1.000, -1.452e-3, 8.10e-7, -1.77e-10};
+  coeffmap[17564] = {1.000, -1.458e-3, 8.13e-7, -1.70e-10};
+  coeffmap[17692] = {1.000, -1.456e-3, 8.06e-7, -1.72e-10};
+  coeffmap[17820] = {1.000, -1.453e-3, 8.00e-7, -1.68e-10};
+  coeffmap[17948] = {1.000, -1.452e-3, 7.99e-7, -1.69e-10};
+  /////K
+  coeffmap[19052] = {1.000, -1.419e-3, 7.56e-7, -1.53e-10};
+  coeffmap[19180] = {1.000, -1.426e-3, 7.70e-7, -1.59e-10};
+  coeffmap[19308] = {1.000, -1.433e-3, 7.82e-7, -1.64e-10};
+  coeffmap[19436] = {1.000, -1.429e-3, 7.73e-7, -1.60e-10};
+  coeffmap[19564] = {1.000, -1.427e-3, 7.70e-7, -1.59e-10};
+  coeffmap[19692] = {1.000, -1.425e-3, 7.65e-7, -1.56e-10};
+  coeffmap[19820] = {1.000, -1.430e-3, 7.76e-7, -1.62e-10};
+  coeffmap[19948] = {1.000, -1.434e-3, 7.81e-7, -1.63e-10};
+  coeffmap[21052] = {1.000, -1.448e-3, 8.05e-7, -1.73e-10};
+  coeffmap[21180] = {1.000, -1.436e-3, 7.84e-7, -1.63e-10};
+  coeffmap[21308] = {1.000, -1.441e-3, 7.94e-7, -1.68e-10};
+  coeffmap[21436] = {1.000, -1.439e-3, 7.89e-7, -1.66e-10};
+  coeffmap[21564] = {1.000, -1.442e-3, 7.96e-7, -1.69e-10};
+  coeffmap[21692] = {1.000, -1.435e-3, 7.81e-7, -1.61e-10};
+  coeffmap[21820] = {1.000, -1.442e-3, 7.92e-7, -1.66e-10};
+  coeffmap[21948] = {1.000, -1.439e-3, 7.82e-7, -1.61e-10};
+  coeffmap[23052] = {1.000, -1.401e-3, 7.21e-7, -1.37e-10};
+  coeffmap[23180] = {1.000, -1.408e-3, 7.31e-7, -1.41e-10};
+  coeffmap[23308] = {1.000, -1.407e-3, 7.28e-7, -1.39e-10};
+  coeffmap[23436] = {1.000, -1.407e-3, 7.31e-7, -1.41e-10};
+  coeffmap[23564] = {1.000, -1.419e-3, 7.47e-7, -1.47e-10};
+  coeffmap[23692] = {1.000, -1.395e-3, 7.10e-7, -1.33e-10};
+  coeffmap[23820] = {1.000, -1.413e-3, 7.36e-7, -1.42e-10};
+  coeffmap[23948] = {1.000, -1.402e-3, 7.21e-7, -1.36e-10};
+  coeffmap[25052] = {1.000, -1.402e-3, 7.17e-7, -1.31e-10};
+  coeffmap[25180] = {1.000, -1.432e-3, 7.73e-7, -1.58e-10};
+  coeffmap[25308] = {1.000, -1.407e-3, 7.22e-7, -1.33e-10};
+  coeffmap[25436] = {1.000, -1.417e-3, 7.43e-7, -1.45e-10};
+  coeffmap[25564] = {1.000, -1.422e-3, 7.52e-7, -1.48e-10};
+  coeffmap[25692] = {1.000, -1.427e-3, 7.59e-7, -1.52e-10};
+  coeffmap[25820] = {1.000, -1.416e-3, 7.42e-7, -1.44e-10};
+  coeffmap[25948] = {1.000, -1.422e-3, 7.46e-7, -1.45e-10};
+  /// A
+  coeffmap[28052] = {1.000, -1.444e-3, 7.61e-7, -1.44e-10};
+  coeffmap[28180] = {1.000, -1.439e-3, 7.54e-7, -1.42e-10};
+  coeffmap[28308] = {1.000, -1.457e-3, 7.87e-7, -1.58e-10};
+  coeffmap[28436] = {1.000, -1.457e-3, 7.90e-7, -1.60e-10};
+  coeffmap[28564] = {1.000, -1.455e-3, 7.87e-7, -1.59e-10};
+  coeffmap[28692] = {1.000, -1.458e-3, 7.88e-7, -1.58e-10};
+  coeffmap[28820] = {1.000, -1.453e-3, 7.81e-7, -1.56e-10};
+  coeffmap[28948] = {1.000, -1.460e-3, 7.98e-7, -1.64e-10};
+  coeffmap[31052] = {1.000, -1.415e-3, 7.44e-7, -1.44e-10};
+  coeffmap[31180] = {1.000, -1.408e-3, 7.26e-7, -1.37e-10};
+  coeffmap[31308] = {1.000, -1.413e-3, 7.28e-7, -1.36e-10};
+  coeffmap[31436] = {1.000, -1.394e-3, 7.07e-7, -1.30e-10};
+  coeffmap[31564] = {1.000, -1.404e-3, 7.23e-7, -1.37e-10};
+  coeffmap[31692] = {1.000, -1.427e-3, 7.48e-7, -1.44e-10};
+  coeffmap[31820] = {1.000, -1.418e-3, 7.48e-7, -1.48e-10};
+  coeffmap[31948] = {1.000, -1.413e-3, 7.37e-7, -1.42e-10};
+  coeffmap[34052] = {1.000, -1.42e-3, 7.28e-7, -1.34e-10};
+  coeffmap[34180] = {1.000, -1.46e-3, 7.77e-7, -1.53e-10};
+  coeffmap[34308] = {1.000, -1.42e-3, 7.41e-7, -1.42e-10};
+  coeffmap[34436] = {1.000, -1.42e-3, 7.36e-7, -1.39e-10};
+  coeffmap[34564] = {1.000, -1.46e-3, 7.76e-7, -1.52e-10};
+  coeffmap[34692] = {1.000, -1.42e-3, 7.34e-7, -1.38e-10};
+  coeffmap[34820] = {1.000, -1.42e-3, 7.34e-7, -1.39e-10};
+  coeffmap[34948] = {1.000, -1.45e-3, 7.68e-7, -1.49e-10};
+  coeffmap[37152] = {1.000, -1.42e-3, 7.47e-7, -1.44e-10};
+  coeffmap[37280] = {1.000, -1.41e-3, 7.35e-7, -1.40e-10};
+  coeffmap[37408] = {1.000, -1.45e-3, 7.65e-7, -1.46e-10};
+  coeffmap[37536] = {1.000, -1.41e-3, 7.13e-7, -1.29e-10};
+  coeffmap[37664] = {1.000, -1.41e-3, 7.30e-7, -1.38e-10};
+  coeffmap[37792] = {1.000, -1.45e-3, 7.75e-7, -1.50e-10};
+  coeffmap[37820] = {1.000, -1.45e-3, 7.68e-7, -1.49e-10};
+  coeffmap[38048] = {1.000, -1.41e-3, 7.38e-7, -1.43e-10};
+  // Q
+  coeffmap[41052] = {1.000, -1.453e-3, 7.69e-7, -1.47e-10};
+  coeffmap[41180] = {1.000, -1.479e-3, 8.03e-7, -1.61e-10};
+  coeffmap[41308] = {1.000, -1.475e-3, 7.97e-7, -1.58e-10};
+  coeffmap[41436] = {1.000, -1.451e-3, 7.73e-7, -1.51e-10};
+  coeffmap[41564] = {1.000, -1.450e-3, 7.71e-7, -1.51e-10};
+  coeffmap[41692] = {1.000, -1.465e-3, 7.79e-7, -1.49e-10};
+  coeffmap[41820] = {1.000, -1.460e-3, 7.73e-7, -1.47e-10};
+  coeffmap[41948] = {1.000, -1.434e-3, 7.47e-7, -1.40e-10};
+  coeffmap[43052] = {1.000, -1.428e-3, 7.40e-7, -1.38e-10};
+  coeffmap[43180] = {1.000, -1.418e-3, 7.29e-7, -1.34e-10};
+  coeffmap[43308] = {1.000, -1.433e-3, 7.49e-7, -1.43e-10};
+  coeffmap[43436] = {1.000, -1.438e-3, 7.55e-7, -1.45e-10};
+  coeffmap[43564] = {1.000, -1.419e-3, 7.36e-7, -1.40e-10};
+  coeffmap[43692] = {1.000, -1.397e-3, 7.13e-7, -1.33e-10};
+  coeffmap[43820] = {1.000, -1.423e-3, 7.39e-7, -1.40e-10};
+  coeffmap[43948] = {1.000, -1.452e-3, 7.68e-7, -1.47e-10};
+  return coeffmap;
+}
diff --git a/cpp/circularsymmetric/vlabeam.h b/cpp/circularsymmetric/vlabeam.h
new file mode 100644
index 0000000000000000000000000000000000000000..734c6484344a6fd062566c4a9b18cf78abc94b99
--- /dev/null
+++ b/cpp/circularsymmetric/vlabeam.h
@@ -0,0 +1,23 @@
+#ifndef EVERYBEAM_CIRCULARSYMMETRIC_VLABEAM_H_
+#define EVERYBEAM_CIRCULARSYMMETRIC_VLABEAM_H_
+
+#include <array>
+#include <map>
+#include <string>
+
+namespace everybeam {
+namespace circularsymmetric {
+class VLABeam {
+ public:
+  static std::array<double, 5> GetCoefficients(const std::string& band_name,
+                                               double freq);
+
+ private:
+  static std::map<int, std::array<double, 5>> GetCoefficients();
+  static std::map<char, double> GetFeedConf();
+  static char DetermineFeed(double freq, double freqCenter = 0.0);
+  static void LimitFreqForBand(char band, double& freq);
+};
+}  // namespace circularsymmetric
+}  // namespace everybeam
+#endif  // EVERYBEAM_CIRCULARSYMMETRIC_VLABEAM_H_
\ No newline at end of file
diff --git a/cpp/circularsymmetric/voltagepattern.cc b/cpp/circularsymmetric/voltagepattern.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5d461f702a84a7a00ab5130e08499d9bd6112905
--- /dev/null
+++ b/cpp/circularsymmetric/voltagepattern.cc
@@ -0,0 +1,195 @@
+#include "voltagepattern.h"
+
+// #include "../wsclean/logger.h"
+// #include "../wsclean/primarybeamimageset.h"
+
+#include <aocommon/imagecoordinates.h>
+
+#include <cmath>
+
+using namespace everybeam::circularsymmetric;
+using aocommon::ImageCoordinates;
+using aocommon::UVector;
+
+void VoltagePattern::EvaluatePolynomial(const UVector<double>& coefficients,
+                                        bool invert) {
+  // This comes from casa's: void PBMath1DIPoly::fillPBArray(), wideband case
+  size_t nsamples = 10000;
+  size_t nfreq = frequencies_.size();
+  size_t ncoef = coefficients.size() / nfreq;
+  values_.resize(nsamples * nfreq);
+  inverse_increment_radius_ = double(nsamples - 1) / maximum_radius_arc_min_;
+  double* output = values_.data();
+  for (size_t n = 0; n != nfreq; n++) {
+    const double* freqcoefficients = &coefficients[n * ncoef];
+    for (size_t i = 0; i < nsamples; i++) {
+      double taper = 0.0;
+      double x2 = double(i) / inverse_increment_radius_;
+      x2 = x2 * x2;
+      double y = 1.0;
+
+      for (size_t j = 0; j < ncoef; j++) {
+        taper += y * freqcoefficients[j];
+        y *= x2;
+      }
+      if (taper >= 0.0) {
+        if (invert && taper != 0.0) {
+          taper = 1.0 / std::sqrt(taper);
+        } else {
+          taper = std::sqrt(taper);
+        }
+      } else {
+        taper = 0.0;
+      }
+      *output = taper;
+      ++output;
+    }
+  }
+};
+
+UVector<double> VoltagePattern::InterpolateValues(double freq) const {
+  UVector<double> result;
+  size_t ifit = 0;
+  size_t nfreq = frequencies_.size();
+  for (ifit = 0; ifit != nfreq; ifit++) {
+    if (freq <= frequencies_[ifit]) break;
+  }
+  if (ifit == 0) {
+    result.assign(values_.begin(), values_.begin() + NSamples());
+  } else if (ifit == nfreq) {
+    result.assign(values_.begin() + (nfreq - 1) * NSamples(), values_.end());
+  } else {
+    size_t n = NSamples();
+    double l = (freq - frequencies_[ifit - 1]) /
+               (frequencies_[ifit] - frequencies_[ifit - 1]);
+    const double* vpA = FreqIndexValues(ifit - 1);
+    const double* vpB = FreqIndexValues(ifit);
+    result.resize(n);
+    for (size_t i = 0; i != n; ++i) {
+      result[i] = vpA[i] * (1.0 - l) + vpB[i] * l;
+    }
+  }
+  return result;
+}
+
+const double* VoltagePattern::InterpolateValues(
+    double frequency_hz, UVector<double>& interpolated_values) const {
+  if (frequencies_.size() > 1) {
+    interpolated_values = InterpolateValues(frequency_hz);
+    return interpolated_values.data();
+  } else {
+    return FreqIndexValues(0);
+  }
+}
+
+double VoltagePattern::LmMaxSquared(double frequency_hz) const {
+  double factor =
+      (180.0 / M_PI) * 60.0 * frequency_hz * 1.0e-9;  // arcminutes * GHz
+  double rmax = maximum_radius_arc_min_ / factor;
+  return rmax * rmax;
+}
+
+// void VoltagePattern::Render(PrimaryBeamImageSet& beamImages, double
+// pixel_scale_x,
+//                             double pixel_scale_y, double phase_centre_ra,
+//                             double phase_centre_dec, double pointing_ra,
+//                             double pointing_dec, double phase_centre_dl,
+//                             double phase_centre_dm, double frequency_hz)
+//                             const {
+//   size_t width = beamImages.Width(), height = beamImages.Height();
+//   double lmMaxSq = LmMaxSquared(frequency_hz);
+
+//   UVector<double> interpolated_values;
+//   const double* vp = InterpolateValues(frequency_hz, interpolated_values);
+
+//   double factor =
+//       (180.0 / M_PI) * 60.0 * frequency_hz * 1.0e-9;  // arcminutes * GHz
+//   double l0, m0;
+//   ImageCoordinates::RaDecToLM(pointing_ra, pointing_dec, phase_centre_ra,
+//                               phase_centre_dec, l0, m0);
+//   l0 += phase_centre_dl;
+//   m0 += phase_centre_dm;
+//   size_t imgIndex = 0;
+// //   Logger::Debug << "Interpolating 1D voltage pattern to output
+// image...\n";
+//   for (size_t iy = 0; iy != height; ++iy) {
+//     for (size_t ix = 0; ix != width; ++ix) {
+//       double l, m, ra, dec;
+//       ImageCoordinates::XYToLM(ix, iy, pixel_scale_x, pixel_scale_y, width,
+//       height,
+//                                l, m);
+//       l += phase_centre_dl;
+//       m += m0;
+//       ImageCoordinates::LMToRaDec(l, m, phase_centre_ra, phase_centre_dec,
+//       ra, dec); ImageCoordinates::RaDecToLM(ra, dec, pointing_ra,
+//       pointing_dec, l, m); l -= l0; m -= m0; double r2 = l * l + m * m;
+//       double out; if (r2 > lmMaxSq) {
+//         out = 0.0;
+//       } else {
+//         double r = std::sqrt(r2) * factor;
+//         int indx = int(r * inverse_increment_radius_);
+//         out = vp[indx];
+//       }
+
+//       beamImages[0][imgIndex] = out;
+//       beamImages[1][imgIndex] = 0.0;
+//       beamImages[2][imgIndex] = 0.0;
+//       beamImages[3][imgIndex] = 0.0;
+//       beamImages[4][imgIndex] = 0.0;
+//       beamImages[5][imgIndex] = 0.0;
+//       beamImages[6][imgIndex] = out;
+//       beamImages[7][imgIndex] = 0.0;
+//       ++imgIndex;
+//     }
+//   }
+// }
+
+void VoltagePattern::Render(std::complex<float>* aterm, size_t width,
+                            size_t height, double pixel_scale_x,
+                            double pixel_scale_y, double phase_centre_ra,
+                            double phase_centre_dec, double pointing_ra,
+                            double pointing_dec, double phase_centre_dl,
+                            double phase_centre_dm, double frequency_hz) const {
+  double lmMaxSq = LmMaxSquared(frequency_hz);
+
+  UVector<double> interpolated_values;
+  const double* vp = InterpolateValues(frequency_hz, interpolated_values);
+
+  double factor =
+      (180.0 / M_PI) * 60.0 * frequency_hz * 1.0e-9;  // arcminutes * GHz
+  double l0, m0;
+  ImageCoordinates::RaDecToLM(pointing_ra, pointing_dec, phase_centre_ra,
+                              phase_centre_dec, l0, m0);
+  l0 += phase_centre_dl;
+  m0 += phase_centre_dm;
+  for (size_t iy = 0; iy != height; ++iy) {
+    std::complex<float>* row = aterm + iy * width * 4;
+    for (size_t ix = 0; ix != width; ++ix) {
+      double l, m, ra, dec;
+      ImageCoordinates::XYToLM(ix, iy, pixel_scale_x, pixel_scale_y, width,
+                               height, l, m);
+      l += phase_centre_dl;
+      m += m0;
+      ImageCoordinates::LMToRaDec(l, m, phase_centre_ra, phase_centre_dec, ra,
+                                  dec);
+      ImageCoordinates::RaDecToLM(ra, dec, pointing_ra, pointing_dec, l, m);
+      l -= l0;
+      m -= m0;
+      double r2 = l * l + m * m;
+      double out;
+      if (r2 > lmMaxSq) {
+        out = 1e-4;
+      } else {
+        double r = std::sqrt(r2) * factor;
+        int indx = int(r * inverse_increment_radius_);
+        out = vp[indx] * (1.0 - 1e-4) + 1e-4;
+      }
+
+      std::complex<float>* ptr = row + ix * 4;
+      ptr[0] = out;
+      ptr[1] = 0.0;
+      ptr[2] = 0.0;
+      ptr[3] = out;
+    }
+  }
+}
diff --git a/cpp/circularsymmetric/voltagepattern.h b/cpp/circularsymmetric/voltagepattern.h
new file mode 100644
index 0000000000000000000000000000000000000000..756f98a3c1e59f5e4808799c3375fa5d60237559
--- /dev/null
+++ b/cpp/circularsymmetric/voltagepattern.h
@@ -0,0 +1,61 @@
+#ifndef EVERYBEAM_CIRCULARSYMMETRIC_VOLTAGE_PATTERN_H_
+#define EVERYBEAM_CIRCULARSYMMETRIC_VOLTAGE_PATTERN_H_
+
+#include <aocommon/uvector.h>
+
+#include <complex>
+
+namespace everybeam {
+namespace circularsymmetric {
+//! Holds the information for a symmetric voltage pattern
+class VoltagePattern {
+ public:
+  VoltagePattern(double frequency, double maximum_radius_arc_min) {
+    frequencies_.assign(1, frequency);
+    maximum_radius_arc_min_ = maximum_radius_arc_min;
+  };
+
+  size_t NSamples() const { return values_.size() / frequencies_.size(); }
+
+  const double* FreqIndexValues(size_t freq_index) const {
+    return &values_[freq_index * NSamples()];
+  }
+
+  void EvaluatePolynomial(const aocommon::UVector<double>& coefficients,
+                          bool invert);
+
+  //   void Render(class PrimaryBeamImageSet& beamImages, double pixel_scale_x,
+  //               double pixel_scale_y, double phase_centre_ra, double
+  //               phase_centre_dec, double pointing_ra, double pointing_dec,
+  //               double phase_centre_dl, double phase_centre_dm, double
+  //               frequency_hz) const;
+
+  void Render(std::complex<float>* aterm, size_t width, size_t height,
+              double pixel_scale_x, double pixel_scale_y,
+              double phase_centre_ra, double phase_centre_dec,
+              double pointing_ra, double pointing_dec, double phase_centre_dl,
+              double phase_centre_dm, double frequency_hz) const;
+
+ private:
+  // Only works when frequencies_.size() > 1
+  aocommon::UVector<double> InterpolateValues(double freq) const;
+  // Works for any frequencies_.size(), including when 1
+  const double* InterpolateValues(
+      double frequency_hz,
+      aocommon::UVector<double>& interpolated_values) const;
+
+  double LmMaxSquared(double frequency_hz) const;
+
+  double inverse_increment_radius_, maximum_radius_arc_min_;
+
+  // These are the radial (one-dimensional) values of the beam
+  // It is an array of size nsamples x nfrequencies, where the sample index is
+  // least significant (fastest changing)
+  aocommon::UVector<double> values_;
+
+  // Array of since nfrequencies
+  aocommon::UVector<double> frequencies_;
+};
+}  // namespace circularsymmetric
+}  // namespace everybeam
+#endif  // EVERYBEAM_CIRCULARSYMMETRIC_VOLTAGE_PATTERN_H_
diff --git a/cpp/griddedresponse/CMakeLists.txt b/cpp/griddedresponse/CMakeLists.txt
index f2ec3de77b039950dfdec503945b130629bc156b..300981f2e38b7342f5b910fd834b843d95c4f028 100644
--- a/cpp/griddedresponse/CMakeLists.txt
+++ b/cpp/griddedresponse/CMakeLists.txt
@@ -1,4 +1,5 @@
 install (FILES
   griddedresponse.h
   lofargrid.h
+  dishgrid.h
 DESTINATION "include/${CMAKE_PROJECT_NAME}/griddedresponse")
diff --git a/cpp/griddedresponse/dishgrid.cc b/cpp/griddedresponse/dishgrid.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d340730d46ef2669c993048468acd8bb5cce3c27
--- /dev/null
+++ b/cpp/griddedresponse/dishgrid.cc
@@ -0,0 +1,40 @@
+#include "dishgrid.h"
+#include "../telescope/dish.h"
+#include "../circularsymmetric/voltagepattern.h"
+#include "../circularsymmetric/vlabeam.h"
+
+#include <aocommon/uvector.h>
+
+#include <algorithm>
+
+using namespace everybeam;
+using namespace everybeam::griddedresponse;
+
+void DishGrid::CalculateStation(std::complex<float>* buffer, double,
+                                double frequency, const size_t,
+                                const size_t field_id) {
+  const telescope::Dish& dishtelescope =
+      static_cast<const telescope::Dish&>(*telescope_);
+
+  double pdir_ra = dishtelescope.ms_properties_.field_pointing[field_id].first,
+         pdir_dec =
+             dishtelescope.ms_properties_.field_pointing[field_id].second;
+  std::array<double, 5> coefs =
+      circularsymmetric::VLABeam::GetCoefficients("", frequency);
+  circularsymmetric::VoltagePattern vp(frequency, 53.0);
+  aocommon::UVector<double> coefs_vec(coefs.begin(), coefs.end());
+  vp.EvaluatePolynomial(coefs_vec, false);
+  vp.Render(buffer, width_, height_, dl_, dm_, ra_, dec_, pdir_ra, pdir_dec,
+            phase_centre_dl_, phase_centre_dm_, frequency);
+};
+
+void DishGrid::CalculateAllStations(std::complex<float>* buffer, double,
+                                    double frequency, const size_t field_id) {
+  CalculateStation(buffer, 0., frequency, 0, field_id);
+
+  // Just repeat nstations times
+  for (size_t i = 1; i != telescope_->GetNrStations(); ++i) {
+    std::copy_n(buffer, width_ * height_ * 4,
+                buffer + i * width_ * height_ * 4);
+  }
+}
diff --git a/cpp/griddedresponse/dishgrid.h b/cpp/griddedresponse/dishgrid.h
new file mode 100644
index 0000000000000000000000000000000000000000..8df4f45c87cacec07eae2d1a4e6baab28aa049cd
--- /dev/null
+++ b/cpp/griddedresponse/dishgrid.h
@@ -0,0 +1,47 @@
+// vlagrid.h: Class for computing the VLA circular symmetric (gridded) response.
+//
+// Copyright (C) 2020
+// ASTRON (Netherlands Institute for Radio Astronomy)
+// P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+//
+// This file is part of the EveryBeam software suite.
+// The EveryBeam software suite is free software: you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The EveryBeam software suite is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with the EveryBeam software suite. If not, see
+// <http://www.gnu.org/licenses/>.
+//
+// $Id$
+
+#ifndef EVERYBEAM_GRIDDEDRESPONSE_DISHGRID_H_
+#define EVERYBEAM_GRIDDEDRESPONSE_DISHGRID_H_
+
+#include "griddedresponse.h"
+
+namespace everybeam {
+namespace griddedresponse {
+
+class DishGrid final : public GriddedResponse {
+ public:
+  DishGrid(telescope::Telescope* telescope_ptr,
+           const coords::CoordinateSystem coordinate_system)
+      : GriddedResponse(telescope_ptr, coordinate_system){};
+
+  void CalculateStation(std::complex<float>* buffer, double time,
+                        double frequency, const size_t field_id,
+                        const size_t station_idx) override;
+
+  void CalculateAllStations(std::complex<float>* buffer, double time,
+                            double frequency, const size_t field_id) override;
+};
+}  // namespace griddedresponse
+}  // namespace everybeam
+#endif  // EVERYBEAM_GRIDDEDRESPONSE_DISHGRID_H_
\ No newline at end of file
diff --git a/cpp/griddedresponse/griddedresponse.h b/cpp/griddedresponse/griddedresponse.h
index 67145981b86cd1486cfbc0d81daaa4ec583f47c5..0f97cd3766a1cbd87ae2a1075388da57f4ea5abe 100644
--- a/cpp/griddedresponse/griddedresponse.h
+++ b/cpp/griddedresponse/griddedresponse.h
@@ -59,7 +59,8 @@ class GriddedResponse {
    * @param frequency Frequency (Hz)
    */
   virtual void CalculateStation(std::complex<float>* buffer, double time,
-                                double freq, const size_t station_idx) = 0;
+                                double freq, const size_t station_idx,
+                                const size_t field_id = 0) = 0;
 
   /**
    * @brief Compute the Beam response for all stations in a Telescope
@@ -70,7 +71,8 @@ class GriddedResponse {
    * @param frequency Frequency (Hz)
    */
   virtual void CalculateAllStations(std::complex<float>* buffer, double time,
-                                    double frequency) = 0;
+                                    double frequency,
+                                    const size_t field_id = 0) = 0;
 
   std::size_t GetBufferSize(std::size_t nstations) {
     return std::size_t(nstations * width_ * height_ * 2 * 2);
diff --git a/cpp/griddedresponse/lofargrid.cc b/cpp/griddedresponse/lofargrid.cc
index 466c18eef8178e60eee9ce425faf40c0e9f65185..03abdc5c25cc4ce9d02fabd56b5481d4c824656c 100644
--- a/cpp/griddedresponse/lofargrid.cc
+++ b/cpp/griddedresponse/lofargrid.cc
@@ -26,7 +26,10 @@ LOFARGrid::LOFARGrid(telescope::Telescope* telescope_ptr,
 };
 
 void LOFARGrid::CalculateStation(std::complex<float>* buffer, double time,
-                                 double frequency, const size_t station_idx) {
+                                 double frequency, const size_t station_idx,
+                                 const size_t) {
+  const telescope::LOFAR& lofartelescope =
+      static_cast<const telescope::LOFAR&>(*telescope_);
   aocommon::Lane<Job> lane(nthreads_);
   lane_ = &lane;
 
@@ -34,7 +37,7 @@ void LOFARGrid::CalculateStation(std::complex<float>* buffer, double time,
   double sb_freq = use_channel_frequency_ ? frequency : subband_frequency_;
   // Dummy calculation of gain matrix, needed for multi-threading
   inverse_central_gain_.resize(1);
-  matrix22c_t gain_matrix = telescope_->GetStation(station_idx)
+  matrix22c_t gain_matrix = lofartelescope.GetStation(station_idx)
                                 ->Response(time, frequency, diff_beam_centre_,
                                            sb_freq, station0_, tile0_);
 
@@ -60,7 +63,9 @@ void LOFARGrid::CalculateStation(std::complex<float>* buffer, double time,
 }
 
 void LOFARGrid::CalculateAllStations(std::complex<float>* buffer, double time,
-                                     double frequency) {
+                                     double frequency, const size_t) {
+  const telescope::LOFAR& lofartelescope =
+      static_cast<const telescope::LOFAR&>(*telescope_);
   aocommon::Lane<Job> lane(nthreads_);
   lane_ = &lane;
 
@@ -69,11 +74,11 @@ void LOFARGrid::CalculateAllStations(std::complex<float>* buffer, double time,
   double sb_freq = use_channel_frequency_ ? frequency : subband_frequency_;
 
   // Dummy loop, needed for multi-threading
-  inverse_central_gain_.resize(telescope_->GetNrStations());
-  for (size_t i = 0; i != telescope_->GetNrStations(); ++i) {
-    matrix22c_t gain_matrix = telescope_->GetStation(i)->Response(
+  inverse_central_gain_.resize(lofartelescope.GetNrStations());
+  for (size_t i = 0; i != lofartelescope.GetNrStations(); ++i) {
+    matrix22c_t gain_matrix = lofartelescope.GetStation(i)->Response(
         time, frequency, diff_beam_centre_, sb_freq, station0_, tile0_);
-    if (telescope_->GetOptions().use_differential_beam) {
+    if (lofartelescope.GetOptions().use_differential_beam) {
       inverse_central_gain_[i][0] = gain_matrix[0][0];
       inverse_central_gain_[i][1] = gain_matrix[0][1];
       inverse_central_gain_[i][2] = gain_matrix[1][0];
@@ -91,7 +96,7 @@ void LOFARGrid::CalculateAllStations(std::complex<float>* buffer, double time,
   }
 
   for (size_t y = 0; y != height_; ++y) {
-    for (size_t antenna_idx = 0; antenna_idx != telescope_->GetNrStations();
+    for (size_t antenna_idx = 0; antenna_idx != lofartelescope.GetNrStations();
          ++antenna_idx) {
       lane.write(Job{
           .y = y, .antenna_idx = antenna_idx, .buffer_offset = antenna_idx});
@@ -133,6 +138,8 @@ void LOFARGrid::SetITRFVectors(double time) {
 
 void LOFARGrid::CalcThread(std::complex<float>* buffer, double time,
                            double frequency) {
+  const telescope::LOFAR& lofartelescope =
+      static_cast<const telescope::LOFAR&>(*telescope_);
   const size_t values_per_ant = width_ * height_ * 4;
   double sb_freq = use_channel_frequency_ ? frequency : subband_frequency_;
 
@@ -160,11 +167,11 @@ void LOFARGrid::CalcThread(std::complex<float>* buffer, double time,
       std::complex<float>* ant_buffer_ptr =
           base_buffer + job.buffer_offset * values_per_ant;
 
-      matrix22c_t gain_matrix = telescope_->GetStation(job.antenna_idx)
+      matrix22c_t gain_matrix = lofartelescope.GetStation(job.antenna_idx)
                                     ->Response(time, frequency, itrf_direction,
                                                sb_freq, station0_, tile0_);
 
-      if (telescope_->GetOptions().use_differential_beam) {
+      if (lofartelescope.GetOptions().use_differential_beam) {
         aocommon::MC2x2F station_gains;
         station_gains[0] = gain_matrix[0][0];
         station_gains[1] = gain_matrix[0][1];
diff --git a/cpp/griddedresponse/lofargrid.h b/cpp/griddedresponse/lofargrid.h
index 1ad8795bfc86f9338aed48449edbb5467f1f470e..e8d8f94c6d419a8986668a9e6d23c4c5c9ec19b8 100644
--- a/cpp/griddedresponse/lofargrid.h
+++ b/cpp/griddedresponse/lofargrid.h
@@ -61,7 +61,8 @@ class LOFARGrid final : public GriddedResponse {
    * @param freq Frequency (Hz)
    */
   void CalculateStation(std::complex<float>* buffer, double time,
-                        double frequency, const size_t station_idx) override;
+                        double frequency, const size_t station_idx,
+                        const size_t) override;
 
   /**
    * @brief Compute the Beam response for all stations in a Telescope
@@ -72,7 +73,7 @@ class LOFARGrid final : public GriddedResponse {
    * @param freq Frequency (Hz)
    */
   void CalculateAllStations(std::complex<float>* buffer, double time,
-                            double frequency) override;
+                            double frequency, const size_t) override;
 
  private:
   casacore::MDirection delay_dir_, tile_beam_dir_, preapplied_beam_dir_;
diff --git a/cpp/load.cc b/cpp/load.cc
index 5f8a5a0d5ba7a40658cef269057ad8c1106c8d6a..a91810d40063bf90370396652bc4e5853bff9a06 100644
--- a/cpp/load.cc
+++ b/cpp/load.cc
@@ -4,22 +4,33 @@
 #include <casacore/ms/MeasurementSets/MeasurementSet.h>
 #include <casacore/tables/Tables/ScalarColumn.h>
 
+#include <stdexcept>
+
 using namespace everybeam;
 namespace everybeam {
 namespace {
-enum TelescopeType { kUnknownTelescope, kLofarTelescope };
+enum TelescopeType {
+  kUnknownTelescope,
+  kLofarTelescope,
+  kVLATelescope,
+  kATCATelescope
+};
 
-TelescopeType Convert(const std::string &str) {
-  if (str == "LOFAR")
-    return kLofarTelescope;
+TelescopeType Convert(const std::string &telescope_name) {
+  if (telescope_name == "LOFAR") return kLofarTelescope;
+  // Maybe more elegant with boost::to_upper_copy()?
+  else if (telescope_name.compare(0, 4, "EVLA") == 0)
+    return kVLATelescope;
+  else if (telescope_name.compare(0, 4, "ATCA") == 0)
+    return kATCATelescope;
   else
     return kUnknownTelescope;
 }
 }  // namespace
 
 std::unique_ptr<telescope::Telescope> Load(casacore::MeasurementSet &ms,
-                                           const ElementResponseModel model,
-                                           const Options &options) {
+                                           const Options &options,
+                                           const ElementResponseModel model) {
   // Read Telescope name and convert to enum
   casacore::ScalarColumn<casacore::String> telescope_name_col(ms.observation(),
                                                               "TELESCOPE_NAME");
@@ -32,6 +43,18 @@ std::unique_ptr<telescope::Telescope> Load(casacore::MeasurementSet &ms,
               new telescope::LOFAR(ms, model, options));
       return telescope;
     }
+    case kATCATelescope: {
+      std::unique_ptr<telescope::Telescope> telescope =
+          std::unique_ptr<telescope::Telescope>(
+              new telescope::Dish(ms, options));
+      return telescope;
+    }
+    case kVLATelescope: {
+      std::unique_ptr<telescope::Telescope> telescope =
+          std::unique_ptr<telescope::Telescope>(
+              new telescope::Dish(ms, options));
+      return telescope;
+    }
     default:
       std::stringstream message;
       message << "The requested telescope type " << telescope_name_col(0)
diff --git a/cpp/load.h b/cpp/load.h
index 19102da3d9e32b5427015f463b5f66b5cf595e6d..ff9ed40467e3d51eb07de2c766abc4f18777b8d9 100644
--- a/cpp/load.h
+++ b/cpp/load.h
@@ -26,6 +26,7 @@
 
 #include "./telescope/telescope.h"
 #include "./telescope/lofar.h"
+#include "./telescope/dish.h"
 #include "options.h"
 
 namespace everybeam {
@@ -40,7 +41,8 @@ namespace everybeam {
  * @return telescope::Telescope::Ptr
  */
 std::unique_ptr<telescope::Telescope> Load(
-    casacore::MeasurementSet &ms, const ElementResponseModel model,
-    const Options &options = Options::GetDefault());
+    casacore::MeasurementSet &ms,
+    const Options &options = Options::GetDefault(),
+    const ElementResponseModel model = ElementResponseModel::kHamaker);
 }  // namespace everybeam
 #endif  // EVERYBEAM_LOAD_H_
\ No newline at end of file
diff --git a/cpp/telescope/CMakeLists.txt b/cpp/telescope/CMakeLists.txt
index 27539ca1783f0e1849892e1634e7a351ee513ff5..23934e1b6a917fae0ae4f2d63a9d2dbf43d6644d 100644
--- a/cpp/telescope/CMakeLists.txt
+++ b/cpp/telescope/CMakeLists.txt
@@ -1,4 +1,5 @@
 install (FILES
+  dish.h
   lofar.h 
   telescope.h
 DESTINATION "include/${CMAKE_PROJECT_NAME}/telescope")
diff --git a/cpp/telescope/atcatelescope.h b/cpp/telescope/atcatelescope.h
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/cpp/telescope/dish.cc b/cpp/telescope/dish.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0aeba4e28b53c1cdc9eaf1c685ce68573662ed58
--- /dev/null
+++ b/cpp/telescope/dish.cc
@@ -0,0 +1,29 @@
+#include "dish.h"
+#include "../griddedresponse/dishgrid.h"
+
+#include <casacore/measures/TableMeasures/ArrayMeasColumn.h>
+
+using namespace everybeam;
+using namespace everybeam::telescope;
+
+Dish::Dish(casacore::MeasurementSet &ms, const Options &options)
+    : Telescope(ms, options) {
+  casacore::MSField field_table = ms.field();
+  casacore::ArrayColumn<double> pointing_dir_col(
+      field_table, casacore::MSField::columnName(casacore::MSField::DELAY_DIR));
+
+  for (std::size_t field_id = 0; field_id != field_table.nrow(); ++field_id) {
+    casacore::Array<double> pdir = pointing_dir_col(field_id);
+    double pdir_ra = *pdir.cbegin();
+    double pdir_dec = *(pdir.cbegin() + 1);
+    ms_properties_.field_pointing.emplace_back(pdir_ra, pdir_dec);
+  }
+}
+
+std::unique_ptr<griddedresponse::GriddedResponse> Dish::GetGriddedResponse(
+    const coords::CoordinateSystem &coordinate_system) {
+  // Get and return GriddedResponse ptr
+  std::unique_ptr<griddedresponse::GriddedResponse> grid(
+      new griddedresponse::DishGrid(this, coordinate_system));
+  return grid;
+};
\ No newline at end of file
diff --git a/cpp/telescope/dish.h b/cpp/telescope/dish.h
new file mode 100644
index 0000000000000000000000000000000000000000..efa2a0b9ffcf03e7af7b4a2df9d144cabe1059c4
--- /dev/null
+++ b/cpp/telescope/dish.h
@@ -0,0 +1,63 @@
+// dishtelescope.h: Base class for dish telescopes (VLA, ATCA, ...).
+// Inherits from Telescope class.
+//
+// Copyright (C) 2020
+// ASTRON (Netherlands Institute for Radio Astronomy)
+// P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+//
+// This file is part of the EveryBeam software suite.
+// The EveryBeam software suite is free software: you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as published
+// by the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The EveryBeam software suite is distributed in the hope that it will be
+// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with the EveryBeam software suite. If not, see
+// <http://www.gnu.org/licenses/>.
+//
+// $Id$
+
+#ifndef EVERYBEAM_TELESCOPE_DISH_H_
+#define EVERYBEAM_TELESCOPE_DISH_H_
+
+#include "telescope.h"
+
+#include <casacore/measures/Measures/MDirection.h>
+
+namespace everybeam {
+
+namespace griddedresponse {
+class DishGrid;
+class GriddedResponse;
+}  // namespace griddedresponse
+
+namespace telescope {
+
+/**
+ * This class calculates the a-terms for dishes with a circularly symmetric
+ * response.
+ */
+class Dish : public Telescope {
+  friend class griddedresponse::DishGrid;
+
+ public:
+  Dish(casacore::MeasurementSet &ms, const Options &options);
+
+  std::unique_ptr<griddedresponse::GriddedResponse> GetGriddedResponse(
+      const coords::CoordinateSystem &coordinate_system) override;
+
+ private:
+  struct MSProperties {
+    std::vector<std::pair<double, double>> field_pointing;
+  };
+  MSProperties ms_properties_;
+};
+}  // namespace telescope
+}  // namespace everybeam
+
+#endif  // EVERYBEAM_TELESCOPE_DISH_H_
\ No newline at end of file
diff --git a/cpp/telescope/lofar.cc b/cpp/telescope/lofar.cc
index 49c800a355ee22edf669d4a48c7a22b2d69a8426..263b5e01cd9b7318edaaf8437f43729f010f7561 100644
--- a/cpp/telescope/lofar.cc
+++ b/cpp/telescope/lofar.cc
@@ -58,7 +58,8 @@ bool GetPreappliedBeamDirection(casacore::MeasurementSet &ms,
 
 LOFAR::LOFAR(MeasurementSet &ms, const ElementResponseModel model,
              const Options &options)
-    : Telescope(ms, model, options) {
+    : Telescope(ms, options) {
+  stations_.resize(nstations_);
   ReadAllStations(ms, model);
 
   // Populate MeasurementSet properties struct
@@ -102,7 +103,6 @@ std::unique_ptr<griddedresponse::GriddedResponse> LOFAR::GetGriddedResponse(
   // Get and return GriddedResponse ptr
   std::unique_ptr<griddedresponse::GriddedResponse> grid(
       new griddedresponse::LOFARGrid(this, coordinate_system));
-  // griddedresponse::GriddedResponse grid(LOFARGrid(this, coordinate_system));
   return grid;
 };
 
diff --git a/cpp/telescope/lofar.h b/cpp/telescope/lofar.h
index 553116e078993b5d962416594e814c27b9c7959a..6e52d958eddd8661487630a606ac60253fd03c2b 100644
--- a/cpp/telescope/lofar.h
+++ b/cpp/telescope/lofar.h
@@ -25,6 +25,8 @@
 #ifndef EVERYBEAM_TELESCOPE_LOFAR_H_
 #define EVERYBEAM_TELESCOPE_LOFAR_H_
 
+#include "../station.h"
+#include "../elementresponse.h"
 #include "telescope.h"
 
 #include <casacore/measures/Measures/MPosition.h>
@@ -59,14 +61,44 @@ class LOFAR final : public Telescope {
   std::unique_ptr<griddedresponse::GriddedResponse> GetGriddedResponse(
       const coords::CoordinateSystem &coordinate_system) override;
 
+  /**
+   * @brief Get station by index
+   *
+   * @param station_id Station index to retrieve
+   * @return Station::Ptr
+   */
+  Station::Ptr GetStation(std::size_t station_idx) const {
+    // Assert only in DEBUG mode
+    assert(station_idx < nstations_);
+    return stations_[station_idx];
+  }
+
  private:
+  /**
+   * @brief Read stations into vector
+   *
+   * @param out_it std::vector of stations
+   * @param ms measurement set
+   * @param model model
+   */
+  void ReadAllStations(const casacore::MeasurementSet &ms,
+                       const ElementResponseModel model) {
+    casacore::ROMSAntennaColumns antenna(ms.antenna());
+
+    for (std::size_t i = 0; i < antenna.nrow(); ++i) {
+      stations_[i] = ReadStation(ms, i, model);
+    }
+  };
+
   Station::Ptr ReadStation(const casacore::MeasurementSet &ms,
                            const std::size_t id,
-                           const ElementResponseModel model) const override;
+                           const ElementResponseModel model) const;
   struct MSProperties {
     double subband_freq;
     casacore::MDirection delay_dir, tile_beam_dir, preapplied_beam_dir;
   };
+
+  std::vector<Station::Ptr> stations_;
   MSProperties ms_properties_;
 };
 }  // namespace telescope
diff --git a/cpp/telescope/telescope.h b/cpp/telescope/telescope.h
index 979017313c5b753f31c9f7c03d198be71c891713..f0e58671b50b31c7d96fba6589c593a98e5b61ed 100644
--- a/cpp/telescope/telescope.h
+++ b/cpp/telescope/telescope.h
@@ -24,9 +24,7 @@
 #ifndef EVERYBEAM_TELESCOPE_TELESCOPE_H_
 #define EVERYBEAM_TELESCOPE_TELESCOPE_H_
 
-#include "../station.h"
 #include "../options.h"
-#include "../elementresponse.h"
 
 #include <vector>
 #include <memory>
@@ -61,18 +59,6 @@ class Telescope {
   virtual std::unique_ptr<griddedresponse::GriddedResponse> GetGriddedResponse(
       const coords::CoordinateSystem &coordinate_system) = 0;
 
-  /**
-   * @brief Get station by index
-   *
-   * @param station_id Station index to retrieve
-   * @return Station::Ptr
-   */
-  Station::Ptr GetStation(std::size_t station_idx) const {
-    // Assert only in DEBUG mode
-    assert(station_idx < nstations_);
-    return stations_[station_idx];
-  }
-
   std::size_t GetNrStations() const { return nstations_; };
 
   Options GetOptions() const { return options_; };
@@ -82,40 +68,13 @@ class Telescope {
    * @brief Construct a new Telescope object
    *
    * @param ms MeasurementSet
-   * @param model ElementResponse model
    * @param options telescope options
    */
-  Telescope(casacore::MeasurementSet &ms, const ElementResponseModel model,
-            const Options &options)
-      : nstations_(ms.antenna().nrow()), options_(options) {
-    stations_.resize(nstations_);
-  };
-
-  /**
-   * @brief Read stations into vector
-   *
-   * @param out_it std::vector of stations
-   * @param ms measurement set
-   * @param model model
-   */
-  void ReadAllStations(const casacore::MeasurementSet &ms,
-                       const ElementResponseModel model) {
-    casacore::ROMSAntennaColumns antenna(ms.antenna());
-
-    for (std::size_t i = 0; i < antenna.nrow(); ++i) {
-      stations_[i] = ReadStation(ms, i, model);
-    }
-  };
+  Telescope(casacore::MeasurementSet &ms, const Options &options)
+      : nstations_(ms.antenna().nrow()), options_(options){};
 
   std::size_t nstations_;
   Options options_;
-  std::vector<Station::Ptr> stations_;
-
- private:
-  // Virtual method for reading a single telescope station
-  virtual Station::Ptr ReadStation(const casacore::MeasurementSet &ms,
-                                   const std::size_t id,
-                                   const ElementResponseModel model) const = 0;
 };
 }  // namespace telescope
 }  // namespace everybeam
diff --git a/cpp/telescope/vlatelescope.h b/cpp/telescope/vlatelescope.h
new file mode 100644
index 0000000000000000000000000000000000000000..854d9a143f303e9eb12d06a5a98d0e7924fb9d98
--- /dev/null
+++ b/cpp/telescope/vlatelescope.h
@@ -0,0 +1 @@
+#ifndef
diff --git a/cpp/test/CMakeLists.txt b/cpp/test/CMakeLists.txt
index bc662495c34c726ee1cecf36c84be7b0443857b6..52cc4287b5bedc147e7f67b170988329af5f0a77 100644
--- a/cpp/test/CMakeLists.txt
+++ b/cpp/test/CMakeLists.txt
@@ -1,4 +1,5 @@
 set(LOFAR_MOCK_MS CACHE STRING "LOFAR measurement set used for testing")
+set(VLA_MOCK_MS CACHE STRING "VLA measurement set used for testing")
 
 #------------------------------------------------------------------------------
 # Find boost
@@ -20,13 +21,21 @@ if(Boost_FOUND)
     include_directories(${Boost_INCLUDE_DIR})
     set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/runtests.cc)
 
-    # Test loading of LOFAR
+    # Test LOFAR beamforming
     if( LOFAR_MOCK_MS )        
         set(TEST_SOURCES 
             ${TEST_SOURCES}
             ${CMAKE_CURRENT_SOURCE_DIR}/tload_lofar.cc
         )
-    endif()    
+    endif()
+
+    # Test VLA beamforming
+    if( VLA_MOCK_MS )
+        set(TEST_SOURCES 
+            ${TEST_SOURCES}
+            ${CMAKE_CURRENT_SOURCE_DIR}/tvla.cc
+        )
+    endif()
 
     # Add test executable
     add_executable(runtests ${TEST_SOURCES})
diff --git a/cpp/test/tload_lofar.cc b/cpp/test/tload_lofar.cc
index c061eaa13c5a3cbcb552c0b3fd19ba060a218280..4958df8defcfaa453879ed2fe3f47356104fb7ab 100644
--- a/cpp/test/tload_lofar.cc
+++ b/cpp/test/tload_lofar.cc
@@ -20,7 +20,7 @@ BOOST_AUTO_TEST_CASE(load_lofar) {
 
   // Load LOFAR Telescope
   std::unique_ptr<telescope::Telescope> telescope =
-      Load(ms, response_model, options);
+      Load(ms, options, response_model);
 
   // Assert if we indeed have a LOFAR pointer
   BOOST_CHECK(nullptr != dynamic_cast<telescope::LOFAR*>(telescope.get()));
@@ -30,7 +30,9 @@ BOOST_AUTO_TEST_CASE(load_lofar) {
   BOOST_CHECK_EQUAL(telescope->GetNrStations(), nstations);
 
   // Assert if GetStation(stationd_id) behaves properly
-  BOOST_CHECK_EQUAL(telescope->GetStation(0)->GetName(), "CS001HBA0");
+  const telescope::LOFAR& lofartelescope =
+      static_cast<const telescope::LOFAR&>(*telescope.get());
+  BOOST_CHECK_EQUAL(lofartelescope.GetStation(0)->GetName(), "CS001HBA0");
 
   // Properties extracted from MS
   double time = 4929192878.008341;
@@ -86,13 +88,13 @@ BOOST_AUTO_TEST_CASE(load_lofar) {
                 1e-4);
   }
 
-  //   std::vector<std::complex<float>> antenna_buffer_all(
-  //       grid_response->GetBufferSize(telescope->GetNrStations()));
-  //   grid_response->CalculateAllStations(antenna_buffer_all.data(), time,
-  //                                       frequency);
-  //   BOOST_CHECK_EQUAL(
-  //       antenna_buffer_all.size(),
-  //       std::size_t(telescope->GetNrStations() * width * height * 2 * 2));
+  std::vector<std::complex<float>> antenna_buffer_all(
+      grid_response->GetBufferSize(telescope->GetNrStations()));
+  grid_response->CalculateAllStations(antenna_buffer_all.data(), time,
+                                      frequency);
+  BOOST_CHECK_EQUAL(
+      antenna_buffer_all.size(),
+      std::size_t(telescope->GetNrStations() * width * height * 2 * 2));
 
   // Test with differential beam, single
   Options options_diff_beam;
@@ -100,7 +102,7 @@ BOOST_AUTO_TEST_CASE(load_lofar) {
 
   // Load LOFAR Telescope
   std::unique_ptr<telescope::Telescope> telescope_diff_beam =
-      Load(ms, response_model, options_diff_beam);
+      Load(ms, options_diff_beam, response_model);
 
   std::unique_ptr<griddedresponse::GriddedResponse> grid_response_diff_beam =
       telescope_diff_beam->GetGriddedResponse(coord_system);
@@ -115,9 +117,4 @@ BOOST_AUTO_TEST_CASE(load_lofar) {
     norm_jones_mat += std::norm(antenna_buffer_diff_beam[offset_22 + i]);
   }
   BOOST_CHECK(std::abs(norm_jones_mat - 2.) < 1e-6);
-
-  // Print to np array
-  // const long unsigned leshape[] = {(long unsigned int)width, height, 2, 2};
-  // npy::SaveArrayAsNumpy("station_responses.npy", false, 4, leshape,
-  //                       antenna_buffer_single);
 }
\ No newline at end of file
diff --git a/cpp/test/tvla.cc b/cpp/test/tvla.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4a4da0bc8de7e778ee8d7598099f6916c0e7be9d
--- /dev/null
+++ b/cpp/test/tvla.cc
@@ -0,0 +1,91 @@
+#include <boost/test/unit_test.hpp>
+
+#include "../load.h"
+#include "../options.h"
+#include "../griddedresponse/dishgrid.h"
+#include "../elementresponse.h"
+#include "../../external/npy.hpp"
+
+#include "config.h"
+#include <complex>
+#include <cmath>
+
+using namespace everybeam;
+
+BOOST_AUTO_TEST_CASE(load_vla) {
+  casacore::MeasurementSet ms(VLA_MOCK_MS);
+
+  std::unique_ptr<telescope::Telescope> telescope = Load(ms);
+
+  // Assert if we indeed have a LOFAR pointer
+  BOOST_CHECK(nullptr != dynamic_cast<telescope::Dish*>(telescope.get()));
+
+  // Assert if correct number of stations
+  std::size_t nstations = 25;
+  BOOST_CHECK_EQUAL(telescope->GetNrStations(), nstations);
+
+  double time = 0.5 * (4.90683119e+09 + 4.90684196e+09);
+  double frequency = 0.5e+09;  // 1991000000.0;
+  std::size_t width(16), height(16);
+  double ra(2.62880729), dec(0.02831797), dl(0.125 * M_PI / 180.),
+      dm(0.125 * M_PI / 180.), shift_l(0.), shift_m(0.);
+
+  coords::CoordinateSystem coord_system = {.width = width,
+                                           .height = height,
+                                           .ra = ra,
+                                           .dec = dec,
+                                           .dl = dl,
+                                           .dm = dm,
+                                           .phase_centre_dl = shift_l,
+                                           .phase_centre_dm = shift_m};
+  std::unique_ptr<griddedresponse::GriddedResponse> grid_response =
+      telescope->GetGriddedResponse(coord_system);
+  BOOST_CHECK(nullptr !=
+              dynamic_cast<griddedresponse::DishGrid*>(grid_response.get()));
+
+  std::vector<std::complex<float>> antenna_buffer(
+      grid_response->GetBufferSize(telescope->GetNrStations()));
+  grid_response->CalculateAllStations(antenna_buffer.data(), time, frequency);
+
+  // Check that XX/YY are equal
+  // Loop over pixels to check that off-diagonals are 0
+  // and diagonal entries are equal
+  for (std::size_t pxl = 0; pxl < width * height; ++pxl) {
+    BOOST_CHECK(std::abs(antenna_buffer[pxl * 4 + 1]) < 1e-8);
+    BOOST_CHECK(std::abs(antenna_buffer[pxl * 4 + 2]) < 1e-8);
+    BOOST_CHECK(
+        std::abs(antenna_buffer[pxl * 4] - antenna_buffer[pxl * 4 + 3]) < 1e-8);
+  }
+
+  // Check whether pixels are reproduced correctly at certain pixels on 16x16
+  // image VLABeam output at pixel (0, 0):
+  std::vector<std::complex<float>> vla_p00 = {
+      {0.4687362, 0.}, {0, 0}, {0, 0}, {0.4687362, 0.}};
+  // VLABeam output at pixel (2, 3):
+  std::vector<std::complex<float>> vla_p23 = {
+      {0.65400606, 0.}, {0, 0}, {0, 0}, {0.65400606, 0.}};
+  // VLABeam output at pixel (10, 12):
+  std::vector<std::complex<float>> vla_p1012 = {
+      {0.8672509, 0.}, {0, 0}, {0, 0}, {0.8672509, 0.}};
+
+  // Compute offsets with everybeam
+  std::size_t offset_00 = (0 + 0 * height) * 4;
+  std::size_t offset_23 = (2 + 3 * height) * 4;
+  std::size_t offset_1012 = (10 + 12 * height) * 4;
+
+  // Check if results are reproduced
+  BOOST_CHECK_EQUAL_COLLECTIONS(antenna_buffer.begin() + offset_00,
+                                antenna_buffer.begin() + offset_00 + 4,
+                                vla_p00.begin(), vla_p00.end());
+  BOOST_CHECK_EQUAL_COLLECTIONS(antenna_buffer.begin() + offset_23,
+                                antenna_buffer.begin() + offset_23 + 4,
+                                vla_p23.begin(), vla_p23.end());
+  BOOST_CHECK_EQUAL_COLLECTIONS(antenna_buffer.begin() + offset_1012,
+                                antenna_buffer.begin() + offset_1012 + 4,
+                                vla_p1012.begin(), vla_p1012.end());
+
+  // Print to np array
+  const long unsigned leshape[] = {(long unsigned int)width, height, 2, 2};
+  npy::SaveArrayAsNumpy("vla_station_responses.npy", false, 4, leshape,
+                        antenna_buffer);
+}
\ No newline at end of file
diff --git a/scripts/download_vla_ms.sh b/scripts/download_vla_ms.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7c18ca8ed70e25d788240fb0b9cddd7337bcef51
--- /dev/null
+++ b/scripts/download_vla_ms.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# Author: Jakob Maljaars
+# Email: jakob.maljaars_@_stcorp.nl
+
+# Script for downloading a mock VLA Measurement set
+
+set -e
+
+SCRIPT_PATH=$(dirname "$0")
+cd $SCRIPT_PATH
+
+# Move up to parent folder which contains the source
+cd ..
+mkdir -p test_data
+cd test_data/
+
+VLA_MOCK_ARCHIVE=VLA_ARCHIVE.tar.bz2
+VLA_MOCK_MS=VLA_MOCK.ms
+
+if [ ! -f "$VLA_MOCK_ARCHIVE" ]; then
+    wget https://www.astron.nl/citt/EveryBeam/small-vla-set.tar.bz2 -O $VLA_MOCK_ARCHIVE
+fi
+
+if [ -d $VLA_MOCK_MS ]
+then
+    echo "Directory already exists"
+else
+    mkdir $VLA_MOCK_MS
+fi
+
+tar -xf $VLA_MOCK_ARCHIVE  -C $VLA_MOCK_MS --strip-components=1
+rm $VLA_MOCK_ARCHIVE
\ No newline at end of file