// This file is autogenerated - see gen_fieldops.py
#include <bout/field2d.hxx>
#include <bout/field3d.hxx>
#include <bout/globals.hxx>
#include <bout/interpolation.hxx>
#include <bout/mesh.hxx>
#include <bout/region.hxx>

// Provide the C++ wrapper for multiplication of Field3D and Field3D
Field3D operator*(const Field3D& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getMesh()->getCommonRegion(lhs.getRegionID(), rhs.getRegionID()));

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] * rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by multiplication with Field3D
Field3D& Field3D::operator*=(const Field3D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    regionID = fieldmesh->getCommonRegion(regionID, rhs.regionID);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs[index]; }

    track(rhs, "operator*=");

    checkData(*this);

  } else {
    track(rhs, "operator*=");
    (*this) = (*this) * rhs;
  }
  return *this;
}

// Provide the C++ wrapper for division of Field3D and Field3D
Field3D operator/(const Field3D& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getMesh()->getCommonRegion(lhs.getRegionID(), rhs.getRegionID()));

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] / rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by division with Field3D
Field3D& Field3D::operator/=(const Field3D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    regionID = fieldmesh->getCommonRegion(regionID, rhs.regionID);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs[index]; }

    track(rhs, "operator/=");

    checkData(*this);

  } else {
    track(rhs, "operator/=");
    (*this) = (*this) / rhs;
  }
  return *this;
}

// Provide the C++ wrapper for addition of Field3D and Field3D
Field3D operator+(const Field3D& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getMesh()->getCommonRegion(lhs.getRegionID(), rhs.getRegionID()));

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] + rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by addition with Field3D
Field3D& Field3D::operator+=(const Field3D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    regionID = fieldmesh->getCommonRegion(regionID, rhs.regionID);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs[index]; }

    track(rhs, "operator+=");

    checkData(*this);

  } else {
    track(rhs, "operator+=");
    (*this) = (*this) + rhs;
  }
  return *this;
}

// Provide the C++ wrapper for subtraction of Field3D and Field3D
Field3D operator-(const Field3D& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getMesh()->getCommonRegion(lhs.getRegionID(), rhs.getRegionID()));

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] - rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by subtraction with Field3D
Field3D& Field3D::operator-=(const Field3D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    regionID = fieldmesh->getCommonRegion(regionID, rhs.regionID);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs[index]; }

    track(rhs, "operator-=");

    checkData(*this);

  } else {
    track(rhs, "operator-=");
    (*this) = (*this) - rhs;
  }
  return *this;
}

// Provide the C++ wrapper for multiplication of Field3D and Field2D
Field3D operator*(const Field3D& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getRegionID());

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, rhs.getRegion("RGN_ALL")) {
    const auto base_ind = localmesh->ind2Dto3D(index);
    for (int jz = 0; jz < localmesh->LocalNz; ++jz) {
      result[base_ind + jz] = lhs[base_ind + jz] * rhs[index];
    }
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by multiplication with Field2D
Field3D& Field3D::operator*=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, rhs.getRegion("RGN_ALL")) {
      const auto base_ind = fieldmesh->ind2Dto3D(index);
      for (int jz = 0; jz < fieldmesh->LocalNz; ++jz) {
        (*this)[base_ind + jz] *= rhs[index];
      }
    }

    track(rhs, "operator*=");

    checkData(*this);

  } else {
    track(rhs, "operator*=");
    (*this) = (*this) * rhs;
  }
  return *this;
}

// Provide the C++ wrapper for division of Field3D and Field2D
Field3D operator/(const Field3D& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getRegionID());

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, rhs.getRegion("RGN_ALL")) {
    const auto base_ind = localmesh->ind2Dto3D(index);
    const auto tmp = 1.0 / rhs[index];
    for (int jz = 0; jz < localmesh->LocalNz; ++jz) {
      result[base_ind + jz] = lhs[base_ind + jz] * tmp;
    }
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by division with Field2D
Field3D& Field3D::operator/=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, rhs.getRegion("RGN_ALL")) {
      const auto base_ind = fieldmesh->ind2Dto3D(index);
      const auto tmp = 1.0 / rhs[index];
      for (int jz = 0; jz < fieldmesh->LocalNz; ++jz) {
        (*this)[base_ind + jz] *= tmp;
      }
    }

    track(rhs, "operator/=");

    checkData(*this);

  } else {
    track(rhs, "operator/=");
    (*this) = (*this) / rhs;
  }
  return *this;
}

