From 2bf4ef518314b7956c55edd1a2a9bff422006ccf Mon Sep 17 00:00:00 2001
From: KeonHKim <alphaover2pi@korea.ac.kr>
Date: Mon, 22 Jul 2024 22:49:57 +0900
Subject: [PATCH] Define an independent wofz function to avoid unnecessary
 complex number calculations

---
 mbtrack2/impedance/resistive_wall.py          | 36 +++++++++++++------
 .../particles_electromagnetic_fields.py       |  2 +-
 2 files changed, 26 insertions(+), 12 deletions(-)

diff --git a/mbtrack2/impedance/resistive_wall.py b/mbtrack2/impedance/resistive_wall.py
index 21a513d..7928c48 100644
--- a/mbtrack2/impedance/resistive_wall.py
+++ b/mbtrack2/impedance/resistive_wall.py
@@ -5,7 +5,7 @@ Define resistive wall elements based on the WakeField class.
 
 import numpy as np
 from scipy.constants import c, epsilon_0, mu_0
-from scipy.special import wofz
+from scipy.special import wofz as _scipy_wofz
 
 from mbtrack2.impedance.wakefield import Impedance, WakeField, WakeFunction
 
@@ -238,25 +238,39 @@ class CircularResistiveWall(WakeField):
             idx2 = np.logical_not(idx1)
             wt[idx2] = self.__TransWakeApprox(time[idx2])
         return wt
+    
+    def __wofz(self, z):
+        """
+        Compute the Faddeeva function w(z) = exp(-z**2) * erfc(-i*z).
+
+        Returns
+        -------
+        tuple
+            Real and imaginary parts of the Faddeeva function.
+        """
+        res = _scipy_wofz(z)
+        return res.real, res.imag
 
     def __LongWakeExact(self, t, factor):
+        w1re, _ = self.__wofz( 1j * np.sqrt(2 * t / self.t0) )
+        w2re, _ = self.__wofz( np.exp(1j * np.pi / 6) *
+                                np.sqrt(2 * t / self.t0) )
+
         wl = factor * ( 4 * np.exp(-1 * t / self.t0) *
              np.cos(np.sqrt(3) * t / self.t0)
-             + np.real( wofz( 1j *
-                        np.sqrt(2 * t / self.t0) ) )
-             - 2 * np.real( wofz( np.exp(1j * np.pi / 6) *
-                            np.sqrt(2 * t / self.t0) ) ) )
+             + w1re - 2 * w2re )
         return wl
 
     def __TransWakeExact(self, t, factor):
+        w1re, _ = self.__wofz( 1j * np.sqrt(2 * t / self.t0) )
+        w2re, w2im = self.__wofz( np.exp(1j * np.pi / 6) *
+                                    np.sqrt(2 * t / self.t0) )
+
         wt = factor * ( 2 * np.exp(-1 * t / self.t0) *
              ( np.sqrt(3) * np.sin(np.sqrt(3) * t / self.t0)
-               - np.cos(np.sqrt(3) * t / self.t0) )
-             + np.real( wofz( 1j *
-                        np.sqrt(2 * t / self.t0) ) )
-             + 2 * np.real( np.exp(-1j * np.pi / 3) *
-                            wofz( np.exp(1j * np.pi / 6) *
-                            np.sqrt(2 * t / self.t0) ) ) )
+             - np.cos(np.sqrt(3) * t / self.t0) )
+             + w1re + 2 * ( np.cos(-np.pi/3) * w2re
+             - np.sin(-np.pi/3) * w2im ) )
         return wt
 
     def __LongWakeApprox(self, t):
diff --git a/mbtrack2/tracking/particles_electromagnetic_fields.py b/mbtrack2/tracking/particles_electromagnetic_fields.py
index ac9577b..3780ebb 100644
--- a/mbtrack2/tracking/particles_electromagnetic_fields.py
+++ b/mbtrack2/tracking/particles_electromagnetic_fields.py
@@ -4,7 +4,7 @@ For example, it can be applied to space charge, beam-beam force, electron lenses
 This is largely adapted from a fork of PyHEADTAIL https://github.com/gubaidulinvadim/PyHEADTAIL.
 Only the fastest Fadeeva implementation of the error function is used here.
 See  Oeftiger, A., de Maria, R., Deniau, L., Li, K., McIntosh, E., Moneta, L., Hegglin, S., Aviral, A. (2016).
-Review of CPU and GPU Fadeeva Implementations. https://cds.cern.ch/record/2207430/files/wepoy044.pdf 
+Review of CPU and GPU Faddeeva Implementations. https://cds.cern.ch/record/2207430/files/wepoy044.pdf 
 """
 
 from functools import wraps
-- 
GitLab