diff --git a/algo/ca/core/pars/CaField.cxx b/algo/ca/core/pars/CaField.cxx
index 99b8ca5f21d171921d287aa6f25d4825692bab69..dcfcbdb625f536d4739d001e2cf8284501c311ee 100644
--- a/algo/ca/core/pars/CaField.cxx
+++ b/algo/ca/core/pars/CaField.cxx
@@ -3,225 +3,3 @@
    Authors: Sergey Gorbunov, Sergei Zharko [committer] */
 
 #include "CaField.h"
-
-#include "KfUtils.h"
-
-#include <iomanip>
-#include <iostream>
-#include <sstream>
-
-using namespace cbm::algo::ca;
-
-
-template<typename DataT>
-bool FieldRegion<DataT>::fgForceUseOfOriginalField = false;
-
-template<typename DataT>
-std::function<std::tuple<double, double, double>(double x, double y, double z)>
-  FieldRegion<DataT>::fgOriginalField([](double, double, double) {
-    assert(false && "ca::FieldRegion: The original field is not set, use cbm::ca::tools::SetCbmField()");
-    return std::tuple(kfdefs::Undef<double>, kfdefs::Undef<double>, kfdefs::Undef<double>);
-  });
-
-template<typename DataT>
-bool FieldRegion<DataT>::fgIsZeroOriginalField = false;
-
-
-//
-// FieldRegion methdos
-//
-
-//----------------------------------------------------------------------------------------------------------------------
-//
-template<typename DataT>
-FieldRegion<DataT>::FieldRegion(float reg[10]) noexcept
-  : cx0(reg[0])
-  , cx1(reg[1])
-  , cx2(reg[2])
-  , cy0(reg[3])
-  , cy1(reg[4])
-  , cy2(reg[5])
-  , cz0(reg[6])
-  , cz1(reg[7])
-  , cz2(reg[8])
-  , z0(reg[9])
-{
-}
-
-//----------------------------------------------------------------------------------------------------------------------
-//
-template<typename DataT>
-void FieldRegion<DataT>::CheckConsistency() const
-{
-  // Check SIMD data vectors for consistent initialization
-  kfutils::CheckSimdVectorEquality(cx0, "FieldRegion::cx0");
-  kfutils::CheckSimdVectorEquality(cx1, "FieldRegion::cx1");
-  kfutils::CheckSimdVectorEquality(cx2, "FieldRegion::cx2");
-  kfutils::CheckSimdVectorEquality(cy0, "FieldRegion::cy0");
-  kfutils::CheckSimdVectorEquality(cy1, "FieldRegion::cy1");
-  kfutils::CheckSimdVectorEquality(cy2, "FieldRegion::cy2");
-  kfutils::CheckSimdVectorEquality(cz0, "FieldRegion::cz0");
-  kfutils::CheckSimdVectorEquality(cz1, "FieldRegion::cz1");
-  kfutils::CheckSimdVectorEquality(cz2, "FieldRegion::cz2");
-  kfutils::CheckSimdVectorEquality(z0, "FieldRegion::z0");
-  // TODO: Any other checks? (S.Zharko)
-}
-
-
-//----------------------------------------------------------------------------------------------------------------------
-// TODO: Should it be inline? (S.Zharko)
-template<typename DataT>
-FieldValue<DataT> FieldRegion<DataT>::Get(const DataT& x, const DataT& y, const DataT& z) const
-{
-  FieldValue<DataT> B;
-  if (fgForceUseOfOriginalField || fUseOriginalField) {
-    // TODO: ? Why the simd words are set indvidually?
-    for (size_t i = 0; i < kfutils::simd::Size<DataT>(); i++) {
-      auto [bx, by, bz] =
-        fgOriginalField(kfutils::simd::Cast<DataT, double>(x, i), kfutils::simd::Cast<DataT, double>(y, i),
-                        kfutils::simd::Cast<DataT, double>(z, i));
-      B.SetSimdEntry(bx, by, bz, i);
-    }
-  }
-  else {
-    DataT dz  = z - z0;
-    DataT dz2 = dz * dz;
-    B.Set(cx0 + cx1 * dz + cx2 * dz2,   // Bx
-          cy0 + cy1 * dz + cy2 * dz2,   // By
-          cz0 + cz1 * dz + cz2 * dz2);  // Bz
-  }
-  return B;
-}
-
-
-//----------------------------------------------------------------------------------------------------------------------
-template<typename T>
-std::tuple<T, T, T> FieldRegion<T>::GetDoubleIntegrals(const T& /*x1*/, const T& /*y1*/, const T& z1,  //
-                                                       const T& /*x2*/, const T& /*y2*/, const T& z2) const
-{
-  // double integral of the field along z
-
-  if (fUseOriginalField) {
-    // TODO: implement the double integral for the original field
-    assert(false && "FieldRegion::GetDoubleIntegrals() is not implemented for the original field");
-  }
-
-  auto fld = *this;
-  fld.Shift(z1);
-  T dz  = z2 - z1;
-  T dz2 = dz * dz;
-  T c0  = dz2 * T(1. / 2.);
-  T c1  = dz2 * dz * T(1. / 6.);
-  T c2  = dz2 * dz2 * T(1. / 12.);
-  return {c0 * fld.cx0 + c1 * fld.cx1 + c2 * fld.cx2,  //
-          c0 * fld.cy0 + c1 * fld.cy1 + c2 * fld.cy2,  //
-          c0 * fld.cz0 + c1 * fld.cz1 + c2 * fld.cz2};
-}
-
-
-//----------------------------------------------------------------------------------------------------------------------
-// TODO: Should it be inline? (S.Zharko)
-template<typename DataT>
-void FieldRegion<DataT>::Set(const FieldValue<DataT>& b0, const DataT b0z, const FieldValue<DataT>& b1, const DataT b1z,
-                             const FieldValue<DataT>& b2, const DataT b2z)
-{
-  fIsZeroField = (b0.IsZero() && b1.IsZero() && b2.IsZero());
-
-  z0        = b0z;
-  DataT dz1 = b1z - b0z;
-  DataT dz2 = b2z - b0z;
-  DataT det = kfutils::simd::One<DataT>() / (dz1 * dz2 * (b2z - b1z));
-
-  DataT w21 = -dz2 * det;
-  DataT w22 = dz1 * det;
-  DataT w11 = -dz2 * w21;
-  DataT w12 = -dz1 * w22;
-
-  DataT db1 = b1.GetBx() - b0.GetBx();
-  DataT db2 = b2.GetBx() - b0.GetBx();
-  cx0       = b0.GetBx();
-  cx1       = db1 * w11 + db2 * w12;
-  cx2       = db1 * w21 + db2 * w22;
-
-  db1 = b1.GetBy() - b0.GetBy();
-  db2 = b2.GetBy() - b0.GetBy();
-  cy0 = b0.GetBy();
-  cy1 = db1 * w11 + db2 * w12;
-  cy2 = db1 * w21 + db2 * w22;
-
-  db1 = b1.GetBz() - b0.GetBz();
-  db2 = b2.GetBz() - b0.GetBz();
-  cz0 = b0.GetBz();
-  cz1 = db1 * w11 + db2 * w12;
-  cz2 = db1 * w21 + db2 * w22;
-}
-
-//----------------------------------------------------------------------------------------------------------------------
-// TODO: Should it be inline? (S.Zharko)
-//template<typename DataT>
-//void FieldRegion<DataT>::Set(const FieldValue<DataT>& b0, const DataT b0z, const FieldValue<DataT>& b1, const DataT b1z)
-//{
-//  fIsZeroField = (b0.IsZeroField() && b1.IsZeroField());
-//
-//  z0        = b0z;
-//  DataT dzi = kfutils::simd::One<DataT>() / (b1z - b0z);
-//  cx0       = b0.x;
-//  cy0       = b0.y;
-//  cz0       = b0.z;
-//  cx1       = (b1.x - b0.x) * dzi;
-//  cy1       = (b1.y - b0.y) * dzi;
-//  cz1       = (b1.z - b0.z) * dzi;
-//  cx2       = 0.f;
-//  cy2       = 0.f;
-//  cz2       = 0.f;
-//}
-
-//----------------------------------------------------------------------------------------------------------------------
-// TODO: Should it be inline? (S.Zharko)
-template<typename DataT>
-void FieldRegion<DataT>::Shift(DataT z)
-{
-  DataT dz    = z - z0;
-  DataT cx2dz = cx2 * dz;
-  DataT cy2dz = cy2 * dz;
-  DataT cz2dz = cz2 * dz;
-  z0          = z;
-  cx0 += (cx1 + cx2dz) * dz;
-  cy0 += (cy1 + cy2dz) * dz;
-  cz0 += (cz1 + cz2dz) * dz;
-  cx1 += cx2dz + cx2dz;
-  cy1 += cy2dz + cy2dz;
-  cz1 += cz2dz + cz2dz;
-}
-
-//----------------------------------------------------------------------------------------------------------------------
-//
-template<typename DataT>
-std::string FieldRegion<DataT>::ToString(int indentLevel) const
-{
-  std::stringstream aStream{};
-  // TODO: possibly it is better to place the indentChar into L1Parameters (S.Zharko)
-  constexpr char indentChar = '\t';
-  std::string indent(indentLevel, indentChar);
-  aStream << indent << "Bx(z) [kG] components: " << '\n';
-  aStream << indent << indentChar << "cx0: " << cx0 << '\n';
-  aStream << indent << indentChar << "cx1: " << cx1 << '\n';
-  aStream << indent << indentChar << "cx2: " << cx2 << '\n';
-  aStream << indent << "By(z) [kG] components: " << '\n';
-  aStream << indent << indentChar << "cy0: " << cy0 << '\n';
-  aStream << indent << indentChar << "cy1: " << cy1 << '\n';
-  aStream << indent << indentChar << "cy2: " << cy2 << '\n';
-  aStream << indent << "Bz(z) [kG] components: " << '\n';
-  aStream << indent << indentChar << "cz0: " << cz0 << '\n';
-  aStream << indent << indentChar << "cz1: " << cz1 << '\n';
-  aStream << indent << indentChar << "cz2: " << cz2 << '\n';
-  aStream << indent << "z0 [cm]: " << z0;
-  return aStream.str();
-}
-
-namespace cbm::algo::ca
-{
-  template class FieldRegion<fvec>;
-  template class FieldRegion<float>;
-  template class FieldRegion<double>;
-}  // namespace cbm::algo::ca
diff --git a/algo/ca/core/pars/CaField.h b/algo/ca/core/pars/CaField.h
index 07d3cee5c1bb41e808203b2af7ee4cc9fa7e91b9..18c73b1ad6946e40cab4ccfcac3b8331be8d661f 100644
--- a/algo/ca/core/pars/CaField.h
+++ b/algo/ca/core/pars/CaField.h
@@ -7,221 +7,13 @@
 
 #include "CaDefs.h"
 #include "CaSimd.h"