// Provide the C++ wrapper for addition of Field3D and Field2D
Field3D operator+(const Field3D& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getRegionID());

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, rhs.getRegion("RGN_ALL")) {
    const auto base_ind = localmesh->ind2Dto3D(index);
    for (int jz = 0; jz < localmesh->LocalNz; ++jz) {
      result[base_ind + jz] = lhs[base_ind + jz] + rhs[index];
    }
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by addition with Field2D
Field3D& Field3D::operator+=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, rhs.getRegion("RGN_ALL")) {
      const auto base_ind = fieldmesh->ind2Dto3D(index);
      for (int jz = 0; jz < fieldmesh->LocalNz; ++jz) {
        (*this)[base_ind + jz] += rhs[index];
      }
    }

    track(rhs, "operator+=");

    checkData(*this);

  } else {
    track(rhs, "operator+=");
    (*this) = (*this) + rhs;
  }
  return *this;
}

// Provide the C++ wrapper for subtraction of Field3D and Field2D
Field3D operator-(const Field3D& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getRegionID());

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, rhs.getRegion("RGN_ALL")) {
    const auto base_ind = localmesh->ind2Dto3D(index);
    for (int jz = 0; jz < localmesh->LocalNz; ++jz) {
      result[base_ind + jz] = lhs[base_ind + jz] - rhs[index];
    }
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by subtraction with Field2D
Field3D& Field3D::operator-=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, rhs.getRegion("RGN_ALL")) {
      const auto base_ind = fieldmesh->ind2Dto3D(index);
      for (int jz = 0; jz < fieldmesh->LocalNz; ++jz) {
        (*this)[base_ind + jz] -= rhs[index];
      }
    }

    track(rhs, "operator-=");

    checkData(*this);

  } else {
    track(rhs, "operator-=");
    (*this) = (*this) - rhs;
  }
  return *this;
}

// Provide the C++ wrapper for multiplication of Field3D and FieldPerp
FieldPerp operator*(const Field3D& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = rhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[base_ind] * rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for division of Field3D and FieldPerp
FieldPerp operator/(const Field3D& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = rhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[base_ind] / rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for addition of Field3D and FieldPerp
FieldPerp operator+(const Field3D& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = rhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[base_ind] + rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for subtraction of Field3D and FieldPerp
FieldPerp operator-(const Field3D& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = rhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[base_ind] - rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for multiplication of Field3D and BoutReal
Field3D operator*(const Field3D& lhs, const BoutReal rhs) {

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getRegionID());

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] * rhs;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by multiplication with BoutReal
Field3D& Field3D::operator*=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs; }

    track(rhs, "operator*=");

    checkData(*this);

  } else {
    track(rhs, "operator*=");
    (*this) = (*this) * rhs;
  }
  return *this;
}

// Provide the C++ wrapper for division of Field3D and BoutReal
Field3D operator/(const Field3D& lhs, const BoutReal rhs) {

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getRegionID());

  const auto tmp = 1.0 / rhs;
  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] * tmp;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by division with BoutReal
Field3D& Field3D::operator/=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    const auto tmp = 1.0 / rhs;
    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= tmp; }

    track(rhs, "operator/=");

    checkData(*this);

  } else {
    track(rhs, "operator/=");
    (*this) = (*this) / rhs;
  }
  return *this;
}

// Provide the C++ wrapper for addition of Field3D and BoutReal
Field3D operator+(const Field3D& lhs, const BoutReal rhs) {

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getRegionID());

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] + rhs;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by addition with BoutReal
Field3D& Field3D::operator+=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs; }

    track(rhs, "operator+=");

    checkData(*this);

  } else {
    track(rhs, "operator+=");
    (*this) = (*this) + rhs;
  }
  return *this;
}

