def do_approximation(self): epsilonp = np.sqrt(np.power(10, self.Ap / 10) - 1) gp = np.power(10, -self.Ap / 20) k1 = np.sqrt((np.power(10, self.Ap / 10) - 1) / (np.power(10, self.Ao / 10) - 1)) k = 1 / self.wan a = mp.asin(1j / epsilonp) vo = mp.ellipf(1j / epsilonp, k1) / (1j * self.n) self.n = np.ceil( special.ellipk(np.sqrt(1 - np.power(k1, 2))) * special.ellipk(k) / (special.ellipk(k1) * special.ellipk(np.sqrt(1 - np.power(k, 2))))) for i in range(1, int(np.floor(self.n / 2)) + 1): cd = mp.ellipfun('cd', (2 * i - 1) / self.n, k) zero = (1j / (float(k * cd.real) + 1j * float(k * cd.imag))) self.num = self.num * np.poly1d([1 / zero, 1]) self.num = self.num * np.poly1d([1 / np.conj(zero), 1]) cd = mp.ellipfun('cd', (2 * i - 1) / self.n - 1j * vo, k) pole = 1j * (float(cd.real) + 1j * float(cd.imag)) if np.real(pole) <= 0: self.den = self.den * np.poly1d([-1 / pole, 1]) self.den = self.den * np.poly1d([-1 / np.conj(pole), 1]) if np.mod(self.n, 2) == 1: sn = 1j * mp.ellipfun('sn', 1j * vo, k) pole = 1j * (float(sn.real) + 1j * float(sn.imag)) if np.real(pole) <= 0: self.den = self.den * np.poly1d([-1 / pole, 1]) self.den = self.den * np.poly1d([-1 / np.conj(pole), 1]) self.zeroes = np.roots(self.num) self.poles = np.roots(self.den) self.aprox_gain = np.power(gp, 1 - (self.n - 2 * np.floor(self.n / 2))) self.num = self.num * self.aprox_gain self.norm_sys = signal.TransferFunction( self.num, self.den) #Filter system is obtained
def _R2deriv(self,R,z,phi=0.,t=0.): """ NAME: _Rderiv PURPOSE: evaluate the second radial derivative for this potential INPUT: R - Galactocentric cylindrical radius z - vertical height phi - azimuth t - time OUTPUT: the second radial derivative HISTORY: 2018-08-04 - Written - Bovy (UofT) """ Raz2= (R+self.a)**2+z**2 Raz= nu.sqrt(Raz2) m= 4.*R*self.a/Raz2 R2ma2mz2o4aR1m= (R**2-self.a2-z**2)/4./self.a/R/(1.-m) return (2*R**2+self.a2+3*R*self.a+z**2)/R/Raz2*self._Rforce(R,z)\ +2.*self.a/R/Raz*(m*(R**2+self.a2+z**2)/4./(1.-m)/self.a/R**2\ *special.ellipe(m)\ +(R2ma2mz2o4aR1m/(1.-m)*special.ellipe(m) +0.5*R2ma2mz2o4aR1m*(special.ellipe(m)-special.ellipk(m)) +0.5*(special.ellipe(m)/(1.-m)-special.ellipk(m))/m)\ *4*self.a*(self.a2+z**2-R**2)/Raz2**2)
def calc_PrimaryLoop(self): """Predicts magnitude and direction of primary field in loop center""" # CALCULATES INDUCING FIELD AT RX LOOP CENTER # Initiate Variables I = self.I a1 = self.a1 x = self.x z = self.z eps = 1e-7 mu0 = 4 * np.pi * 1e-7 # 1e9*mu0 s = np.abs(x) # Define Radial Distance k = 4 * a1 * s / (z**2 + (a1 + s)**2) Bpx = mu0 * np.sign(x) * (z * I / (2 * np.pi * s + eps)) * ( 1 / np.sqrt(z**2 + (a1 + s)**2)) * (-sp.ellipk(k) + ((a1**2 + z**2 + s**2) / (z**2 + (s - a1)**2)) * sp.ellipe(k)) Bpz = mu0 * (I / (2 * np.pi)) * (1 / np.sqrt(z**2 + (a1 + s)**2)) * ( sp.ellipk(k) + ((a1**2 - z**2 - s**2) / (z**2 + (s - a1)**2)) * sp.ellipe(k)) self.Bpx = Bpx self.Bpz = Bpz
def _R2deriv(self, R, z, phi=0., t=0.): """ NAME: _Rderiv PURPOSE: evaluate the second radial derivative for this potential INPUT: R - Galactocentric cylindrical radius z - vertical height phi - azimuth t - time OUTPUT: the second radial derivative HISTORY: 2018-08-04 - Written - Bovy (UofT) """ Raz2 = (R + self.a)**2 + z**2 Raz = numpy.sqrt(Raz2) m = 4. * R * self.a / Raz2 R2ma2mz2o4aR1m = (R**2 - self.a2 - z**2) / 4. / self.a / R / (1. - m) return (2*R**2+self.a2+3*R*self.a+z**2)/R/Raz2*self._Rforce(R,z)\ +2.*self.a/R/Raz*(m*(R**2+self.a2+z**2)/4./(1.-m)/self.a/R**2\ *special.ellipe(m)\ +(R2ma2mz2o4aR1m/(1.-m)*special.ellipe(m) +0.5*R2ma2mz2o4aR1m*(special.ellipe(m)-special.ellipk(m)) +0.5*(special.ellipe(m)/(1.-m)-special.ellipk(m))/m)\ *4*self.a*(self.a2+z**2-R**2)/Raz2**2)
def calc_PrimaryRegion(self, X, Z): """Predicts magnitude and direction of primary field in region""" # CALCULATES INDUCING FIELD WITHIN REGION AND RETURNS AT LOCATIONS # Initiate Variables from object I = self.I a1 = self.a1 eps = 1e-6 mu0 = 4 * np.pi * 1e-7 # 1e9*mu0 s = np.abs(X) # Define Radial Distance k = 4 * a1 * s / (Z**2 + (a1 + s)**2) Bpx = mu0 * np.sign(X) * (Z * I / (2 * np.pi * s + eps)) * ( 1 / np.sqrt(Z**2 + (a1 + s)**2)) * (-sp.ellipk(k) + ((a1**2 + Z**2 + s**2) / (Z**2 + (s - a1)**2)) * sp.ellipe(k)) Bpz = mu0 * (I / (2 * np.pi)) * (1 / np.sqrt(Z**2 + (a1 + s)**2)) * ( sp.ellipk(k) + ((a1**2 - Z**2 - s**2) / (Z**2 + (s - a1)**2)) * sp.ellipe(k)) Bpx[(X > -1.025 * a1) & (X < -0.975 * a1) & (Z > -0.025 * a1) & (Z < 0.025 * a1)] = 0. Bpx[(X < 1.025 * a1) & (X > 0.975 * a1) & (Z > -0.025 * a1) & (Z < 0.025 * a1)] = 0. Bpz[(X > -1.025 * a1) & (X < -0.975 * a1) & (Z > -0.025 * a1) & (Z < 0.025 * a1)] = 0. Bpz[(X < 1.025 * a1) & (X > 0.975 * a1) & (Z > -0.025 * a1) & (Z < 0.025 * a1)] = 0. Babs = np.sqrt(Bpx**2 + Bpz**2) return Bpx, Bpz, Babs
def Int3(q, r, R): ''' Integral I3. ''' m = 4 * R * r / (q**2 + (r + R)**2) K0 = ellipk(m) # Complete elliptic integral of the first kind K1 = ellipk(1 - m) E0 = ellipe(m) # Complete elliptic integral of the second kind E1 = ellipe(1 - m) beta = np.arcsin(q / np.sqrt(q**2 + (R - r)**2)) K2 = ellipkinc(beta, 1 - m) # Incomplete elliptic integral of the first kind E2 = ellipeinc(beta, 1 - m) # Incomplete elliptic integral of the second kind Z = E2 - E1 * K2 / K1 # Jacobi zeta function lamb = K2 / K1 + 2 * K0 * Z / np.pi # Heuman’s lambda function I3 = -q * np.sqrt(m) * K0 / (2 * np.pi * R * np.sqrt(r * R)) + ( np.heaviside(r - R, 0.5) - np.heaviside(R - r, 0.5)) * lamb / ( 2 * R) + np.heaviside(R - r, 0.5) / R return I3
def elliptic_int_constants(s, w, h): """Calculates the complete elliptic integral of the first kind for CPW lumped element equivalent circuit calculations. Args: s (float): The width of the CPW trace (center) line, in meters (eg. 10*10**-6). w (float): The width of the CPW gap (dielectric space), in meters (eg. 6*10**-6). h (float): Thickness of the dielectric substrate, in meters (eg. 760*10**-6). Returns: tuple: Contents outlined below Tuple contents: * ellipk(k0) (float): The complete elliptic integral for k0 * ellipk(k01) (float): The complete elliptic integral for k01 * ellipk(k1) (float): The complete elliptic integral for k1 * ellipk(k11) (float): The complete elliptic integral for k11 """ #elliptical integral constants k0 = s / (s + 2 * w) k01 = np.sqrt(1 - k0**2) k1 = np.sinh((np.pi * s) / (4 * h)) / (np.sinh( (np.pi * (s + 2 * w)) / (4 * h))) k11 = np.sqrt(1 - k1**2) return ellipk(k0), ellipk(k01), ellipk(k1), ellipk(k11)
def period(self): '''Analytically calculate the period of EKM oscillations.''' # First calculate the limits. xcrit = brentq(lambda x: ellipk(x) - 2 * ellipe(x), 0, 1) phicrit = 3 * (1 - xcrit) / (3 + 2 * xcrit) if self.phiq < phicrit: CKLmin = brentq(lambda CKL: self.chi - self.epsoct - F(CKL), self.tol, self.phiq) else: # Check if flips occur for Omega = Pi or 0 if (np.sign(self.chi - self.epsoct - F(self.tol)) != np.sign(self.chi - self.epsoct - F(self.phiq))): CKLmin = brentq(lambda CKL: self.chi - self.epsoct - F(CKL), self.tol, self.phiq) else: CKLmin = brentq(lambda CKL: self.chi + self.epsoct - F(CKL), self.tol, self.phiq) if self.doesflip(): CKLmax = self.phiq else: CKLmax = brentq(lambda CKL: self.chi + self.epsoct - F(CKL), 0, 1) prefactor = 256 * np.sqrt(10) / (15 * np.pi) / self.epsoct P = quad(lambda CKL: (prefactor * ellipk((3 - 3*CKL)/(3 + 2*CKL)) / (4 - 11*CKL) / np.sqrt(6 + 4*CKL) / np.sqrt(1 - 1/self.epsoct**2 * (F(CKL) - self.chi)**2) / np.sqrt(2* np.fabs(self.phiq - CKL))), CKLmin, CKLmax, epsabs=1e-12, epsrel=1e-12, limit=100) return P[0]
def EllipticK(): """Return EllipticK.""" if (b == 0) or (ksq == 1): return 0 elif ksq < 1: return ellipk(ksq) else: return ellipk(1. / ksq)
def pulsation_canon(self, jgrid, vgrid): return np.select( [vgrid < 1, vgrid > 1], [.5 * np.pi / scsp.ellipk(vgrid), np.pi * np.sqrt(vgrid) / scsp.ellipk(1/vgrid) ], default=0 )
def __init__(self, L, a): """ Construct an elastic rod of length L in equilibrium L -- Arc length of the rod a -- Distance the rod endpoints are held from each other. """ self.L = L # Find the elliptic modulus describing the equilibrium shape of the rod constrained to span width 'a' self.m = newton(lambda m: 2 * ellipe(m) / ellipk(m) - 1 - a / L, 0.5) self.C = 1.0 / (2.0 * ellipk(self.m))
def WaveLengthDepth(k,a0,a1): """ Returns the wavelength and mean depth of a cnoidal wave with parameters k,a0,a1 """ kappa = np.sqrt(3*a1)/(2*np.sqrt(a0*(a0+a1)*(a0+(1-k*k)*a1))) h0 = a0+ a1*special.ellipe(k)/special.ellipk(k) lam = 2.*special.ellipk(k)/kappa return lam,h0
def calculate_impedance (pinw,gapw,eps_eff): #From Andreas' resonator paper or my thesis...agrees for values given in his paper k0 = float(pinw)/(pinw+2*gapw) k0p = sqrt(1-k0**2) L=(mu0/4)*ellipk(k0p**2)/ellipk(k0**2) C=4 *eps0*eps_eff*ellipk(k0**2)/ellipk(k0p**2) Z=sqrt(L/C) #print "pinw: %f, gapw: %f, k0: %f, k0p: %f, L: %f nH/m, C: %f pF/m, Z: %f" % (pinw,gapw,k0,k0p,L *1e9,C*1e12,Z) return Z
def cal_cp(Dw, alpha0, Dpw, ri, re, Ep, ve, tol=0.001): """ calculation of the spring constant cp, acc. to ISO 16218 Function 11. Args: tol: tolerance for convergence Dw: diameter of the ball alpha0: initial contact angle Dpw: pitch diameter of the bearing ri: cross-sectional raceway groove radius, inner re: cross-sectional raceway groove radius, outer Ep: modulus of elasticity ve: poisson's ratio Returns: cp: float """ gamma = Dw * cos(alpha0) / Dpw # 内外圈曲率和 rho_i = 2 / Dw * (2 + gamma / (1 - gamma) - Dw / 2 / ri) rho_e = 2 / Dw * (2 - gamma / (1 + gamma) - Dw / 2 / re) # 内外圈曲率差 Fip = (gamma / (1 - gamma) + Dw / 2 / ri) / (2 + gamma / (1 - gamma) - Dw / 2 / ri) Fep = (-gamma / (1 + gamma) + Dw / 2 / re) / (2 - gamma / (1 + gamma) - Dw / 2 / ri) for k in arange(0, 1, 0.001): # 内圈迭代求解 if k == 0: chi = float("inf") else: chi = 1 / k M = 1 - 1 / chi**2 # 第一类和第二类椭圆积分 Ki = ellipk(M) Ei = ellipe(M) Fp = 1 - 2 / (chi**2 - 1) * (Ki / Ei - 1) if abs((Fp - Fip) / Fp) < tol: chi_i = chi break else: pass for k in arange(0, 1, 0.001): # 外圈迭代求解 if k == 0: chi = float("inf") else: chi = 1 / k M = 1 - 1 / chi**2 # 第一类和第二类椭圆积分 Ke = ellipk(M) Ee = ellipe(M) Fp = 1 - 2 / (chi**2 - 1) * (Ke / Ee - 1) if abs((Fp - Fep) / Fp) < tol: chi_e = chi break else: pass return (1.48 * Ep / (1 - ve**2) * ((Ki * (rho_i / chi_i**2 / Ei)**(1 / 3) + Ke * (rho_e / chi_e**2 / Ee)**(1 / 3)))**(-1.5))
def coplanar(w, s, epsilon_eff): """ return capacitance and inductance (geometric) perunit length in SI unit """ k0 = w / (w + 2 * s) k0_ = sqrt(1 - k0**2) C = 4 * const.epsilon_0 * epsilon_eff * ellipk(k0) / ellipk(k0_) L = const.mu_0 / 4 * ellipk(k0_) / ellipk(k0) return C, L
def surface_displacement(x, y, transform=0): """ Into surface displacement at the surface for an elliptical contact Parameters ---------- x,y : array-like x and y coordinates of the points of interest transform : int {0,1,2}, optional (0) a flag which defines which axes the result is displayed on. If set to 0 the result is displayed on the 'contact axes' which are aligned with the principal radii of the contact ellipse. If set to 1 or 2 the result is aligned with the axes of the first or second body respectively. Returns ------- displacement : array The into surface displacement at each of the points of interest Notes ----- The pressure distribution is given by: p(x,y)=p0*(1-(x/a)**2-(y/b)**2)**0.5 References ---------- [1] Johnson, K. (1985). Contact Mechanics. Cambridge: Cambridge University Press. doi:10.1017/CBO9781139171731 """ nonlocal l_johnson, m_johnson, n_johnson if l_johnson is None: if b > a: raise ValueError("Change in a>b or b>a between sources, " "sort out") e = (1 - b**2 / a**2)**0.5 l_johnson = np.pi * p0 * b * special.ellipk(e) m_johnson = np.pi * p0 * b / e**2 / a**2 * (special.ellipk(e) - special.ellipe(e)) n_johnson = np.pi * p0 * b / a**2 / e**2 * ( (a**2 / b**2) * special.ellipe(e) - special.ellipk(e)) if transform: x, y = _transform_axes(x, y, [alpha, beta][transform - 1]) out_of_bounds = np.clip((1 - (x / a)**2 - (y / b)**2), 0, float('inf')) == 0 displacement = np.array( (1 - v**2) / modulus / np.pi * (l_johnson - m_johnson * x**2 - n_johnson * y**2)) displacement[out_of_bounds] = float('Nan') return displacement
def C_l(self): """ Capacitance per unit length, F/m Ref: Goople paper """ k0 = self.w / self.b k0_p = sqrt(1 - k0**2) C_l = 4 * epsilon_0 * self.epsilon_eff * ellipk(k0)/ellipk(k0_p) return C_l
def Lm_l(self): """ Magnetic inductance per unit length, H/m Ref: Goople paper, Yosida1995(Schuster thesis): They show the same expressions. """ k0 = self.w / self.b k0_p = np.sqrt(1 - k0**2) L_l = mu_0 / 4 * ellipk(k0_p**2) / ellipk(k0**2) return L_l
def elliptic_integral(self, h=None): # Calculate the complete elliptic integral of the first kind if not self.__h: k = self.__w / (self.__w + 2 * self.__s) kp = np.sqrt(1 - k**2) elif self.__h: k = (np.sinh((np.pi * self.__w) / (4 * self.__h)) / np.sinh( (np.pi * (self.__w + 2 * self.__s)) / (4 * self.__h))) kp = np.sqrt(1 - k**2) Kk = ellipk(k) Kkp = ellipk(kp) return (Kk, Kkp)
def Z0(self): """ Characteristic impedance of CPW. Ref: Gupta """ k = self.w / self.b k_p = np.sqrt(1 - k**2) Z0 = 30 * np.pi / np.sqrt(self.epsilon_eff) * ellipk(k_p**2) / ellipk( k**2) return Z0
def interdigitated_capacitance(epsilon_r, area, width, gap): """ Return the capacitance C of an interdigitated capacitor with the given surface area, tine width, and gap between tines; epsilon_r is the dielectric constant of the substrate. The formula is given in Jonas's MKID design memo. Note that all lengths and areas must use SI units (m and m^2) for the return value to be in farads. """ pitch = width + gap k = np.tan(pi * width / (4 * pitch))**2 K = ellipk(k**2) Kp = ellipk(1 - k**2) C = epsilon_0 * (1 + epsilon_r) * (area / pitch) * (K / Kp) return C
def findCap(height, eff): print("--------------") print("height is:", height) print("math.pi is ", math.pi) coeffInSideBracketsa = (math.pi * xa) / (2 * height) coeffInSideBracketsb = (math.pi * xb) / (2 * height) coeffInSideBracketsc = (math.pi * xc) / (2 * height) coeffa = math.sinh(coeffInSideBracketsa) coeffasquared = math.pow(coeffa, 2) print("coeffInSideBracketsb is: ", coeffInSideBracketsb) coeffb = math.sinh(coeffInSideBracketsb) print("coeffb is: ", coeffb) coeffbsquared = math.pow(coeffb, 2) coeffc = math.sinh(coeffInSideBracketsc) coeffcsquared = math.pow(coeffc, 2) kp1 = coeffc / coeffb kInsideSqurt = (coeffbsquared - coeffasquared) / (coeffcsquared - coeffasquared) kp2 = math.sqrt(kInsideSqurt) k = kp1 * kp2 ksquared = math.pow(k, 2) kder = math.sqrt(1 - ksquared) K = ellipk(k) Kder = ellipk(kder) Kcoeff = Kder / K C = 2 * relativePermittivityOfFreeSpace * eff * Kcoeff print("---------------") print("height is:", height) print("coeffa is:", coeffa) print("coeffasquared is:", coeffasquared) print("coeffb is:", coeffb) print("coeffbsquared is:", coeffbsquared) print("coeffc is:", coeffc) print("coeffcsquared is:", coeffcsquared) print("Calculating C") print("kp1 is:", kp1) print("kInsideSqurt is:", kInsideSqurt) print("kp2 is:", kp2) print("k is:", k) print("kder is:", kder) print("K is:", K) print("Kder is:", Kder) print("C is:", C) print("Kcoeff is:", Kcoeff) print("relativePermittivityOfFreeSpace is:", relativePermittivityOfFreeSpace) print("eff is:", eff) return C
def loop_current(a, I, rho, z): alphasq = a * a + rho * rho + z * z - 2 * a * rho betasq = a * a + rho * rho + z * z + 2 * a * rho beta = sqrt(betasq) ksq = 1. - alphasq / betasq C = mu0 * I / pi Brho = (C * z / (2 * alphasq * rho * beta)) * ( (a * a + rho * rho + z * z) * ellipe(ksq) - alphasq * ellipk(ksq)) Bz = (C / (2 * alphasq * beta)) * ( (a * a - rho * rho - z * z) * ellipe(ksq) + alphasq * ellipk(ksq)) return Brho, Bz
def find_collision_pts(e, q): """ Finds the collision points for a period q, given an eccentricity e """ collisions_dict = {} a = semi_axes[e][0] b = semi_axes[e][1] l = period_lambda_dict[q][e] k_l_sq = ((a**2) - (b**2)) / ((a**2) - (l**2)) for j in range(int(q)): d_l_q = (4 * (special.ellipk(k_l_sq))) / int(q) t_j = (special.ellipk(k_l_sq)) + j * d_l_q collisions_dict[str(j).zfill(2)] = special.ellipj(t_j, k_l_sq)[3] return (collisions_dict)
def Z0(self): """ Characteristic impedance of CPW. Ref: Simons book (Schuster thesis) """ k = self.w / self.b k3 = tanh(pi*self.w/4/self.h) / tanh(pi*self.b/4/self.h) k_p = sqrt(1 - k**2) k3_p = sqrt(1 - k3**2) Z0 = 60 * pi / sqrt(self.epsilon_eff) / (ellipk(k)/ellipk(k_p) + ellipk(k3)/ellipk(k3_p)) return Z0
def calculate_eps_eff_from_geometry(substrate_epsR,pinw,gapw,substrate_height): a=pinw b=pinw+2*gapw h=substrate_height k0 = float(a)/b k0p = sqrt(1-k0**2) #k3 = tanh(pi*a/(4*h))/ tanh(pi*b/(4*h)) k3 = sinh(pi*a/(4*h)) / sinh(pi*b/(4*h)) k3p= sqrt(1-k3**2) Ktwid= ellipk(k0p**2)*ellipk(k3**2)/(ellipk(k0**2)*ellipk(k3p**2)) #return (1+substrate_epsR*Ktwid)/(1+Ktwid) return 1 + (substrate_epsR - 1) * Ktwid / 2
def _deriv(self, t, y, epsoct, phiq): # Eqs. 11 of Katz (2011) jz, Omega = y CKL = phiq - jz**2 / 2. x = (3 - 3 * CKL) / (3 + 2 * CKL) fj = (15 * np.pi / (128 * np.sqrt(10)) / ellipk(x) * (4 - 11 * CKL) * np.sqrt(6 + 4 * CKL)) fOmega = ((6 * ellipe(x) - 3 * ellipk(x)) / (4 * ellipk(x))) jzdot = -epsoct * fj * np.sin(Omega) Omegadot = jz * fOmega return [jzdot, Omegadot]
def epsilon_eff(self): """ Effectvie permittivity. Unitless Ref: Simmons' book (Schuster thesis) """ k = self.w / self.b k3 = tanh(pi*self.w/4/self.h) / tanh(pi*self.b/4/self.h) k_p = sqrt(1 - k**2) k3_p = sqrt(1 - k3**2) K_tilda = ellipk(k_p) * ellipk(k3) / ellipk(k) / ellipk(k3_p) epsilon_eff = (1 + self.epsilon_r * K_tilda) / (1 + K_tilda) return epsilon_eff
def calc_PrimaryLoop(self): """Predicts magnitude and direction of primary field in loop center""" # CALCULATES INDUCING FIELD AT RX LOOP CENTER # Initiate Variables I = self.I a1 = self.a1 a2 = self.a2 x = self.x z = self.z azm = self.azm eps = 1e-7 mu0 = 4 * np.pi * 1e-7 # 1e9*mu0 s = np.abs(x) # Define Radial Distance k = 4 * a1 * s / (z ** 2 + (a1 + s) ** 2) Bpx = ( mu0 * np.sign(x) * (z * I / (2 * np.pi * s + eps)) * (1 / np.sqrt(z ** 2 + (a1 + s) ** 2)) * ( -sp.ellipk(k) + ((a1 ** 2 + z ** 2 + s ** 2) / (z ** 2 + (s - a1) ** 2)) * sp.ellipe(k) ) ) Bpz = ( mu0 * (I / (2 * np.pi)) * (1 / np.sqrt(z ** 2 + (a1 + s) ** 2)) * ( sp.ellipk(k) + ((a1 ** 2 - z ** 2 - s ** 2) / (z ** 2 + (s - a1) ** 2)) * sp.ellipe(k) ) ) Bpabs = np.sqrt(Bpx ** 2 + Bpz ** 2) Bpn = np.sin(np.deg2rad(azm)) * Bpx + np.cos(np.deg2rad(azm)) * Bpz Area = np.pi * a2 ** 2 self.Bpx = Bpx self.Bpz = Bpz self.Bpabs = Bpabs self.Bpn = Bpn self.Area = Area
def advance(self, jgrid, vgrid, distrib, times): yield distrib fft_distrib = np.fft.rfft(distrib.T, axis=1) n = np.fft.rfftfreq(jgrid.size, jgrid[1] - jgrid[0]) for dt in np.diff(times): w = np.select( [vgrid < 1, vgrid > 1], [.5 * np.pi / scsp.ellipk(vgrid), np.pi * np.sqrt(vgrid) / scsp.ellipk(1/vgrid) ], default=0 ) fft_distrib *= np.exp(1j * n * w.T * dt) yield np.fft.irfft(fft_distrib, axis=1).T
def test_comp_ellint_1(): if NumCpp.NO_USE_BOOST and not NumCpp.STL_SPECIAL_FUNCTIONS: return a = np.random.rand(1).item() assert (roundScaler(NumCpp.comp_ellint_1_Scaler(a), NUM_DECIMALS_ROUND) == roundScaler(sp.ellipk(a**2).item(), NUM_DECIMALS_ROUND)) shapeInput = np.random.randint(20, 100, [2, ]) shape = NumCpp.Shape(shapeInput[0].item(), shapeInput[1].item()) aArray = NumCpp.NdArray(shape) a = np.random.rand(shape.rows, shape.cols) aArray.setArray(a) assert np.array_equal(roundArray(NumCpp.comp_ellint_1_Array(aArray), NUM_DECIMALS_ROUND), roundArray(sp.ellipk(np.square(a)), NUM_DECIMALS_ROUND))
def kparameter(CPW_C, CPW_G, Die_thickness): # CPW k parameter k = CPW_C / (CPW_C+CPW_G*2) k_1 = np.sinh(pi*CPW_C/4/Die_thickness)/np.sinh(pi*(CPW_C+2*CPW_G)/4/Die_thickness) k_prime = np.sqrt(1-k*k) # CPW k_prime parameter k_1_prime = np.sqrt(1-k_1*k_1) # The definition of elliptic integral function is different. In scipy it is m number, but here is modulus k K_k = ellipk(k*k) K_k_prime = ellipk(k_prime*k_prime) # for calculating dielectric loss K_k_1 = ellipk(k_1*k_1) K_k_1_prime = ellipk(k_1_prime*k_1_prime) q = 0.5 * K_k_prime*K_k_1/K_k_1_prime/K_k # filling factor return k, k_prime, k_1, k_1_prime, K_k, K_k_prime, K_k_1, K_k_1_prime, q
def action_from_oscillation_amplitude(RFStation, dtmax, timestep = 0, Np_histogram = None): ''' Returns the relative action for given oscillation amplitude in time, assuming single-harmonic RF system and no intensity effects. Action is normalised to the value at the separatrix, given in units of 1. Optional: RF parameters at a given timestep (default = 0) are used. Optional: Number of points for histogram output ''' omega_rf = RFStation.omega_RF[0,timestep] xx = x2(omega_rf*dtmax) action = np.zeros(len(xx)) indices = np.where(xx != 1.)[0] indices0 = np.where(xx == 1.)[0] action[indices] = (ellipe(xx[indices]) - (1. - xx[indices])*ellipk(xx[indices])) if indices0: action[indices0] = np.float(ellipe(xx[indices0])) if Np_histogram != None: histogram, bins = np.histogram(action, Np_histogram, (0,1)) histogram = np.double(histogram)/np.sum(histogram[:]) bin_centres = 0.5*(bins[0:-1] + bins[1:]) return action, bin_centres, histogram else: return action
def tune_from_phase_amplitude(phimax): ''' Find the tune w.r.t. the central synchrotron frequency corresponding to a given amplitude of synchrotron oscillations in phase ''' return 0.5*np.pi/ellipk(x(phimax))
def ellippi(n, m): """ Complete elliptic integral of third kind (simplified version). .. FIXME: Incorrect, because of non-standard definitions of elliptic integral in the reference Reference --------- F. LAMARCHE and C. LEROY, Evaluation of the volume of a sphere with a cylinder by elliptic integrals, Computer Phys. Comm. 59 (1990) pg. 365 """ a2 = n k2 = m k2_a2 = k2 + a2 phi = np.arcsin(a2 / k2_a2) Kc = ellipk(k2) Ec = ellipe(k2) Ki = ellipkinc(phi, (1. - k2) ** 1) Ei = ellipeinc(phi, (1. - k2) ** 1) c1 = k2 / k2_a2 c2 = np.sqrt(a2 / (1 + a2) / k2_a2) return c1 * Kc + c2 * ((Kc - Ec) * Ki + Kc * Ei)
def do_kernel(r): N = len(r) K = np.zeros ((N, N)) for i in range (0, N): ri = r[i] if (i > 0): dri = r[i] - r[i - 1] else: dri = r[i + 1] - r[i] for j in range (i + 1, N): rj = r[j] drj = r[j] - r[j - 1] mij = 4.0 * ri * rj / (ri + rj)**2 kval = special.ellipk(mij) # elliptic integral K[i, j] = kval / (ri + rj) * 4.0 * drj K[j, i] = kval / (ri + rj) * 4.0 * dri if i != 0: # contributions of left and right neighbours K[i, i] = 2.0/ri * (math.log(8.0*ri/dri) + 1.0) * dri else: K[i, i] = 1.0 / ri * (math.log(8.0*ri/dri) + 1.0) * dri K[i, i] += math.log(8.0 ) + 1.0 # interval [0, r[0]] is # to be treated separately K[i, -1] *= 0.5 # 0.5 factor from standard integration rule #K[i, 0] *= 0.5 def f(r): m = 4 * ri * r / (r + ri)**2 return special.ellipk(m) / (r + ri) / r I, eps = integrate.quad(f, r[-1], np.inf, limit=100) K[i, -1] += I * 4 * r[-1] # Right endpoint correction return K
def ellippi(n, m): """ Complete elliptic integral of third kind (simplified version). .. FIXME: Incorrect, because of non-standard definitions of elliptic integral in the reference Reference --------- F. LAMARCHE and C. LEROY, Evaluation of the volume of a sphere with a cylinder by elliptic integrals, Computer Phys. Comm. 59 (1990) pg. 365 """ a2 = n k2 = m k2_a2 = k2 + a2 phi = np.arcsin(a2 / k2_a2) Kc = ellipk(k2) Ec = ellipe(k2) Ki = ellipkinc(phi, (1. - k2)**1) Ei = ellipeinc(phi, (1. - k2)**1) c1 = k2 / k2_a2 c2 = np.sqrt(a2 / (1 + a2) / k2_a2) return c1 * Kc + c2 * ((Kc - Ec) * Ki + Kc * Ei)
def action_from_oscillation_amplitude(RFStation, dtmax, timestep=0, Np_histogram=None): ''' Returns the relative action for given oscillation amplitude in time, assuming single-harmonic RF system and no intensity effects. Action is normalised to the value at the separatrix, given in units of 1. Optional: RF parameters at a given timestep (default = 0) are used. Optional: Number of points for histogram output ''' omega_rf = RFStation.omega_RF[0, timestep] xx = x2(omega_rf * dtmax) action = np.zeros(len(xx)) indices = np.where(xx != 1.)[0] indices0 = np.where(xx == 1.)[0] action[indices] = (ellipe(xx[indices]) - (1. - xx[indices]) * ellipk(xx[indices])) if indices0: action[indices0] = np.float(ellipe(xx[indices0])) if Np_histogram != None: histogram, bins = np.histogram(action, Np_histogram, (0, 1)) histogram = np.double(histogram) / np.sum(histogram[:]) bin_centres = 0.5 * (bins[0:-1] + bins[1:]) return action, bin_centres, histogram else: return action
def Bvector(self,r): ''' calculate B vector (T/amp) at a point r. convert r to coil frame. then get B then convert b back to lab frame. ''' x,y,z = self.posToCoil(r) R = self.R rho = norm([x,y]) d = np.sqrt( (R+rho)**2 + z**2 ) if d == 0: # No Coil return np.asarray([0,0,0]) d2 = ( (R-rho)**2 + z**2 ) if d2 == 0: # on coil return np.asarray([0,0,0]) k2 = (4*R*rho)/d**2 K = ellipk(k2) E = ellipe(k2) Bc = (1/d)*(K + E*(R**2 - rho**2 - z**2)/d2) if rho == 0: Br=Ba=Bb = 0 else: Br = (1/rho)*(z/d)*(-K + E*(R**2 + rho**2 + z**2)/d2) Ba = Br*x/rho Bb = Br*y/rho B = np.asarray([Ba,Bb,Bc])*self.unit return self.toLab(B)
def tune_from_phase_amplitude(phimax): ''' Find the tune w.r.t. the central synchrotron frequency corresponding to a given amplitude of synchrotron oscillations in phase ''' return 0.5 * np.pi / ellipk(x(phimax))
def alpha_conductor(self): ''' Losses due to conductor resistivity Returns -------- alpha_conductor : array-like lossyness due to conductor losses See Also ---------- surface_resistivity : calculates surface resistivity ''' if self.rho is None or self.t is None: raise(AttributeError('must provide values conductivity and conductor thickness to calculate this. see initializer help')) t, k1, ep_re = self.t, self.k1,self.ep_re r_s = surface_resistivity(f=self.frequency.f, rho=self.rho, \ mu_r=1) a = self.w/2. b = self.s+self.w/2. K = ellipk # complete elliptical integral of first kind K_p = lambda x: ellipk(sqrt(1-x**2)) # ellipk's compliment return ((r_s * sqrt(ep_re)/(480*pi*K(k1)*K_p(k1)*(1-k1**2) ))*\ (1./a * (pi+log((8*pi*a*(1-k1))/(t*(1+k1)))) +\ 1./b * (pi+log((8*pi*b*(1-k1))/(t*(1+k1))))))
def calc_G(lamda, mu, alpha, r): ''' Calculates the G transform for a disk of radius alpha at a distance r, on top of a substrate with Lame parameter lambda and shear modulus mu. lamda: Lame parameter of substrate mu: shear modulus of substrate alpha: disk radius, in metres r: array of distances from centre of disk at which to calculate solution. In metres. eg r = np.linspace(0,50*10**3,num=1000) to go to 50km distance. ''' sigma = lamda + 2 * mu nabla = lamda + mu defm = np.zeros_like(r) r_disk = r[r <= alpha] r_postdisk = r[r >= alpha] defm[r <= alpha] = g * (sigma / (np.pi**2 * mu * nabla * alpha) * special.ellipe( (r_disk / alpha)**2)) defm[r >= alpha] = g * (sigma * r_postdisk / (np.pi**2 * mu * nabla * alpha**2)) * ( special.ellipe((alpha / r_postdisk)**2) - (1 - (alpha / r_postdisk)**2) * special.ellipk( (alpha / r_postdisk)**2)) return defm
def champB(self,x,z): if abs(x) < 1e-8: x=0 if x>0: sx = 1 x = -x else: sx = -1 z = z-self.zs x2 = x*x z2 = z*z r2 = x2+z2 b1 = self.a2+ r2 b2 = 2*x*self.a b3 = b1+b2 b4 = b1-b2 b5 = -2*b2/b4 b6 = math.sqrt(b3/b4)*self.i rb3 = math.sqrt(b3) b7 = self.a*b3*rb3 b8 = self.a4-self.a2*(x2-2*z2)+z2*(x2+z2) b9 = (self.a2+z2)*b3 e = ellipe(b5) k = ellipk(b5) bz = b6*((self.a2-r2)*e+b3*k)/b7 if x==0: bx = 0.0 Atheta = 0.0 Adx = bz/2 else: bx = -sx*z/x*b6*(b1*e-b3*k)/b7 Atheta = -sx*b6/x*(-b4*e+(self.a2+r2)*k)/(self.a*rb3) Adx = b6/x2*(b8*e-b9*k)/b7 return [bx,bz,Atheta,Adx]
def energy(T, J): beta = 1./(R*T) K = beta*J L = beta*J K1q = ellipk(q(K, L)) u = -J*coth(2.*K)*(1. + 2./np.pi*(2.*(np.tanh(2.*K))**2 - 1.)*K1q) return u
def cnoidalwaves(x,t,dx,a0,a1,g,k): n = len(x) u = zeros(n) h = zeros(n) bed = zeros(n) m = k*k h0 = a0 + a1*(float(ellipe(m)) / ellipk(m)) c = sqrt((g*a0*(a0 + a1)*(a0 + (1 - k*k)*a1))) / float(h0) Kc = sqrt(float(3*a1) / (4*a0*(a0 + a1)*(a0 + (1-k*k)*a1))) for i in range(n): h[i] = a0 + a1*dnsq(Kc*(x[i] - c*t),m) u[i] = c *(1 - float(h0)/h[i]) h0i = a0 + a1*dnsq(Kc*(x[0] - dx - c*t),m) u0i = c *(1 - float(h0)/h0i) h1i = a0 + a1*dnsq(Kc*(x[-1] + dx - c*t),m) u1i = c *(1 - float(h0)/h1i) G = getGfromupy(h,u,bed,u0i,u1i,h0i,h1i,bed[0],bed[-1],dx) return h,u,G,bed
def evaluate_field_at_point(self, x, y, z): rad = np.sqrt(x**2 + y**2) # If on-axis if rad / self.radius < 1e-10: return 0.0, 0.0, self.__on_axis_field(z) # z relative to position of coil z_rel = z - self.z b_central = self.__central_field() rad_norm = rad / self.radius z_norm = z_rel / self.radius alpha = (1.0 + rad_norm)**2 + z_norm**2 root_alpha_pi = np.sqrt(alpha) * np.pi beta = 4 * rad_norm / alpha int_e = ellipe(beta) int_k = ellipk(beta) gamma = alpha - 4 * rad_norm b_r = b_central * (int_e * ((1.0 + rad_norm**2 + z_norm**2) / gamma) - int_k) / root_alpha_pi * (z_rel / rad) b_z = b_central * (int_e * ( (1.0 - rad_norm**2 - z_norm**2) / gamma) + int_k) / root_alpha_pi return b_r * x / rad, b_r * y / rad, b_z
def greens(R, Z, Rc, Zc): """ Greens function for the toroidal elliptic operator """ ksq = 4.*R*Rc / ( (R + Rc)**2 + (Z - Zc)**2 ) # k**2 k = sqrt(ksq) return sqrt(R*Rc) * ( (2. - ksq)*ellipk(k) - 2.*ellipe(k) ) / (2.*pi*k)
def G(x, t_cap, f, t): r = 1. + f*math.cos(t) rcap = 1 + x*math.cos(t_cap) zmzcap = f*math.sin(t) - x*math.sin(t_cap) k = 4*r*rcap/((r+rcap)**2 + zmzcap**2) term1 = np.sqrt((r+rcap)**2 + zmzcap**2) term1 = term1*rcap term2 = (1.e0 - (k)*0.5e0)*scsp.ellipk(k) term2 = term2 - scsp.ellipe(k) return term1*term2
def compute_rational_approximation(self): # Compute shifts and quadrature weights m, M = 10e-6, 10e6 k2 = m / M kp = special.ellipk(1.0 - k2) t = 1j * np.arange(0.5, self.n_shift) * kp / self.n_shift sn, cn, dn, ph = special.ellipj(t.imag, 1-k2) cn = 1./cn cn *= cn shifts = -m*sn*sn*cn weights = 2.*cn*dn*kp*np.sqrt(m) / (np.pi * self.n_shift) return (shifts, weights)
def coulombkernel(r): N = len(r) M = zeros((N,N)) for i in range (0,N): r_i = r[i] print "Coulomb kernel:", i, "/", N for j in range (0,N): r_j = r[j] if i == j: if (j < N - 1): Dr = 0.5 * (r[j + 1] - r_j) else: Dr = 0.5 * (r_j - r[j - 1]) Ldr = Dr * math.log(1.0 / Dr**2) Lconst = 2.0 * Dr * math.log(4.0) Lplus = 2.0 * Dr M[i,j] = 0.5 * (Ldr + Lplus + Lconst) else: if j == 0: a = r_j b = 0.5 * (r_j + r[j + 1]) elif j == (N - 1): a = 0.5 * (r_j + r[j - 1]) b = r_j else: a = 0.5 * (r_j + r[j - 1]) b = 0.5 * (r_j + r[j + 1]) d = b - a mu_top = (4 * r_i * b) / ((r_i + b)**2) mu_bot = (4 * r_i * a) / ((r_i + a)**2) ellip_top = special.ellipk(mu_top) ellip_bot = special.ellipk(mu_bot) alpha_top = b / (r_i + b) alpha_bot = a / (r_i + a) I_top = ellip_top * alpha_top I_bot = ellip_bot * alpha_bot # i have added the constant of 4 that was previously forgotten M[i,j] = 4.0 * 0.5 * (I_top + I_bot) * d return M
def BxForRot(self,xx,yy,zz): x = (xx-self.x0)*np.cos(self.theta) - (zz-self.z0)*np.sin(self.theta) y = yy-self.y0 z = (xx-self.x0)*np.sin(self.theta) + (zz-self.z0)*np.cos(self.theta) rho2 = x**2 + y**2 r2 = x**2 + y**2 + z**2 alpha2 = self.a**2 + r2 - 2*self.a*np.sqrt(rho2) beta2 = self.a**2 + r2 + 2*self.a*np.sqrt(rho2) k2 = 1 - alpha2/beta2 gamma = x**2 - y**2 C = mu0*self.I/np.pi return C*x*z/(2*alpha2*np.sqrt(beta2)*rho2 + epsilon)*\ ((self.a**2+r2)*sp.ellipe(k2)-alpha2*sp.ellipk(k2))*10**4
def analyticalSolutionSolitary(x,t,a0,a1): """ Returns the cnoidal solution with parameters k,a0,a1 at (x,t) (possibly arrays) """ k = 0 g = 9.81 kappa = np.sqrt(3*a1)/(2*np.sqrt(a0*(a0+a1))) h0 = a0+ a1*special.ellipe(k)/special.ellipk(k) c = np.sqrt(g*a0*(a0+a1)) h = a0+ a1*np.power(np.cosh(kappa*(x-c*t)),-2) u = c*(1-a0/h) return h,u
def analyticalSolution(x,t,k,a0,a1): """ Returns the cnoidal solution with parameters k,a0,a1 at (x,t) (possibly arrays) """ g = 9.81 kappa = np.sqrt(3*a1)/(2*np.sqrt(a0*(a0+a1)*(a0+(1-k*k)*a1))) h0 = a0+ a1*special.ellipe(k)/special.ellipk(k) c = np.sqrt(g*a0*(a0+a1)*(a0+(1.-k*k)*a1))/h0 sn,cn,dn,ph = special.ellipj(kappa*(x-c*t),k) h = a0+a1*dn**2 u = c*(1-h0/h) return h,u
def Bz(self,xx,yy,zz): """Return the z component of the magnetic field in the point of space (xx,yy,zz) """ x = xx-self.x0 y = yy-self.y0 z = zz-self.z0 rho2 = x**2 + y**2 r2 = x**2 + y**2 + z**2 alpha2 = self.a**2 + r2 - 2*self.a*np.sqrt(rho2) beta2 = self.a**2 + r2 + 2*self.a*np.sqrt(rho2) k2 = 1 - alpha2/beta2 gamma = x**2 - y**2 C = mu0*self.I/np.pi return C/(2*alpha2*np.sqrt(beta2))*\ ((self.a**2-r2)*sp.ellipe(k2)+alpha2*sp.ellipk(k2))*10**4
def B(self,P): a = self.a theta = self.theta x = P[0] - self.x0 y = P[1] - self.y0 r = x*np.cos(theta)+y*np.sin(theta) z = -x*np.sin(theta)+y*np.cos(theta) # On se ramène à des # coordonnées cylindriques par rapport à la spire. Pour la # suite des calculs, voir l'aticle de T.Pré # http://www.udppc.asso.fr/bupdoc/textes/fichierjoint/918/0918D119.zip k= 4.*abs(r)*a/((a+abs(r))**2+z**2) Kk=sp.ellipk(k) Ek=sp.ellipe(k) Br=self.I*(z/r)/np.sqrt((a+abs(r))**2+z**2)*(-Kk+(a**2+r**2+z**2)/((a-abs(r))**2+z**2)*Ek) Bz=(self.I/np.sqrt((a+abs(r))**2+z**2))*(Kk+((a**2-r**2-z**2)/((a-abs(r))**2+z**2))*Ek) return([Br*np.cos(theta)-Bz*np.sin(theta),Br*np.sin(theta)+Bz*np.cos(theta)])
def _vintersect_sphcyl_ellip(rs, rc, b): """ The cases for which evaluating the volume of intersection of a sphere with a cylinder makes use of elliptic integrals. """ rs3 = rs ** 3 bprc = b + rc bmrc = b - rc A = max(rs ** 2, bprc ** 2) B = min(rs ** 2, bprc ** 2) C = bmrc ** 2 AB = A - B AC = A - C BC = B - C k2 = BC / AC s = bprc * bmrc e1 = ellipk(k2) e2 = ellipe(k2) if bmrc == 0: if rs == bprc: vi = - 4. / 3 * AC ** 0.5 * (s + 2. / 3 * AC) elif rs < bprc: vi = 4. / 3 / A ** 0.5 * (e1 * AB * (3 * B - 2 * A) + e2 * A * (2 * A - 4 * B)) / 3 else: vi = 4. / 3 / A ** 0.5 * (e1 * AB * A - e2 * A * (4 * A - 2 * B)) / 3 else: a2 = 1 - B / C e3 = elliptic_pi(a2, k2) if rs == bprc: vi = (4. / 3 * rs3 * np.arctan(2 * (b * rc) ** 0.5 / bmrc) - 4. / 3 * AC ** 0.5 * (s + 2. / 3 * AC)) elif rs < bprc: vi = (4. / 3 / AC ** 0.5 * (e3 * B ** 2 * s / C + e1 * (s * (A - 2. * B) + AB * (3 * B - C - 2 * A) / 3) + e2 * AC * (-s + (2 * A + 2 * C - 4 * B) / 3))) else: vi = 4. / 3 / AC ** 0.5 * (e3 * A ** 2 * s / C - e1 * (A * s - AB * AC / 3.) - e2 * AC * (s + (4. * A - 2 * B - 2 * C) / 3)) return vi
def force_between_windings(self, r1, r2, z, N_m): m = 4*r1*r2/float((r1+r2)**2+z**2); # Argument of the Elliptic Integrals K = special.ellipk(m); # Complete. First kind. E = special.ellipe(m); # Complete. Second kind. # Current in the coil. I1 = self.c.I; # The magnet is treated as an equivalent coil. # I2 is the current in the equivalent coil. I2 = self.m.B_r * self.m.l_m / float( N_m * MU_0); return ( MU_0 * I1 * I2 * z * np.sqrt(m/float(4*r1*r2)) * (K - E*(m/2.0-1)/float(m-1)) );
def _elliptic_integral(self, m): ''' Handle the calculation of the elliptic integral thank scipy special functions. First we have to precise that with the scipy documention definition of ellipk or ellipkm1, the argument of these function are m = k**2. Next the current method will use ellipk when 0<=m<0.5 and 0.5<=ellipkm1<=1 ''' if m<0.: raise ValueError('The argument of the elliptic integral has to be strictly positive.') if m >1.: raise ValueError('The argument of the elliptic integral has to be smaller than one.') if m < 0.99: return ellipk(m) else: return ellipkm1(m)
def _ellipk(self, k): ''' Handle the calculation of the elliptic integral thanks to scipy special functions module. First we have to precise that with the scipy documention definition of ellipk or ellipkm1, the argument of these function are m = k**2. Next the current method will use ellipk or ellipkm1 following the value of m ''' m = k**2. if m < self._ellipk_limit: return ellipk(m) else: return ellipkm1(m)
def heat_capacity(bond_energy, lower_temperature, higher_temperature, step=0.001): """ Calculate the exact heat capacity. Boltzmann constant is set to 1. Formula from McCoy and Wu, 1973, The Two-Dimensional Ising Model. """ # Shorter variable name to ease formula writing. j = bond_energy exact_heat_capacity = [] for t in np.arange(lower_temperature, higher_temperature, step): b = 1 / t k = 2 * np.sinh(2 * b * j) / np.cosh(2 * b * j)**2 kprime = np.sqrt(1 - k**2) c = (b * j / np.tanh(2 * b * j))**2 * (2 / np.pi) * (2 * ellipk(k**2) - 2 * ellipe(k**2) - (1 - kprime) * (np.pi / 2 + kprime * ellipk(k**2))) exact_heat_capacity.append((t, c)) return exact_heat_capacity