+#include "KfFieldRegion.h"
 #include "KfFieldValue.h"
 #include "KfTrackParam.h"
 
-#include <boost/serialization/access.hpp>
-
-#include <functional>
-#include <string>
-
 namespace cbm::algo::ca
 {
+  using cbm::algo::kf::FieldRegion;
   using cbm::algo::kf::FieldSlice;
   using cbm::algo::kf::FieldValue;
-
-  //template<typename T>
-  //using FieldRegion = cbm::algo::kf::FieldRegion<T, cbm::algo::kf::EFieldMode::Intrpl>;
-
-  template<typename DataT>
-  class FieldRegion {
-   public:
-    // NOTE: When a custom constructor is defined, default constructor also should be provided (S.Zharko)
-    FieldRegion() = default;
-
-    FieldRegion(float reg[10]) noexcept;
-
-    /// \brief Copy constructor with type conversion
-    template<typename DataIn>
-    FieldRegion(const FieldRegion<DataIn>& other)
-      : cx0(kfutils::simd::Cast<DataIn, DataT>(other.cx0))
-      , cx1(kfutils::simd::Cast<DataIn, DataT>(other.cx1))
-      , cx2(kfutils::simd::Cast<DataIn, DataT>(other.cx2))
-      , cy0(kfutils::simd::Cast<DataIn, DataT>(other.cy0))
-      , cy1(kfutils::simd::Cast<DataIn, DataT>(other.cy1))
-      , cy2(kfutils::simd::Cast<DataIn, DataT>(other.cy2))
-      , cz0(kfutils::simd::Cast<DataIn, DataT>(other.cz0))
-      , cz1(kfutils::simd::Cast<DataIn, DataT>(other.cz1))
-      , cz2(kfutils::simd::Cast<DataIn, DataT>(other.cz2))
-      , z0(kfutils::simd::Cast<DataIn, DataT>(other.z0))
-      , fUseOriginalField(other.fUseOriginalField)
-    {
-    }
-
-    /// Consistency checker
-    void CheckConsistency() const;
-
-    /// Gets the field vector and writes it into B pointer
-    /// \param x  x-coordinate of the point to calculate the field
-    /// \param y  y-coordinate of the point to calculate the field
-    /// \param z  z-coordinate of the point to calculate the field
-    /// \return    the magnetic field value
-    FieldValue<DataT> Get(const DataT& x, const DataT& y, const DataT& z) const;
-
-    std::tuple<DataT, DataT, DataT> GetDoubleIntegrals(const DataT& x1, const DataT& y1, const DataT& z1,  //
-                                                       const DataT& x2, const DataT& y2, const DataT& z2) const;
-
-    /// Is the field region empty?
-    bool IsZeroField() const
-    {
-      if (fgForceUseOfOriginalField || fUseOriginalField) {
-        return fgIsZeroOriginalField;
-      }
-      return fIsZeroField;
-    }
-
-    /// Interpolates the magnetic field by three nodal points and sets the result to this FieldRegion object
-    /// The result is a quadratic interpolation of the field as a function of z
-    /// \param b0   field value in the first nodal point
-    /// \param b0z  z-coordinate of the first nodal point
-    /// \param b1   field value in the second nodal point
-    /// \param b1z  z-coordinate of the second nodal point
-    /// \param b2   field value in the third nodal point
-    /// \param b2z  z-coordinate of the third nodal point
-    /// TODO: does the sequence of b0z, b1z and b2z matter? If yes, probalby we need an assertion (S.Zharko)
-    void Set(const FieldValue<DataT>& b0, const DataT b0z, const FieldValue<DataT>& b1, const DataT b1z,
-             const FieldValue<DataT>& b2, const DataT b2z);
-
-    /// Interpolates the magnetic field by thwo nodal points and sets the result to this FieldRegion object.
-    /// The result is a linear interpolation of the field as a function of z
-    /// \param b0   field value in the first nodal point
-    /// \param b0z  z-coordinate of the first nodal point
-    /// \param b1   field value in the second nodal point
-    /// \param b1z  z-coordinate of the second nodal point
-    /// TODO: does the sequence of b0z and b1z matter? If yes, probalby we need an assertion (S.Zharko)
-    //void Set(const FieldValue<DataT>& b0, const DataT b0z, const FieldValue<DataT>& b1, const DataT b1z);
-
-    /// Shifts the coefficients to new central point
-    /// \param z  z-coordinate of the new central point
-    void Shift(DataT z);
-
-    /// Set one SIMD entry from one SIMD entry of the other class
-    /// It only works when DataT is fvec, TdataB is fvec
-    /// \param fb    the other FieldRegion object, which layer is going to be replaced
-    /// \param ib    the index of the source fvec layer to copy
-    template<typename TdataB>
-    void SetSimdEntry(const FieldRegion<TdataB>& fb, const int ib)
-    {
-      CopyBase<TdataB, true, false>(0, fb, ib);
-    }
-
-    /// Set one SIMD entry from one SIMD entry of the other class
-    /// It only works when DataT is fvec, TdataB is fvec
-    /// \param ia    the index of the fvec layer in this FieldRegion object
-    /// \param fb    the other FieldRegion object, which layer is going to be replaced
-    /// \param ib    the index of the source fvec layer to copy
-    //void SetSimdEntry(const int ia, const FieldRegion<fvec>& fb, const int ib)
-    //{
-    //  CopyBase<fvec, false, false>(ia, fb, ib);
-    //}
-
-    /// String representation of class contents
-    /// \param indentLevel      number of indent characters in the output
-    std::string ToString(int indentLevel = 0) const;
-
-    /// Use original field instead of the field approximation
-    void SetUseOriginalField(bool v = true) { fUseOriginalField = v; }
-
-    /// Force using the original field
-    static void ForceUseOfOriginalField(bool v = true) { fgForceUseOfOriginalField = v; }
-
-    /// Set the original field
-    static void SetOriginalField(std::function<std::tuple<double, double, double>(double x, double y, double z)> f,
-                                 bool isZeroField)
-    {
-      fgOriginalField       = f;
-      fgIsZeroOriginalField = isZeroField;
-    }
-
-    /// \brief Copies all/one entries from the other class
-    /// \tparam TdataB  Type of the other class
-    /// \tparam TDoAllA  If true, all entries of the current class must be set
-    /// \tparam TDoAllB  If true, all entries of the other class must be used
-    /// \param ia  Index of SIMD vector element of the current class
-    /// \param Tb  Other class
-    /// \param ib  Index of SIMD vector element of the other class
-    template<typename TdataB, bool TDoAllA, bool TDoAllB>
-    void CopyBase(const int ia, const FieldRegion<TdataB>& Tb, const int ib);
-
-   public:
-    static bool fgForceUseOfOriginalField;
-    static std::function<std::tuple<double, double, double>(double x, double y, double z)> fgOriginalField;
-    static bool fgIsZeroOriginalField;
-
-    // TODO: Probably it's better to have arrays instead of separate fvec values? (S.Zharko)
-    // Bx(z) = cx0 + cx1*(z-z0) + cx2*(z-z0)^2
-    DataT cx0{0.f};
-    DataT cx1{0.f};
-    DataT cx2{0.f};
-
-    // By(z) = cy0 + cy1*(z-z0) + cy2*(z-z0)^2
-    DataT cy0{0.f};
-    DataT cy1{0.f};
-    DataT cy2{0.f};
-
-    // Bz(z) = cz0 + cz1*(z-z0) + cz2*(z-z0)^2
-    DataT cz0{0.f};
-    DataT cz1{0.f};
-    DataT cz2{0.f};
-
-    DataT z0{0.f};  ///< z-coordinate of the field region central point
-
-    bool fUseOriginalField{false};  ///< Use original field instead of the field approximation
-
-    bool fIsZeroField{false};  ///< Is the field region empty?
-
-    /// Serialization function
-    friend class boost::serialization::access;
-    template<class Archive>
-    void serialize(Archive& ar, const unsigned int)
-    {
-      ar& cx0;
-      ar& cx1;
-      ar& cx2;
-      ar& cy0;
-      ar& cy1;
-      ar& cy2;
-      ar& cz0;
-      ar& cz1;
-      ar& cz2;
-      ar& z0;
-      ar& fUseOriginalField;
-      ar& fIsZeroField;
-    }
-  } _fvecalignment;
-
-  // ---------------------------------------------------------------------------------------------------------------------
-  //
-  template<typename TdataA>
-  template<typename TdataB, bool TDoAllA, bool TDoAllB>
-  inline void FieldRegion<TdataA>::CopyBase(const int ia, const FieldRegion<TdataB>& Tb, const int ib)
-  {
-    auto copy = [&](TdataA& a, const TdataB& b) {
-      kfutils::VecCopy<TdataA, TdataB, TDoAllA, TDoAllB>::CopyEntries(a, ia, b, ib);
-    };
-
-    copy(cx0, Tb.cx0);
-    copy(cx1, Tb.cx1);
-    copy(cx2, Tb.cx2);
-
-    copy(cy0, Tb.cy0);
-    copy(cy1, Tb.cy1);
-    copy(cy2, Tb.cy2);
-
-    copy(cz0, Tb.cz0);
-    copy(cz1, Tb.cz1);
-    copy(cz2, Tb.cz2);
-
-    copy(z0, Tb.z0);
-
-    fUseOriginalField = Tb.fUseOriginalField;
-    fIsZeroField      = Tb.fIsZeroField;
-
-  }  // CopyBase
-
-  /// \brief Explicit instantiation declarations for FieldRegion class with specific template types to ensure proper fgOriginalField definition
-  extern template class FieldRegion<fvec>;
-  extern template class FieldRegion<float>;
-  extern template class FieldRegion<double>;
-
 }  // namespace cbm::algo::ca