// Provide the C++ wrapper for subtraction of Field3D and BoutReal
Field3D operator-(const Field3D& lhs, const BoutReal rhs) {

  Field3D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(lhs.getRegionID());

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] - rhs;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field3D by subtraction with BoutReal
Field3D& Field3D::operator-=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    // Delete existing parallel slices. We don't copy parallel slices, so any
    // that currently exist will be incorrect.
    clearParallelSlices();

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs; }

    track(rhs, "operator-=");

    checkData(*this);

  } else {
    track(rhs, "operator-=");
    (*this) = (*this) - rhs;
  }
  return *this;
}

// Provide the C++ wrapper for multiplication of Field2D and Field3D
Field3D operator*(const Field2D& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(rhs.getRegionID());

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, lhs.getRegion("RGN_ALL")) {
    const auto base_ind = localmesh->ind2Dto3D(index);
    for (int jz = 0; jz < localmesh->LocalNz; ++jz) {
      result[base_ind + jz] = lhs[index] * rhs[base_ind + jz];
    }
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for division of Field2D and Field3D
Field3D operator/(const Field2D& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(rhs.getRegionID());

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, lhs.getRegion("RGN_ALL")) {
    const auto base_ind = localmesh->ind2Dto3D(index);
    for (int jz = 0; jz < localmesh->LocalNz; ++jz) {
      result[base_ind + jz] = lhs[index] / rhs[base_ind + jz];
    }
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for addition of Field2D and Field3D
Field3D operator+(const Field2D& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(rhs.getRegionID());

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, lhs.getRegion("RGN_ALL")) {
    const auto base_ind = localmesh->ind2Dto3D(index);
    for (int jz = 0; jz < localmesh->LocalNz; ++jz) {
      result[base_ind + jz] = lhs[index] + rhs[base_ind + jz];
    }
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for subtraction of Field2D and Field3D
Field3D operator-(const Field2D& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field3D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(rhs.getRegionID());

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, lhs.getRegion("RGN_ALL")) {
    const auto base_ind = localmesh->ind2Dto3D(index);
    for (int jz = 0; jz < localmesh->LocalNz; ++jz) {
      result[base_ind + jz] = lhs[index] - rhs[base_ind + jz];
    }
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for multiplication of Field2D and Field2D
Field2D operator*(const Field2D& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field2D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] * rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field2D by multiplication with Field2D
Field2D& Field2D::operator*=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs[index]; }

    checkData(*this);

  } else {
    (*this) = (*this) * rhs;
  }
  return *this;
}

// Provide the C++ wrapper for division of Field2D and Field2D
Field2D operator/(const Field2D& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field2D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] / rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field2D by division with Field2D
Field2D& Field2D::operator/=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs[index]; }

    checkData(*this);

  } else {
    (*this) = (*this) / rhs;
  }
  return *this;
}

// Provide the C++ wrapper for addition of Field2D and Field2D
Field2D operator+(const Field2D& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field2D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] + rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field2D by addition with Field2D
Field2D& Field2D::operator+=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs[index]; }

    checkData(*this);

  } else {
    (*this) = (*this) + rhs;
  }
  return *this;
}

// Provide the C++ wrapper for subtraction of Field2D and Field2D
Field2D operator-(const Field2D& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  Field2D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] - rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field2D by subtraction with Field2D
Field2D& Field2D::operator-=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs[index]; }

    checkData(*this);

  } else {
    (*this) = (*this) - rhs;
  }
  return *this;
}

// Provide the C++ wrapper for multiplication of Field2D and FieldPerp
FieldPerp operator*(const Field2D& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = rhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[base_ind] * rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for division of Field2D and FieldPerp
FieldPerp operator/(const Field2D& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = rhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[base_ind] / rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for addition of Field2D and FieldPerp
FieldPerp operator+(const Field2D& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = rhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[base_ind] + rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for subtraction of Field2D and FieldPerp
FieldPerp operator-(const Field2D& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = rhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[base_ind] - rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for multiplication of Field2D and BoutReal
Field2D operator*(const Field2D& lhs, const BoutReal rhs) {

  Field2D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] * rhs;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field2D by multiplication with BoutReal
Field2D& Field2D::operator*=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs; }

    checkData(*this);

  } else {
    (*this) = (*this) * rhs;
  }
  return *this;
}

// Provide the C++ wrapper for division of Field2D and BoutReal
Field2D operator/(const Field2D& lhs, const BoutReal rhs) {

  Field2D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  const auto tmp = 1.0 / rhs;
  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] * tmp;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field2D by division with BoutReal
Field2D& Field2D::operator/=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    checkData(*this);
    checkData(rhs);

    const auto tmp = 1.0 / rhs;
    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= tmp; }

    checkData(*this);

  } else {
    (*this) = (*this) / rhs;
  }
  return *this;
}

