From 29f1a91ff967350cab77f93e12ad91fc3c0f1ff9 Mon Sep 17 00:00:00 2001
From: lintao <lintao51@gmail.com>
Date: Thu, 27 May 2021 23:30:34 +0800
Subject: [PATCH] WIP: calculate the Br/Bz.

---
 .../src/FieldMapFileProvider.cpp              | 17 +++-
 .../src/FieldMapFileProvider.h                |  4 +-
 .../src/GenericBFieldMapBrBz.cpp              | 94 ++++++++++++++++++-
 .../MagneticFieldMap/src/IFieldMapProvider.h  |  5 +-
 4 files changed, 109 insertions(+), 11 deletions(-)

diff --git a/Detector/MagneticFieldMap/src/FieldMapFileProvider.cpp b/Detector/MagneticFieldMap/src/FieldMapFileProvider.cpp
index 2865f6bf..2eb352e4 100644
--- a/Detector/MagneticFieldMap/src/FieldMapFileProvider.cpp
+++ b/Detector/MagneticFieldMap/src/FieldMapFileProvider.cpp
@@ -16,7 +16,7 @@ FieldMapFileProvider::FieldMapFileProvider(const std::string& url_)
     init();
 }
 
-int FieldMapFileProvider::rBinIdx(double r) {
+int FieldMapFileProvider::rBinIdx(double r, double& rn) {
     // 
     // | --- | --- | --- |
     // ^        ^        ^
@@ -30,20 +30,30 @@ int FieldMapFileProvider::rBinIdx(double r) {
 
     int idx = -1;
 
+    // std::cout << "FieldMapFileProvider::rBinIdx: "
+    //           << " r: " << r
+    //           << " rBinMin: " << rBinMin
+    //           << " rBinMax: " << rBinMax
+    //           << std::endl;
+
     if ( rBinMin <= absr && absr < rBinMax) {
         idx = (absr - rBinMin) / drBin;
+        double r0 = rBinMin + idx*drBin;
+        rn = (absr - r0)/drBin;
     }
     
     return idx;
 }
 
-int FieldMapFileProvider::zBinIdx(double z) {
+int FieldMapFileProvider::zBinIdx(double z, double& zn) {
     double absz = std::fabs(z);
 
     int idx = -1;
 
     if ( zBinMin <= absz && absz < zBinMax) {
-        idx = (absz - zBinMin) / drBin;
+        idx = (absz - zBinMin) / dzBin;
+        double z0 = zBinMin + idx*dzBin;
+        zn = (absz - z0)/dzBin;
     }
     
     return idx;
@@ -55,6 +65,7 @@ void FieldMapFileProvider::access(int rbin, int zbin, double& Br, double& Bz) {
     if ((rbin < 0 || rbin >= nr) || (zbin < 0 || zbin >= nr)) {
         Br = 0;
         Bz = 0;
+        return;
     }
 
     // convert to the internal table (with left col and top row)
diff --git a/Detector/MagneticFieldMap/src/FieldMapFileProvider.h b/Detector/MagneticFieldMap/src/FieldMapFileProvider.h
index a6712c66..8a754a7a 100644
--- a/Detector/MagneticFieldMap/src/FieldMapFileProvider.h
+++ b/Detector/MagneticFieldMap/src/FieldMapFileProvider.h
@@ -12,8 +12,8 @@ public:
     FieldMapFileProvider(const std::string& url_);
 
     // Meta data about the map
-    virtual int rBinIdx(double r);
-    virtual int zBinIdx(double z);
+    virtual int rBinIdx(double r, double& rn);
+    virtual int zBinIdx(double z, double& zn);
 
     // The Br and Bz
     virtual void access(int rbin, int zbin, double& Br, double& Bz);
diff --git a/Detector/MagneticFieldMap/src/GenericBFieldMapBrBz.cpp b/Detector/MagneticFieldMap/src/GenericBFieldMapBrBz.cpp
index 568d70c8..9b3218b3 100644
--- a/Detector/MagneticFieldMap/src/GenericBFieldMapBrBz.cpp
+++ b/Detector/MagneticFieldMap/src/GenericBFieldMapBrBz.cpp
@@ -3,6 +3,10 @@
 
 #include "FieldMapFileProvider.h"
 
+#include <cmath>
+
+#include "DD4hep/DD4hepUnits.h"
+
 GenericBFieldMapBrBz::GenericBFieldMapBrBz()
     : m_provider(nullptr) {
     type = dd4hep::CartesianField::MAGNETIC;
@@ -10,11 +14,93 @@ GenericBFieldMapBrBz::GenericBFieldMapBrBz()
 }
 
 void GenericBFieldMapBrBz::fieldComponents(const double* pos, double* field) {
-    double curfield[3] = {0.0, 0.0, 0.0};
+    if (!m_provider) {
+        std::string error_msg = "[ERROR] GenericBFieldMapBrBz: No provider! ";
+        throw std::runtime_error(error_msg); 
+    }
+
+    // convert pos to r/z
+    double x = pos[0] / dd4hep::m; // convert to meter
+    double y = pos[1] / dd4hep::m;
+    double z = pos[2] / dd4hep::m;
+    double r = sqrt(x*x+y*y);
+    double phi = atan2(y, x);
+
+    // std::cout << " r: " << r
+    //           << " x: " << x
+    //           << " y: " << y
+    //           << " z: " << z
+    //           << " field Bx: " << field[0]
+    //           << " field By: " << field[1]
+    //           << " field Bz: " << field[2]
+    //           << std::endl;
+
+    // get the point r0/z0, r1/z1
+
+    // -- normalized r/z at the bin
+    double rn = 0.0;
+    double zn = 0.0;
+
+    int ir0 = 0;
+    int iz0 = 0;
+
+    ir0 = m_provider->rBinIdx(r, rn);
+    iz0 = m_provider->zBinIdx(z, zn);
+
+    // not in the valid return
+    if (ir0 < 0 || iz0 < 0) {
+        // std::cout << "SKIP due to "
+        //           << " r: " << r
+        //           << " x: " << x
+        //           << " y: " << y
+        //           << " z: " << z
+        //           << " ir0: " << ir0
+        //           << " iz0: " << iz0
+        //           << " rn: " << rn
+        //           << " zn: " << zn
+        //           << std::endl;
+        return;
+    }
+
+    // std::cout << " r: " << r
+    //           << " x: " << x
+    //           << " y: " << y
+    //           << " z: " << z
+    //           << " ir0: " << ir0
+    //           << " iz0: " << iz0
+    //           << " rn: " << rn
+    //           << " zn: " << zn
+    //           << std::endl;
+
+    int ir1 = ir0 + 1;
+    int iz1 = iz0 + 1;
+
+    // get the Br/Bz at four points
+    double Br_r0z0 = 0.0;    double Bz_r0z0 = 0.0;
+    double Br_r1z0 = 0.0;    double Bz_r1z0 = 0.0;
+    double Br_r0z1 = 0.0;    double Bz_r0z1 = 0.0;
+    double Br_r1z1 = 0.0;    double Bz_r1z1 = 0.0;
+
+    // calculate the field at r/z
+    m_provider->access(ir0, iz0, Br_r0z0, Bz_r0z0);
+    m_provider->access(ir1, iz0, Br_r1z0, Bz_r1z0);
+    m_provider->access(ir0, iz1, Br_r0z1, Bz_r0z1);
+    m_provider->access(ir1, iz1, Br_r1z1, Bz_r1z1);
+
+    double Br = (1.0 - rn) * (1.0 - zn) * Br_r0z0 
+              +        rn  * (1.0 - zn) * Br_r1z0
+              + (1.0 - rn) *        zn  * Br_r0z1
+              +        rn  *        zn  * Br_r1z1;
+
+    double Bz = (1.0 - rn) * (1.0 - zn) * Bz_r0z0 
+              +        rn  * (1.0 - zn) * Bz_r1z0
+              + (1.0 - rn) *        zn  * Bz_r0z1
+              +        rn  *        zn  * Bz_r1z1;
 
-    field[0] += curfield[0];
-    field[1] += curfield[1];
-    field[1] += curfield[2];
+    // update the global field
+    field[0] += Br*cos(phi);
+    field[1] += Br*sin(phi);
+    field[2] += Bz;
 
     return;
 }
diff --git a/Detector/MagneticFieldMap/src/IFieldMapProvider.h b/Detector/MagneticFieldMap/src/IFieldMapProvider.h
index 3d238422..b1e8d948 100644
--- a/Detector/MagneticFieldMap/src/IFieldMapProvider.h
+++ b/Detector/MagneticFieldMap/src/IFieldMapProvider.h
@@ -13,8 +13,9 @@
 class IFieldMapProvider {
 public:
     // Meta data about the map
-    virtual int rBinIdx(double r) = 0;
-    virtual int zBinIdx(double z) = 0;
+    // return rn/zn is the normalized value in the bin. the value is [0,1]
+    virtual int rBinIdx(double r, double& rn) = 0;
+    virtual int zBinIdx(double z, double& zn) = 0;
 
     // The Br and Bz
     virtual void access(int rbin, int zbin, double& Br, double& Bz) = 0;
-- 
GitLab