diff --git a/algo/ca/core/tracking/CaFramework.cxx b/algo/ca/core/tracking/CaFramework.cxx
index eae683f55b19c6a8ee7a38788714dfc0ba198f37..422f282f51704d1985bf7002af116d82322dc115 100644
--- a/algo/ca/core/tracking/CaFramework.cxx
+++ b/algo/ca/core/tracking/CaFramework.cxx
@@ -61,7 +61,6 @@ void Framework::ReceiveParameters(Parameters<fvec>&& parameters)
   fParameters          = std::move(parameters);
   fNstationsBeforePipe = fParameters.GetNstationsActive(static_cast<EDetectorID>(0));
 
-  ca::FieldRegion<fvec>::ForceUseOfOriginalField(fParameters.DevIsUseOfOriginalField());
   kf::GlobalField::ForceUseOfOriginalField(fParameters.DevIsUseOfOriginalField());
 }
 
diff --git a/algo/ca/core/tracking/CaTrackFit.cxx b/algo/ca/core/tracking/CaTrackFit.cxx
index d31d4aa2c1ea1f5f5280d6bcd0fc0af3c527d39d..1ab9c9809312e14e4ffc5cccf7a10af5b5da2296 100644
--- a/algo/ca/core/tracking/CaTrackFit.cxx
+++ b/algo/ca/core/tracking/CaTrackFit.cxx
@@ -619,7 +619,7 @@ namespace cbm::algo::ca
   {
     // use Q/p linearisation at fQp0
 
-    if (F.IsZeroField()) {
+    if (F.GetFieldType() == kf::EFieldType::Null) {
       ExtrapolateLineNoField(z_out);
     }
     else {
diff --git a/algo/ca/core/tracking/CaTrackFitter.cxx b/algo/ca/core/tracking/CaTrackFitter.cxx
index a2f3214b9b1a92a3f15b238c5f4627491c693e47..7f49cc9927ad4554054729709e84328354e198aa 100644
--- a/algo/ca/core/tracking/CaTrackFitter.cxx
+++ b/algo/ca/core/tracking/CaTrackFitter.cxx
@@ -288,8 +288,7 @@ void TrackFitter::FitCaTracks(const ca::InputData& input, WindowData& wData)
         vtxInfo.SetDy2(1.e-8);
 
         if (ca::TrackingMode::kGlobal == fTrackingMode) {
-          ca::FieldRegion<fvec> fldFull _fvecalignment;
-          fldFull.SetUseOriginalField(true);
+          ca::FieldRegion<fvec> fldFull(kf::GlobalField::fgOriginalFieldType, kf::GlobalField::fgOriginalField);
           fitpv.SetMaxExtrapolationStep(1.);
           for (int vtxIter = 0; vtxIter < 2; vtxIter++) {
             fitpv.SetQp0(fitpv.Tr().Qp());
diff --git a/algo/kf/core/geo/KfField.h b/algo/kf/core/geo/KfField.h
index 1e07c1afb20a1ca60fb63d3533c13a205b4f11e7..e1227faa5abe9246ad616484052f4578bcf4e8d6 100644
--- a/algo/kf/core/geo/KfField.h
+++ b/algo/kf/core/geo/KfField.h
@@ -268,7 +268,7 @@ namespace cbm::algo::kf
     FieldRegion<T> GetFieldRegion(const FieldValue<T>& b0, const T& z0, const FieldValue<T>& b1, const T& z1,
                                   const FieldValue<T>& b2, const T& z2) const
     {
-      return (fFieldMode == EFieldMode::Intrpl ? FieldRegion<T>(fFieldType, b0, z0, b1, z1, b2, z2)
+      return (fFieldMode == EFieldMode::Intrpl ? FieldRegion<T>(b0, z0, b1, z1, b2, z2)
                                                : FieldRegion<T>(fFieldType, foFldOrig->GetFieldFunction()));
     }
 
diff --git a/algo/kf/core/geo/KfFieldRegion.cxx b/algo/kf/core/geo/KfFieldRegion.cxx
index f87839f61eea8e777a7fff03ef57dab0b5b98ba5..340e22a18d6b5378857c434fd3bf61473ef04bde 100644
--- a/algo/kf/core/geo/KfFieldRegion.cxx
+++ b/algo/kf/core/geo/KfFieldRegion.cxx
@@ -24,9 +24,12 @@ using cbm::algo::kf::FieldValue;
 using cbm::algo::kf::GlobalField;
 
 using cbm::algo::kf::detail::FieldRegionBase;
+using namespace cbm::algo;
 
+FieldFn_t GlobalField::fgOriginalField = &GlobalField::UndefField;
+
+kf::EFieldType GlobalField::fgOriginalFieldType{kf::EFieldType::Null};
 
-FieldFn_t GlobalField::gOriginalField = &GlobalField::UndefField;
 
 bool GlobalField::fgForceUseOfOriginalField = false;
 
@@ -63,7 +66,7 @@ template<typename T>
 FieldValue<T> FieldRegionBase<T, EFieldMode::Intrpl>::Get(const T& x, const T& y, const T& z) const
 {
   if (GlobalField::IsUsingOriginalFieldForced()) {
-    return GlobalField::GetFieldValue(GlobalField::gOriginalField, x, y, z);
+    return GlobalField::GetFieldValue(GlobalField::fgOriginalField, x, y, z);
   }
   auto dz = z - this->fZfirst;
   return FieldValue<T>{this->fCoeff[0][0] + dz * (this->fCoeff[0][1] + dz * this->fCoeff[0][2]),
@@ -71,6 +74,30 @@ FieldValue<T> FieldRegionBase<T, EFieldMode::Intrpl>::Get(const T& x, const T& y
                        this->fCoeff[2][0] + dz * (this->fCoeff[2][1] + dz * this->fCoeff[2][2])};
 }
 
+// ---------------------------------------------------------------------------------------------------------------------
+//
+template<typename T>
+std::tuple<T, T, T>
+FieldRegionBase<T, EFieldMode::Intrpl>::GetDoubleIntegrals(const T& /*x1*/, const T& /*y1*/, const T& z1,  //
+                                                           const T& /*x2*/, const T& /*y2*/, const T& z2) const
+{
+  // double integral of the field along z
+
+  if (GlobalField::IsUsingOriginalFieldForced()) {
+    // TODO: implement the double integral for the original field
+  }
+  auto fld = *this;
+  fld.Shift(z1);
+  T dz  = z2 - z1;
+  T dz2 = dz * dz;
+  T c0  = dz2 * T(1. / 2.);
+  T c1  = dz2 * dz * T(1. / 6.);
+  T c2  = dz2 * dz2 * T(1. / 12.);
+  return {c0 * fld.fCoeff[0][0] + c1 * fld.fCoeff[0][1] + c2 * fld.fCoeff[0][2],
+          c0 * fld.fCoeff[1][0] + c1 * fld.fCoeff[1][1] + c2 * fld.fCoeff[1][2],
+          c0 * fld.fCoeff[2][0] + c1 * fld.fCoeff[2][1] + c2 * fld.fCoeff[2][2]};
+}
+
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<typename T>
@@ -166,17 +193,6 @@ namespace cbm::algo::kf::detail
 }  // namespace cbm::algo::kf::detail
 
 
-// ---------------------------------------------------------------------------------------------------------------------
-//
-template<typename T>
-void FieldRegion<T>::Set(const FieldValue<T>& b0, const T& z0, const FieldValue<T>& b1, const T& z1,
-                         const FieldValue<T>& b2, const T& z2)
-{
-  if (fFieldMode == EFieldMode::Intrpl) {
-    foFldIntrpl->Set(b0, z0, b1, z1, b2, z2);
-  }
-}
-
 // ---------------------------------------------------------------------------------------------------------------------
 //
 template<typename T>
diff --git a/algo/kf/core/geo/KfFieldRegion.h b/algo/kf/core/geo/KfFieldRegion.h
index 0ca1f66f9ca1fa46e8c552725ffa1d2a911ec73b..299aa5fb853fbe5f941135daa1e9897098792248 100644
--- a/algo/kf/core/geo/KfFieldRegion.h
+++ b/algo/kf/core/geo/KfFieldRegion.h
@@ -33,14 +33,21 @@ namespace cbm::algo::kf
   class GlobalField {
    public:
     /// \brief Global variable to store the fielf funciton (x,y,z)->(Bx,By,Bz)
-    static FieldFn_t gOriginalField;
+    static FieldFn_t fgOriginalField;
+
+    /// \brief Global field type
+    static EFieldType fgOriginalFieldType;  ///< global field type
 
     /// \brief Undefined magnetic field function
     static std::tuple<double, double, double> UndefField(double, double, double);
 
     /// \brief Sets global field function
     /// \param fn  Field function of the FairRoot format
-    static void SetFieldFunction(const FieldFn_t& fn) { gOriginalField = fn; }
+    static void SetFieldFunction(EFieldType fldType, const FieldFn_t& fn)
+    {
+      fgOriginalFieldType = fldType;
+      fgOriginalField     = fn;
+    }
 
     /// \brief Creates a field value object in a spactial point of a generic floating-point type
     /// \tparam T       Floating point data-type of the involved variables
@@ -112,6 +119,14 @@ namespace cbm::algo::kf
         return GlobalField::GetFieldValue(fFieldFn, x, y, z);
       }
 
+      /// \brief Gets the double integrals of the field along the track
+      std::tuple<T, T, T> GetDoubleIntegrals(const T& /*x1*/, const T& /*y1*/, const T& /*z1*/,  //
+                                             const T& /*x2*/, const T& /*y2*/, const T& /*z2*/) const
+      {
+        assert("cbm::algo::kf::FieldRegionBase<T, EFieldMode::Orig>::GetDoubleIntegrals() is not implemented");
+        return {defs::Undef<T>, defs::Undef<T>, defs::Undef<T>};
+      }
+
       /// Consistency checker
       void CheckConsistency() const;
 
@@ -178,9 +193,16 @@ namespace cbm::algo::kf
       /// \param z  z-coordinate of the point [cm]
       FieldValue<T> Get(const T& x, const T& y, const T& z) const;
 
+      /// \brief Gets the double integrals of the field along the track
+      std::tuple<T, T, T> GetDoubleIntegrals(const T& x1, const T& y1, const T& z1,  //
+                                             const T& x2, const T& y2, const T& z2) const;
+
       /// \brief Gets the first z-coordinate of the interpolation
       const T& GetZfirst() const { return fZfirst; }
 
+      /// \brief Gets the coefficients of the polynomial approximation
+      const auto& GetCoefficients() const { return fCoeff; }
+
       /// \brief Interpolates the field by three nodal points with the second order polynomial
       /// \note  The interpolation is carried out vs. z-coordinates of the space points of the field values
       /// \param b0  Field value at z0 [kG]
@@ -192,6 +214,13 @@ namespace cbm::algo::kf
       void Set(const FieldValue<T>& b0, const T& z0, const FieldValue<T>& b1, const T& z1, const FieldValue<T>& b2,
                const T& z2);
 
+      /// \brief Set the coefficients of the polynomial approximation
+      void Set(const CoeffArray_t& coeff, const T& z0)
+      {
+        fCoeff  = coeff;
+        fZfirst = z0;
+      }
+
       /// \brief Shifts the coefficients to another first z-coordinate
       /// \param z  new z-coordinate [cm]
       void Shift(const T& z);
@@ -231,7 +260,7 @@ namespace cbm::algo::kf
 
    public:
     /// \brief  Constructor of the generic field
-    FieldRegion(EFieldMode fldMode, EFieldType fldType)
+    FieldRegion(EFieldMode fldMode = EFieldMode::Intrpl, EFieldType fldType = EFieldType::Normal)
       : foFldIntrpl(fldMode == EFieldMode::Intrpl ? std::make_optional<detail::FieldRegionBase<T, EFieldMode::Intrpl>>()
                                                   : std::nullopt)
       , foFldOrig(fldMode == EFieldMode::Orig ? std::make_optional<detail::FieldRegionBase<T, EFieldMode::Orig>>()
@@ -256,11 +285,22 @@ namespace cbm::algo::kf
     {
     }
 
+    /// \brief  Constructor for the interpolated field region
+    FieldRegion(const FieldValue<T>& b0, const T& z0, const FieldValue<T>& b1, const T& z1, const FieldValue<T>& b2,
+                const T& z2)
+      : foFldIntrpl(std::make_optional<detail::FieldRegionBase<T, EFieldMode::Intrpl>>())
+      , foFldOrig(std::nullopt)
+      , fFieldType(EFieldType::Normal)
+      , fFieldMode(EFieldMode::Intrpl)
+    {
+      // Set the field type automatically
+      Set(b0, z0, b1, z1, b2, z2);
+    }
+
     /// \brief  Constructor for the interpolated field region
     /// \param  fieldType  Type of the field
-    FieldRegion(EFieldType fieldType, const FieldValue<T>& b0, const T& z0, const FieldValue<T>& b1, const T& z1,
-                const FieldValue<T>& b2, const T& z2)
-      : foFldIntrpl(std::make_optional<detail::FieldRegionBase<T, EFieldMode::Intrpl>>(b0, z0, b1, z1, b2, z2))
+    FieldRegion(EFieldType fieldType, const detail::FieldRegionBase<T, EFieldMode::Intrpl>& fld)
+      : foFldIntrpl(std::make_optional(fld))
       , foFldOrig(std::nullopt)
       , fFieldType(fieldType)
       , fFieldMode(EFieldMode::Intrpl)
@@ -293,6 +333,14 @@ namespace cbm::algo::kf
       return fFieldMode == EFieldMode::Intrpl ? foFldIntrpl->Get(x, y, z) : foFldOrig->Get(x, y, z);
     }
 
+    /// \brief Gets the double integrals of the field along the track
+    std::tuple<T, T, T> GetDoubleIntegrals(const T& x1, const T& y1, const T& z1, const T& x2, const T& y2,
+                                           const T& z2) const
+    {
+      return fFieldMode == EFieldMode::Intrpl ? foFldIntrpl->GetDoubleIntegrals(x1, y1, z1, x2, y2, z2)
+                                              : foFldOrig->GetDoubleIntegrals(x1, y1, z1, x2, y2, z2);
+    }
+
     /// \brief Gets field mode
     EFieldMode GetFieldMode() const { return fFieldMode; }
 
@@ -308,7 +356,16 @@ namespace cbm::algo::kf
     /// \param b2  Field value at z2 [kG]
     /// \param z2  Third nodal point in z-axis direction [cm]
     void Set(const FieldValue<T>& b0, const T& z0, const FieldValue<T>& b1, const T& z1, const FieldValue<T>& b2,
-             const T& z2);
+             const T& z2)
+    {
+      fFieldMode = EFieldMode::Intrpl;
+      fFieldType = EFieldType::Normal;
+      // Set the field type automatically
+      if (b0.IsZero() && b1.IsZero() && b2.IsZero()) {
+        fFieldType = EFieldType::Null;
+      }
+      foFldIntrpl->Set(b0, z0, b1, z1, b2, z2);
+    }
 
     /// \brief Sets the field type
     void SetFieldType(EFieldType fldType) { fFieldType = fldType; }
@@ -325,12 +382,11 @@ namespace cbm::algo::kf
     /// \param verbose       Verbosity level
     std::string ToString(int indentLevel = 0, int verbose = 1) const;
 
+    const auto& GetIntrplField() const { return foFldIntrpl; }
+
    private:
     friend class boost::serialization::access;
 
-    /// \brief Default constructor
-    FieldRegion() = default;
-
     /// \brief Serialization load method
     template<class Archive>
     void load(Archive& ar, const unsigned int /*version*/)
diff --git a/reco/KF/CbmKfTrackFitter.cxx b/reco/KF/CbmKfTrackFitter.cxx
index 1a5afc8f9385d1bd443c71823065f456a4ea0724..7b3f9652b3d6755a01783dfd62f52609d516a73c 100644
--- a/reco/KF/CbmKfTrackFitter.cxx
+++ b/reco/KF/CbmKfTrackFitter.cxx
@@ -39,10 +39,7 @@ using namespace std;
 using ca::fmask;
 using ca::fvec;
 
-namespace
-{
-  using namespace cbm::algo;
-}
+using namespace cbm::algo;
 
 void CbmKfTrackFitter::Track::OrderNodesInZ()
 {
@@ -529,8 +526,7 @@ bool CbmKfTrackFitter::FitTrack(CbmKfTrackFitter::Track& t)
 
   fFit.SetParticleMass(fMass);
 
-  ca::FieldRegion<double> field;
-  field.SetUseOriginalField();
+  ca::FieldRegion<double> field(kf::GlobalField::fgOriginalFieldType, kf::GlobalField::fgOriginalField);
 
   {  // fit downstream
 
diff --git a/reco/KF/ParticleFitter/CbmL1PFFitter.cxx b/reco/KF/ParticleFitter/CbmL1PFFitter.cxx
index 0b4613a5cbcfae9fd844f8e990ce3f7ce88cd58a..b0464a6c9cc994ae9a31c700009dbc5fcac7f763 100644
--- a/reco/KF/ParticleFitter/CbmL1PFFitter.cxx
+++ b/reco/KF/ParticleFitter/CbmL1PFFitter.cxx
@@ -55,38 +55,40 @@ namespace NS_L1TrackFitter
 using namespace NS_L1TrackFitter;
 
 
-inline void CbmL1PFFitter::PFFieldRegion::setFromL1FieldRegion(const ca::FieldRegion<fvec>& fld, int i)
+inline void CbmL1PFFitter::PFFieldRegion::setFromL1FieldRegion(const ca::FieldRegion<fvec>& fld, int ind)
 {
-  fP[0] = fld.cx0[i];
-  fP[1] = fld.cx1[i];
-  fP[2] = fld.cx2[i];
-
-  fP[3] = fld.cy0[i];
-  fP[4] = fld.cy1[i];
-  fP[5] = fld.cy2[i];
-
-  fP[6] = fld.cz0[i];
-  fP[7] = fld.cz1[i];
-  fP[8] = fld.cz2[i];
-
-  fP[9] = fld.z0[i];
+  assert(fld.GetFieldMode() == kf::EFieldMode::Intrpl);
+  const auto& coeff = fld.GetIntrplField()->GetCoefficients();
+
+  int i = 0;
+  for (int j = 0; j < 3; j++) {
+    for (int k = 0; k < 3; k++) {
+      fP[i] = coeff[j][k][ind];
+      i++;
+    }
+  }
+  fP[9] = fld.GetIntrplField()->GetZfirst()[ind];
 }
 
-inline void CbmL1PFFitter::PFFieldRegion::getL1FieldRegion(ca::FieldRegion<fvec>& fld, int i)
+inline void CbmL1PFFitter::PFFieldRegion::getL1FieldRegion(ca::FieldRegion<fvec>& fld, int ind)
 {
-  fld.cx0[i] = fP[0];
-  fld.cx1[i] = fP[1];
-  fld.cx2[i] = fP[2];
+  assert(fld.GetFieldMode() == kf::EFieldMode::Intrpl);
 
-  fld.cy0[i] = fP[3];
-  fld.cy1[i] = fP[4];
-  fld.cy2[i] = fP[5];
+  auto coeff = fld.GetIntrplField()->GetCoefficients();
+  auto z     = fld.GetIntrplField()->GetZfirst();
 
-  fld.cz0[i] = fP[6];
-  fld.cz1[i] = fP[7];
-  fld.cz2[i] = fP[8];
+  int i = 0;
+  for (int j = 0; j < 3; j++) {
+    for (int k = 0; k < 3; k++) {
+      coeff[j][k][ind] = fP[i];
+      i++;
+    }
+  }
+  z[ind] = fP[9];
 
-  fld.z0[i] = fP[9];
+  kf::detail::FieldRegionBase<fvec, kf::EFieldMode::Intrpl> fldInterpolated;
+  fldInterpolated.Set(coeff, fP[9]);
+  fld = kf::FieldRegion<fvec>(kf::EFieldType::Normal, fldInterpolated);
 }
 
 inline CbmL1PFFitter::PFFieldRegion::PFFieldRegion(const ca::FieldRegion<fvec>& fld, int i)
@@ -170,7 +172,7 @@ void CbmL1PFFitter::Fit(std::vector<CbmStsTrack>& Tracks, const std::vector<CbmM
   Initialize();
 
   ca::FieldValue<fvec> b0, b1, b2 _fvecalignment;
-  ca::FieldRegion<fvec> fld _fvecalignment;
+  ca::FieldRegion<fvec> fld;
   // fld.SetUseOriginalField();
 
   static int nHits = CbmL1::Instance()->fpAlgo->GetParameters().GetNstationsActive();
diff --git a/reco/L1/CbmL1Performance.cxx b/reco/L1/CbmL1Performance.cxx
index 92ac7e05a2b809388037707af92b4a064cd3ec10..9cdf511f0b72ccf25f9f9bba71642e9b2691ba5a 100644
--- a/reco/L1/CbmL1Performance.cxx
+++ b/reco/L1/CbmL1Performance.cxx
@@ -59,6 +59,7 @@
 #include <vector>
 
 using namespace cbm::algo::ca;
+using namespace cbm::algo;
 
 using cbm::algo::kf::TrackParamV;
 using cbm::ca::tools::Debugger;
@@ -1310,8 +1311,7 @@ void CbmL1::TrackFitPerformance()
       if (!mc.IsPrimary()) {  // secondary
 
         {  // extrapolate to vertex
-          ca::FieldRegion<fvec> fld _fvecalignment;
-          fld.SetUseOriginalField();
+          ca::FieldRegion<fvec> fld(kf::GlobalField::fgOriginalFieldType, kf::GlobalField::fgOriginalField);
           fit.Extrapolate(mc.GetStartZ(), fld);
           // add material
           const int fSta = fvHitDebugInfo[it->Hits[0]].iStation;
@@ -1378,8 +1378,7 @@ void CbmL1::TrackFitPerformance()
       else {  // primary
 
         {  // extrapolate to vertex
-          ca::FieldRegion<fvec> fld _fvecalignment;
-          fld.SetUseOriginalField();
+          ca::FieldRegion<fvec> fld(kf::GlobalField::fgOriginalFieldType, kf::GlobalField::fgOriginalField);
 
           // add material
           const int fSta = fvHitDebugInfo[it->Hits[0]].iStation;
@@ -1527,8 +1526,7 @@ void CbmL1::FillFitHistos(TrackParamV& track, const cbm::ca::tools::MCPoint& mcP
   //fit.SetMaxExtrapolationStep(10.);
   fit.SetDoFitVelocity(true);
   fit.SetTrack(track);
-  ca::FieldRegion<fvec> fld _fvecalignment;
-  fld.SetUseOriginalField();
+  ca::FieldRegion<fvec> fld(kf::EFieldType::Normal, kf::GlobalField::fgOriginalField);
   fit.Extrapolate(mcP.GetZOut(), fld);
   track = fit.Tr();
 
diff --git a/reco/L1/catools/CaToolsField.h b/reco/L1/catools/CaToolsField.h
index b77604318cf976018dd38925896569fe4bb2e406..9757b5034558fecfcce0b0944b8bb2ee630e8e5f 100644
--- a/reco/L1/catools/CaToolsField.h
+++ b/reco/L1/catools/CaToolsField.h
@@ -37,20 +37,10 @@ namespace cbm::ca::tools
         return std::tuple(0., 0., 0.);
       }
     };
-    if (FairRunAna::Instance()->GetField()) {
-      // NOTE: SZh 28.08.2024:
-      //   A template class instantiates an independent static variable for each class specification, so each specification must
-      //   be addressed.
-      ca::FieldRegion<ca::fvec>::SetOriginalField(fld, false);
-      ca::FieldRegion<float>::SetOriginalField(fld, false);
-      ca::FieldRegion<double>::SetOriginalField(fld, false);
-    }
-    else {
-      ca::FieldRegion<ca::fvec>::SetOriginalField(fld, true);
-      ca::FieldRegion<float>::SetOriginalField(fld, true);
-      ca::FieldRegion<double>::SetOriginalField(fld, true);
-    }
-    cbm::algo::kf::GlobalField::SetFieldFunction(fld);
+
+    cbm::algo::kf::GlobalField::SetFieldFunction(                                                                  //
+      (FairRunAna::Instance()->GetField() ? cbm::algo::kf::EFieldType::Normal : cbm::algo::kf::EFieldType::Null),  //
+      fld);
   }
 
 }  // namespace cbm::ca::tools
diff --git a/reco/L1/qa/CbmCaTrackFitQa.cxx b/reco/L1/qa/CbmCaTrackFitQa.cxx
index 357bae8080ea908c543c9b2b2026455871cc09c2..0de6cb97e8d09ad488b3b0a643750e517b85500e 100644
--- a/reco/L1/qa/CbmCaTrackFitQa.cxx
+++ b/reco/L1/qa/CbmCaTrackFitQa.cxx
@@ -165,8 +165,8 @@ void TrackFitQa::Fill(const TrackParamV& trPar, const tools::MCPoint& mcPoint, b
   fitter.SetMask(fmask::One());
   fitter.SetDoFitVelocity(true);
   fitter.SetTrack(trPar);
-  cbm::algo::ca::FieldRegion<ca::fvec> fieldRegion;
-  fieldRegion.SetUseOriginalField();  // Precised magnetic field is used
+  cbm::algo::ca::FieldRegion<ca::fvec> fieldRegion(kf::GlobalField::fgOriginalFieldType,
+                                                   kf::GlobalField::fgOriginalField);
   fitter.Extrapolate(mcPoint.GetZ(), fieldRegion);
 
   const TrackParamV& trParExtr = fitter.Tr();  // Track parameters extrapolated to given MC point
diff --git a/reco/L1/qa/CbmCaTrackTypeQa.cxx b/reco/L1/qa/CbmCaTrackTypeQa.cxx
index 8d152adb885c4d5019e877dac9a0650d8a798c5e..bb07084d91763bced95b79da1f0ac32f97d4b4f9 100644
--- a/reco/L1/qa/CbmCaTrackTypeQa.cxx
+++ b/reco/L1/qa/CbmCaTrackTypeQa.cxx
@@ -19,6 +19,7 @@ using cbm::ca::TrackTypeQa;
 using cbm::ca::tools::MCPoint;
 using cbm::ca::tools::MCTrack;
 
+using namespace cbm::algo;
 
 // ---------------------------------------------------------------------------------------------------------------------
 //
@@ -240,7 +241,7 @@ void TrackTypeQa::Init()
   // Track fitter
   fTrackFit.SetDoFitVelocity(true);  // TODO: set flag to the configuration
   fTrackFit.SetMask(fmask::One());
-  fFieldRegion.SetUseOriginalField();
+  fFieldRegion = kf::FieldRegion<fvec>(kf::GlobalField::fgOriginalFieldType, kf::GlobalField::fgOriginalField);
 }
 
 // ---------------------------------------------------------------------------------------------------------------------