// Provide the C++ wrapper for addition of Field2D and BoutReal
Field2D operator+(const Field2D& lhs, const BoutReal rhs) {

  Field2D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] + rhs;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field2D by addition with BoutReal
Field2D& Field2D::operator+=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs; }

    checkData(*this);

  } else {
    (*this) = (*this) + rhs;
  }
  return *this;
}

// Provide the C++ wrapper for subtraction of Field2D and BoutReal
Field2D operator-(const Field2D& lhs, const BoutReal rhs) {

  Field2D result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] - rhs;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update Field2D by subtraction with BoutReal
Field2D& Field2D::operator-=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs; }

    checkData(*this);

  } else {
    (*this) = (*this) - rhs;
  }
  return *this;
}

// Provide the C++ wrapper for multiplication of FieldPerp and Field3D
FieldPerp operator*(const FieldPerp& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = lhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[index] * rhs[base_ind];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by multiplication with Field3D
FieldPerp& FieldPerp::operator*=(const Field3D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    Mesh* localmesh = this->getMesh();

    BOUT_FOR(index, this->getRegion("RGN_ALL")) {
      int yind = this->getIndex();
      const auto base_ind = localmesh->indPerpto3D(index, yind);
      (*this)[index] *= rhs[base_ind];
    }

    checkData(*this);

  } else {
    (*this) = (*this) * rhs;
  }
  return *this;
}

// Provide the C++ wrapper for division of FieldPerp and Field3D
FieldPerp operator/(const FieldPerp& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = lhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[index] / rhs[base_ind];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by division with Field3D
FieldPerp& FieldPerp::operator/=(const Field3D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    Mesh* localmesh = this->getMesh();

    BOUT_FOR(index, this->getRegion("RGN_ALL")) {
      int yind = this->getIndex();
      const auto base_ind = localmesh->indPerpto3D(index, yind);
      (*this)[index] /= rhs[base_ind];
    }

    checkData(*this);

  } else {
    (*this) = (*this) / rhs;
  }
  return *this;
}

// Provide the C++ wrapper for addition of FieldPerp and Field3D
FieldPerp operator+(const FieldPerp& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = lhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[index] + rhs[base_ind];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by addition with Field3D
FieldPerp& FieldPerp::operator+=(const Field3D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    Mesh* localmesh = this->getMesh();

    BOUT_FOR(index, this->getRegion("RGN_ALL")) {
      int yind = this->getIndex();
      const auto base_ind = localmesh->indPerpto3D(index, yind);
      (*this)[index] += rhs[base_ind];
    }

    checkData(*this);

  } else {
    (*this) = (*this) + rhs;
  }
  return *this;
}

// Provide the C++ wrapper for subtraction of FieldPerp and Field3D
FieldPerp operator-(const FieldPerp& lhs, const Field3D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = lhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[index] - rhs[base_ind];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by subtraction with Field3D
FieldPerp& FieldPerp::operator-=(const Field3D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    Mesh* localmesh = this->getMesh();

    BOUT_FOR(index, this->getRegion("RGN_ALL")) {
      int yind = this->getIndex();
      const auto base_ind = localmesh->indPerpto3D(index, yind);
      (*this)[index] -= rhs[base_ind];
    }

    checkData(*this);

  } else {
    (*this) = (*this) - rhs;
  }
  return *this;
}

// Provide the C++ wrapper for multiplication of FieldPerp and Field2D
FieldPerp operator*(const FieldPerp& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = lhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[index] * rhs[base_ind];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by multiplication with Field2D
FieldPerp& FieldPerp::operator*=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    Mesh* localmesh = this->getMesh();

    BOUT_FOR(index, this->getRegion("RGN_ALL")) {
      int yind = this->getIndex();
      const auto base_ind = localmesh->indPerpto3D(index, yind);
      (*this)[index] *= rhs[base_ind];
    }

    checkData(*this);

  } else {
    (*this) = (*this) * rhs;
  }
  return *this;
}

