diff --git a/CMakeLists.txt b/CMakeLists.txt
index 51fad484aaabb0b890aed4790dda6f796c40b94d..99b15a890a11da441305fd2bdafb532f03baedcc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,7 +28,7 @@ endif()
 # Enable loading dependencies in subdirectories.
 cmake_policy(SET CMP0079 NEW)
 
-set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD 20)
 set(CMAKE_CXX_STANDARD_REQUIRED YES)
 set(CMAKE_CXX_EXTENSIONS NO)
 set(CMAKE_CXX_VISIBILITY_PRESET hidden)
diff --git a/docker/ubuntu_20_04_base b/docker/ubuntu_20_04_base
index 37f9d43440cb75f1fc67ad0bc379b00bba596c7f..6f5212e475ab5bd41838a5b6a667e2c2ecaa9510 100644
--- a/docker/ubuntu_20_04_base
+++ b/docker/ubuntu_20_04_base
@@ -7,9 +7,50 @@ RUN export DEBIAN_FRONTEND=noninteractive \
     && apt-get update && apt-get upgrade -y \
 # install astronomy packages
     && apt-get -y install libcfitsio-dev wcslib-dev libfftw3-dev libgsl-dev \
-# install misc packages
-    wget git make cmake g++ doxygen \
+# install misc packages. g++-10 is required for C++20.
+    wget git make cmake g++-10 doxygen \
 # install dependencies