// Provide the C++ wrapper for division of FieldPerp and Field2D
FieldPerp operator/(const FieldPerp& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = lhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[index] / rhs[base_ind];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by division with Field2D
FieldPerp& FieldPerp::operator/=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    Mesh* localmesh = this->getMesh();

    BOUT_FOR(index, this->getRegion("RGN_ALL")) {
      int yind = this->getIndex();
      const auto base_ind = localmesh->indPerpto3D(index, yind);
      (*this)[index] /= rhs[base_ind];
    }

    checkData(*this);

  } else {
    (*this) = (*this) / rhs;
  }
  return *this;
}

// Provide the C++ wrapper for addition of FieldPerp and Field2D
FieldPerp operator+(const FieldPerp& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = lhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[index] + rhs[base_ind];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by addition with Field2D
FieldPerp& FieldPerp::operator+=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    Mesh* localmesh = this->getMesh();

    BOUT_FOR(index, this->getRegion("RGN_ALL")) {
      int yind = this->getIndex();
      const auto base_ind = localmesh->indPerpto3D(index, yind);
      (*this)[index] += rhs[base_ind];
    }

    checkData(*this);

  } else {
    (*this) = (*this) + rhs;
  }
  return *this;
}

// Provide the C++ wrapper for subtraction of FieldPerp and Field2D
FieldPerp operator-(const FieldPerp& lhs, const Field2D& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  Mesh* localmesh = lhs.getMesh();

  BOUT_FOR(index, result.getRegion("RGN_ALL")) {
    int yind = lhs.getIndex();
    const auto base_ind = localmesh->indPerpto3D(index, yind);
    result[index] = lhs[index] - rhs[base_ind];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by subtraction with Field2D
FieldPerp& FieldPerp::operator-=(const Field2D& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    Mesh* localmesh = this->getMesh();

    BOUT_FOR(index, this->getRegion("RGN_ALL")) {
      int yind = this->getIndex();
      const auto base_ind = localmesh->indPerpto3D(index, yind);
      (*this)[index] -= rhs[base_ind];
    }

    checkData(*this);

  } else {
    (*this) = (*this) - rhs;
  }
  return *this;
}

// Provide the C++ wrapper for multiplication of FieldPerp and FieldPerp
FieldPerp operator*(const FieldPerp& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] * rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by multiplication with FieldPerp
FieldPerp& FieldPerp::operator*=(const FieldPerp& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs[index]; }

    checkData(*this);

  } else {
    (*this) = (*this) * rhs;
  }
  return *this;
}

// Provide the C++ wrapper for division of FieldPerp and FieldPerp
FieldPerp operator/(const FieldPerp& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] / rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by division with FieldPerp
FieldPerp& FieldPerp::operator/=(const FieldPerp& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs[index]; }

    checkData(*this);

  } else {
    (*this) = (*this) / rhs;
  }
  return *this;
}

// Provide the C++ wrapper for addition of FieldPerp and FieldPerp
FieldPerp operator+(const FieldPerp& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] + rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by addition with FieldPerp
FieldPerp& FieldPerp::operator+=(const FieldPerp& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs[index]; }

    checkData(*this);

  } else {
    (*this) = (*this) + rhs;
  }
  return *this;
}

// Provide the C++ wrapper for subtraction of FieldPerp and FieldPerp
FieldPerp operator-(const FieldPerp& lhs, const FieldPerp& rhs) {
  ASSERT1_FIELDS_COMPATIBLE(lhs, rhs);

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] - rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by subtraction with FieldPerp
FieldPerp& FieldPerp::operator-=(const FieldPerp& rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {
    ASSERT1_FIELDS_COMPATIBLE(*this, rhs);

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs[index]; }

    checkData(*this);

  } else {
    (*this) = (*this) - rhs;
  }
  return *this;
}

// Provide the C++ wrapper for multiplication of FieldPerp and BoutReal
FieldPerp operator*(const FieldPerp& lhs, const BoutReal rhs) {

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] * rhs;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by multiplication with BoutReal
FieldPerp& FieldPerp::operator*=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] *= rhs; }

    checkData(*this);

  } else {
    (*this) = (*this) * rhs;
  }
  return *this;
}

// Provide the C++ wrapper for division of FieldPerp and BoutReal
FieldPerp operator/(const FieldPerp& lhs, const BoutReal rhs) {

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  const auto tmp = 1.0 / rhs;
  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] * tmp;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by division with BoutReal
FieldPerp& FieldPerp::operator/=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] /= rhs; }

    checkData(*this);

  } else {
    (*this) = (*this) / rhs;
  }
  return *this;
}

// Provide the C++ wrapper for addition of FieldPerp and BoutReal
FieldPerp operator+(const FieldPerp& lhs, const BoutReal rhs) {

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] + rhs;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by addition with BoutReal
FieldPerp& FieldPerp::operator+=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] += rhs; }

    checkData(*this);

  } else {
    (*this) = (*this) + rhs;
  }
  return *this;
}

// Provide the C++ wrapper for subtraction of FieldPerp and BoutReal
FieldPerp operator-(const FieldPerp& lhs, const BoutReal rhs) {

  FieldPerp result{emptyFrom(lhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs[index] - rhs;
  }

  checkData(result);
  return result;
}

// Provide the C++ operator to update FieldPerp by subtraction with BoutReal
FieldPerp& FieldPerp::operator-=(const BoutReal rhs) {
  // only if data is unique we update the field
  // otherwise just call the non-inplace version
  if (data.unique()) {

    checkData(*this);
    checkData(rhs);

    BOUT_FOR(index, this->getRegion("RGN_ALL")) { (*this)[index] -= rhs; }

    checkData(*this);

  } else {
    (*this) = (*this) - rhs;
  }
  return *this;
}

// Provide the C++ wrapper for multiplication of BoutReal and Field3D
Field3D operator*(const BoutReal lhs, const Field3D& rhs) {

  Field3D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(rhs.getRegionID());

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs * rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for division of BoutReal and Field3D
Field3D operator/(const BoutReal lhs, const Field3D& rhs) {

  Field3D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(rhs.getRegionID());

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs / rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for addition of BoutReal and Field3D
Field3D operator+(const BoutReal lhs, const Field3D& rhs) {

  Field3D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(rhs.getRegionID());

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs + rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for subtraction of BoutReal and Field3D
Field3D operator-(const BoutReal lhs, const Field3D& rhs) {

  Field3D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  result.setRegion(rhs.getRegionID());

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs - rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for multiplication of BoutReal and Field2D
Field2D operator*(const BoutReal lhs, const Field2D& rhs) {

  Field2D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs * rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for division of BoutReal and Field2D
Field2D operator/(const BoutReal lhs, const Field2D& rhs) {

  Field2D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs / rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for addition of BoutReal and Field2D
Field2D operator+(const BoutReal lhs, const Field2D& rhs) {

  Field2D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs + rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for subtraction of BoutReal and Field2D
Field2D operator-(const BoutReal lhs, const Field2D& rhs) {

  Field2D result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs - rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for multiplication of BoutReal and FieldPerp
FieldPerp operator*(const BoutReal lhs, const FieldPerp& rhs) {

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs * rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for division of BoutReal and FieldPerp
FieldPerp operator/(const BoutReal lhs, const FieldPerp& rhs) {

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs / rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for addition of BoutReal and FieldPerp
FieldPerp operator+(const BoutReal lhs, const FieldPerp& rhs) {

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs + rhs[index];
  }

  checkData(result);
  return result;
}

// Provide the C++ wrapper for subtraction of BoutReal and FieldPerp
FieldPerp operator-(const BoutReal lhs, const FieldPerp& rhs) {

  FieldPerp result{emptyFrom(rhs)};
  checkData(lhs);
  checkData(rhs);

  BOUT_FOR(index, result.getValidRegionWithDefault("RGN_ALL")) {
    result[index] = lhs - rhs[index];
  }

  checkData(result);
  return result;
}