-    libboost-all-dev libhdf5-dev libpython3-dev python3-pip \
-    casacore-dev casacore-tools \
+    libboost-date-time-dev \
+    libboost-filesystem-dev \
+    libboost-system-dev \
+    libboost-test-dev \
+    libhdf5-dev \
+    libpython3-dev \
+    python3-pip \
+# For casacore
+    bison \
+    flex \
+    gfortran \
+    python3-dev \
+    python3-numpy \
+    libboost-python-dev \
+    libblas-dev \
+    liblapack-dev \
+    libreadline-dev \
     && rm -rf /var/lib/apt/lists/*
+
+ENV CC /usr/bin/gcc-10
+ENV CXX /usr/bin/g++-10
+
+# Install WSRT Measures (extra casacore data, for integration tests)
+# Note: The file on the ftp site is updated daily. When warnings regarding leap
+# seconds appear, ignore them or regenerate the docker image.
+RUN wget -nv -O /WSRT_Measures.ztar ftp://ftp.astron.nl/outgoing/Measures/WSRT_Measures.ztar \
+  && mkdir -p /var/lib/casacore/data \
+	&& cd /var/lib/casacore/data \
+	&& tar xfz /WSRT_Measures.ztar \
+	&& rm /WSRT_Measures.ztar
+# Casacore
+RUN mkdir /external && \
+  cd /external && \
+  git clone https://github.com/casacore/casacore.git && \
+  cd /external/casacore && \
+  git checkout 4c661342faf74c56ea15ecdfc6f2ff4a58072e76 && \
+  mkdir build && \
+  cd build && \
+  cmake .. -DBUILD_PYTHON=OFF -DBUILD_TESTING=OFF -DDATA_DIR=/var/lib/casacore/data && \
+  make -j`nproc` && \
+  make install -j`nproc` && \
+  cd /external && \
+  rm -rf /external/casacore
+
diff --git a/docker/ubuntu_22_04_base b/docker/ubuntu_22_04_base
index f7c4aab0af8096cde557f7a5be83cf3fe4a4553c..edc4dce1ac483e30c785b97b38f25146d00c4ba7 100644
--- a/docker/ubuntu_22_04_base
+++ b/docker/ubuntu_22_04_base
@@ -10,11 +10,50 @@ RUN export DEBIAN_FRONTEND=noninteractive \
 # install misc packages
     wget git make cmake g++ doxygen \
 # install dependencies
-    libboost-all-dev libhdf5-dev libpython3-dev python3-pip \
-    casacore-dev casacore-tools clang-format-12 clang-tidy-12 \
+    libboost-date-time-dev \
+    libboost-filesystem-dev \
+    libboost-system-dev \
+    libboost-test-dev \
+    libhdf5-dev \
+    libpython3-dev \
+    python3-pip \
+    clang-format-15 \
+    clang-tidy-15 \
+# For casacore
+    bison \
+    flex \
+    gfortran \
+    python3-dev \
+    python3-numpy \
+    libboost-python-dev \
+    libblas-dev \
+    liblapack-dev \
+    libreadline-dev \
     && rm -rf /var/lib/apt/lists/* \
-# The formatter needs a binary named 'clang-format', not 'clang-format-12'.
-# Same for clang-tidy-12.
-    && ln -sf clang-format-12 /usr/bin/clang-format \
-    && ln -sf clang-tidy-12 /usr/bin/clang-tidy \
+# The formatter needs a binary named 'clang-format', not 'clang-format-15'.
+# Same for clang-tidy-15.
+    && ln -sf clang-format-15 /usr/bin/clang-format \
+    && ln -sf clang-tidy-15 /usr/bin/clang-tidy \
     && python3 -m pip install gcovr black cmake-format isort
+
+# Install WSRT Measures (extra casacore data, for integration tests)
+# Note: The file on the ftp site is updated daily. When warnings regarding leap
+# seconds appear, ignore them or regenerate the docker image.
+RUN wget -nv -O /WSRT_Measures.ztar ftp://ftp.astron.nl/outgoing/Measures/WSRT_Measures.ztar \
+  && mkdir -p /var/lib/casacore/data \
+	&& cd /var/lib/casacore/data \
+	&& tar xfz /WSRT_Measures.ztar \
+	&& rm /WSRT_Measures.ztar
+# Casacore
+RUN mkdir /external && \
+  cd /external && \
+  git clone https://github.com/casacore/casacore.git && \
+  cd /external/casacore && \
+  git checkout 4c661342faf74c56ea15ecdfc6f2ff4a58072e76 && \
+  mkdir build && \
+  cd build && \
+  cmake .. -DBUILD_PYTHON=OFF -DBUILD_TESTING=OFF -DDATA_DIR=/var/lib/casacore/data && \
+  make -j`nproc` && \
+  make install -j`nproc` && \
+  cd /external && \
+  rm -rf /external/casacore
diff --git a/include/schaapcommon/facets/ds9facetfile.h b/include/schaapcommon/facets/ds9facetfile.h
index 6d5270914acbc86d82ae15ab9b941e2cf99fac86..bd02e4366a9919dfd2bf832380e632db8ce749fa 100644
--- a/include/schaapcommon/facets/ds9facetfile.h
+++ b/include/schaapcommon/facets/ds9facetfile.h
@@ -238,7 +238,7 @@ class DS9FacetFile {
     }
     const double ra = vals[0] * (M_PI / 180.0);
     const double dec = vals[1] * (M_PI / 180.0);
-    return Coord(ra, dec);
+    return {ra, dec};
   }
 
   std::vector<double> ReadNumList() {
diff --git a/scripts/format.sh b/scripts/format.sh
index 41ac7b18ff631f2dcf929f70dd8a06e22c2a3be4..e96c55a2f2eb63b77fd505e56dc448f05a40c16c 100644
--- a/scripts/format.sh
+++ b/scripts/format.sh
@@ -79,7 +79,7 @@ PYTHON_FILES=$(git ls-files $PYTHON_FILES_EXCLUDEDIRS)
 BLACK="black -l 79"
 
 # Sort imports according to PEP-8
-ISORT="isort --profile black"
+ISORT="isort --profile black -l 79"
 
 if [[ "${CLANG_FORMAT_BINARY}" == "" ]] ; then
     CLANG_FORMAT_BINARY="clang-format"
diff --git a/src/facets/facet.cc b/src/facets/facet.cc
index a7d800515dd9d0e7d21a752fb090f3a1189b2871..aa557dfe977660ff0955391aa7c730eea35f8b37 100644
--- a/src/facets/facet.cc
+++ b/src/facets/facet.cc
@@ -112,7 +112,7 @@ PixelPosition Facet::Centroid() const {
 
   point_f x{};
   boost::geometry::centroid(poly, x);
-  return PixelPosition(x.get<0>(), x.get<1>());
+  return {int(x.get<0>()), int(x.get<1>())};
 }
 
 namespace {
diff --git a/src/facets/facetimage.cc b/src/facets/facetimage.cc
index ee0e8208aa066eab7952a40d3ccc6c5faac385d5..bdd084c934225e48086eeb8ab9db507bc9d4e8f8 100644
--- a/src/facets/facetimage.cc
+++ b/src/facets/facetimage.cc
@@ -36,8 +36,8 @@ void FacetImage::SetFacet(const Facet& facet, bool trimmed) {
 }
 
 FacetImage& FacetImage::operator*=(float factor) {
-  for (size_t term = 0; term != data_.size(); ++term) {
-    for (auto& val : data_[term]) val *= factor;
+  for (std::vector<float>& term : data_) {
+    for (float& val : term) val *= factor;
   }
   return *this;
 }
diff --git a/src/fitters/nlplfitter.cc b/src/fitters/nlplfitter.cc
index 4750cbe177fca9acaea66123f4a7f2de7fc93827..5cdd4c2e9e5669838d565535da78910e9c4e23b5 100644
--- a/src/fitters/nlplfitter.cc
+++ b/src/fitters/nlplfitter.cc
@@ -216,8 +216,8 @@ void NonLinearPowerLawFitter::Fit(NumT& exponent, NumT& factor) {
   } else {
     exponent = 0.0;
     factor = 0.0;
-    for (size_t i = 0; i != data_->points.size(); ++i) {
-      factor += data_->points[i].second;
+    for (const std::pair<double, double>& point : data_->points) {
+      factor += point.second;
     }
     factor /= NumT(data_->points.size());
   }