def test_roots_laguerre(): weightf = orth.laguerre(5).weight_func verify_gauss_quad(sc.roots_laguerre, orth.eval_laguerre, weightf, 0., np.inf, 5) verify_gauss_quad(sc.roots_laguerre, orth.eval_laguerre, weightf, 0., np.inf, 25, atol=1e-13) verify_gauss_quad(sc.roots_laguerre, orth.eval_laguerre, weightf, 0., np.inf, 100, atol=1e-12) x, w = sc.roots_laguerre(5, False) y, v, m = sc.roots_laguerre(5, True) assert_allclose(x, y, 1e-14, 1e-14) assert_allclose(w, v, 1e-14, 1e-14) muI, muI_err = integrate.quad(weightf, 0, np.inf) assert_allclose(m, muI, rtol=muI_err) assert_raises(ValueError, sc.roots_laguerre, 0) assert_raises(ValueError, sc.roots_laguerre, 3.3)
def mean_xsectv(mX, mphi, alphaX, vmean, sign, minn=10, maxn=15, precision=1e-2, minb=0.1, classical_th = 10, tol=1e-2, eval_L=2, max_L=260, method='RK45', tol_convergence=0.01, max_itr=100, xtol_root=1e-4, rtol_root=1e-4, atol_ode=1e-4, rtol_ode=1e-5): """ Return <\sigma v>, assuming Boltzmann distribution. Only t+u channel We use Gauss-Laguerre quadrature for integration. Note: the input velocity is vmean, <v> = 2\sqrt(2/pi)v0, not v0. minn: we sample at least minn points by quadrature. maxn: we do not sample more than maxn, if maxn <= minn, we do not check convergence. precision: we stop integration when it converges below this value Other parameters are for cross section """ v0 = np.sqrt(np.pi/8)*vmean params = (minb, classical_th, tol, eval_L, max_L, method, tol_convergence, max_itr, xtol_root, rtol_root, atol_ode, rtol_ode) # First minn sampling nodes, weights = roots_laguerre(minn) integ_arr = list(map(lambda i: np.sqrt(8/np.pi)*v0*weights[i]*nodes[i]*xsect(mX, mphi, alphaX, np.sqrt(2*nodes[i])*v0, sign, *params), range(minn))) integ = sum(integ_arr) if maxn > minn: # add sampling points until convergence integ_err = 1.0 for n in np.arange(minn+1, maxn+1,1): nodes, weights = roots_laguerre(n) integ_old = integ integ_arr = list(map(lambda i: np.sqrt(8/np.pi)*v0*weights[i]*nodes[i]*xsect(mX, mphi, alphaX, np.sqrt(2*nodes[i])*v0, sign, *params), range(n))) integ = sum(integ_arr) integ_err = np.abs(integ-integ_old)/integ_old if integ_err < precision: break return integ
def laguerre(function, order, *args, **kwargs): """ Evaluate integral of <function> object, of 1 variable and parameters: integral[0, +infinity] {dx exp(-x) function(x, **args)} Args: :function <function> f(x, *args, **kwargs) :order <int> order of the quadrature or <tuple> (order, alpha) where alpha is float for the associated Laguerre integration (dx x^alpha exp(-x) *f(x)) *args and **kwargs will be passed to the function (check argument introduction in case of several function management) """ if not order in GaussianQuadrature._roots_weights_Laguerre: if isinstance(order, tuple): x_i, w_i = roots_genlaguerre(order[0], alpha=order[1]) else: x_i, w_i = roots_laguerre(order, mu=False) GaussianQuadrature._roots_weights_Laguerre[order] = (x_i, w_i) else: x_i, w_i = GaussianQuadrature._roots_weights_Laguerre.get(order) # integral = 0.0 # for i in range(len(x_i)): # integral += w_i[i] * function(x_i[i], *args, **kwargs) integral = np.dot(w_i, function(x_i, *args, **kwargs)) #print("order", order, "=",integral) return integral
def gauss_laguerre(n): ''' Gauss-Laguerre quadrature: A rule of order 2*n-1 on the ray with respect to the weight function w(x) = exp(-x). ''' return special.roots_laguerre(n)
def gauss_laguerre_quadrature(f, conversion, N): x, w = roots_laguerre(N) #need to become e^(-x) x = x * conversion w = w * conversion return sum(f(x) * w)
def _cached_roots_laguerre(n): """ Cache roots_laguerre results to speed up calls of the fixed_quad function. """ if n in _cached_roots_laguerre_cache: return _cached_roots_laguerre_cache[n] _cached_roots_laguerre_cache[n] = roots_laguerre(n) return _cached_roots_laguerre_cache[n]
def exponential(n, scale=1): ''' Gauss-Laguerre quadrature: A rule of order 2*n-1 on the ray with respect to the PDF of an exponential distribution with arbitrary scale. ''' nodes, weights = special.roots_laguerre(n) nodes = scale * nodes return nodes, weights
def test_gausslaguerre(): """ compar own implementation aginst scipy.special """ N = 20 w, r = GaussLaguerre(N) r_e, w_e = roots_laguerre(N) res_w = np.abs(w - w_e) res_r = np.abs(r - r_e) assert np.max(res_w) == pytest.approx(0, abs=10**-5) assert np.max(res_r) == pytest.approx(0)
def splitPlus(dicSAM, clsEOS): iERR = 0 nUser = clsEOS.NU #-- Component Number of the User Plus Fraction nComp = clsEOS.NC #-- Component Number of Heaviest Pseudo nSamp = clsEOS.NS #-- Number of Samples nSplt = clsEOS.NP #-- Number of Pseudo-Components (=NC-NU+1) #print("splitPlus: nUser,nComp,nSamp,nSplt ",nUser,nComp,nSamp,nSplt) cPlus = clsEOS.gPP("CN", nUser - 1) #-- Name of the User Plus Fraction cPlus = procPlusFracName(nUser - 1, cPlus, clsEOS) #-- If already split, process-name #print("splitPlus: cPlus ",cPlus) #---------------------------------------------------------------------- # Gauss-Laguerre Zeros (xZ) and Weights (wT) depending on Num Pseudos # Now using Scipy Special Function to get Zeros & Weights #---------------------------------------------------------------------- xZ, wT = SS.roots_laguerre(nSplt) #-- Whitson Rule: Heaviest Pseudo = MIN(500,2.5*max-Plus-Frac) ------ maxMw = 0.0 for iS in range(nSamp): maxMw = max(maxMw, dicSAM[iS].mPlus) maxMw = min(2.5 * maxMw, 500.0) #-- eta = Min Mole Wt in Plus Frac, i.e. if C7+ => Mw(C6+1/2) ------- eta = clsEOS.gPP("MW", nUser - 2) + 6.0 #-- Penultimate Comp + 6.0 A.U. beta0 = (maxMw - eta) / xZ[nSplt - 1] #-- Eqn.(3.33) #-------------------------------------------------------------------- # alfa - User alpha-Coeff (defaulted to 1.0 if not sepcified) # mObs - User Plus Fraction Mole Weight # delt - Eqn.(3.34) # gama - The Gamma Function - now use Scipy Special Function #-------------------------------------------------------------------- alfa = NP.zeros(nSamp) mObs = NP.zeros(nSamp) delt = NP.zeros(nSamp) gama = NP.zeros(nSamp) for iSam in range(nSamp): clsSAM = dicSAM[iSam] if clsSAM.aPlus < 1.0E-06: clsSAM.aPlus = 1.0 alfa[iSam] = clsSAM.aPlus mObs[iSam] = clsSAM.mPlus delt[iSam] = exp(alfa[iSam] * beta0 / (mObs[iSam] - eta) - 1.0) gama[iSam] = SS.gamma(alfa[iSam]) #-------------------------------------------------------------------- # mSpl - Pseudo-Component Mole Weights, Eqn.(3.32) # fCon - "Constant" part (no delt-dependence) of Eqn.(3.30) #-------------------------------------------------------------------- mSpl = NP.zeros(nSplt) fCon = NP.zeros((nSamp, nSplt)) for iSpl in range(nSplt): mSpl[iSpl] = eta + beta0 * xZ[iSpl] for iSam in range(nSamp): expO = (alfa[iSam] - 1.0) / gama[iSam] fCon[iSam][iSpl] = pow(xZ[iSpl], expO) #print("mSpl ",mSpl) #print("fCon ",fCon) #-- Adjust the delta's to match the Measured Mole Weight by Sample -- delt, zSpl = matchAllDelta(alfa, delt, mObs, mSpl, wT, xZ, fCon) #-- Ensure the sample plus fraction compositions normalise ---------- sumZ = NP.zeros(nSamp) for iSam in range(nSamp): iOffs = nUser - 1 for iSp in range(nSplt): sumZ[iSam] = sumZ[iSam] + zSpl[iSam][iSp] sPls = dicSAM[iSam].sComp[nUser - 1] #print("sumZ,sPls ",sumZ[iSa],sPls) sPls = sPls / sumZ[iSam] for iSp in range(nSplt): dicSAM[iSam].sZI(iOffs, sPls * zSpl[iSam][iSp]) iOffs += 1 #print("iSa,iSp,sTst ",iSa,iSp,sTst) #== Now, check the specific gravities against Soreide correlation ===== nPlus = 0 fPlus = 0.0 zPlus = NP.zeros(nSplt) gPlus = NP.zeros(nSplt) for iSam in range(nSamp): sPlus = dicSAM[iSam].sPlus if sPlus > 0.0: for iSpl in range(nSplt): zPlus[iSpl] = zSpl[iSam][iSpl] fCThs = adjustFC(nSplt, zPlus, mSpl, sPlus) nPlus = nPlus + 1 fPlus = fPlus + fCThs if nPlus > 0: fCavg = fPlus / float(nPlus) for iSpl in range(nSplt): gPlus[iSpl] = soreideSpcG(mSpl[iSpl], fCavg) #print("gPlus ",gPlus) else: print( "No Plus Fraction Specific Gravities for Any of the Samples - Error" ) iERR = -1 return iERR #== Now can define the Pseudo-Component Properties ==================== iC = nUser - 1 for iSpl in range(nSplt): molWt = mSpl[iSpl] SpecG = gPlus[iSpl] heavyComp(molWt, SpecG, iC, clsEOS) cName = cPlus + "P" + str(iSpl + 1) clsEOS.sPP("CN", iC, cName) iC += 1 #======================================================================= # End of Routine #======================================================================= return iERR
def mean_xsectv_tu_intf(mX, mphi, alphaX, vmean, sign, width_sm, minn=10, maxn=15, precision=1e-2, minb=0.1, classical_th = 10, tol=1e-2, eval_L=2, max_L=260, method='RK45', tol_convergence=0.01, max_itr=100, xtol_root=1e-4, rtol_root=1e-4, atol_ode=1e-4, rtol_ode=1e-5, n_width=100, eval_N_peak=500, tol_peak=1e-3, h=1e-1, eval_N=5, tol_trp=1e-2, tol_quad=1e-2): """ Calculate t+u corss section and interference btw s- and t+u channel simultaneously For the t-channel resonance region, this function reduces the computation time. """ v0 = np.sqrt(np.pi/8)*vmean vRsq = mphi**2/mX**2 - 4 b = alphaX*mX/mphi # If s-ch resonance exists or in Born region if vRsq > 0 or b < minb: #t+u-channel params = (mX, mphi, alphaX, vmean, sign, minn, maxn, precision, minb, classical_th, tol, eval_L, max_L, method, tol_convergence, max_itr, xtol_root, rtol_root, atol_ode, rtol_ode) xsectv_t = mean_xsectv(*params) #interference btw. s- and t-(u-) channel params=(mX, mphi, alphaX, vmean, sign, width_sm, n_width, eval_N_peak, tol_peak, h, eval_N, tol_trp, minn, maxn, tol_quad, None, minb, tol, eval_L, max_L, method, tol_convergence, max_itr, xtol_root, rtol_root, atol_ode, rtol_ode) xsectv_intf = mean_xsectv_intf(*params) return xsectv_t + xsectv_intf # In t-ch resonance region else: other_params = (tol, eval_L, max_L, method, tol_convergence, max_itr, xtol_root, rtol_root, atol_ode, rtol_ode) integ_err = 1.0 integ = 1.0 for n in np.arange(minn, maxn+1, 1): integ_old = integ nodes, weights = roots_laguerre(n) integ_t_arr = np.array([]) integ_intf_arr = np.array([]) # For each nodes of Quadrature for i in range(n): v = np.sqrt(2*nodes[i]) * v0 a = v/(2*alphaX) if mX*v/mphi < classical_th: # t+u channel xsectk2_t = xsectk2_part_wave(a, b, sign, *other_params) xsect_t = xsectk2_t[0]*16*np.pi/v**2/mX**2 delta_arr_input = xsectk2_t[-1] #print delta_arr_input integ_t_arr = np.append(integ_t_arr, np.sqrt(8/np.pi)*v0*weights[i]*nodes[i]*xsect_t) # Interference term xsect_intf = xsect_intf_part_wave(mX, mphi, alphaX, v, sign, width_sm, delta_arr_input, *other_params)[0] integ_intf_arr = np.append(integ_intf_arr, np.sqrt(8/np.pi)*v0*weights[i]*nodes[i]*xsect_intf) else: xsect_t = xsect_clas(mX, mphi, alphaX, v, sign) integ_t_arr = np.append(integ_t_arr, np.sqrt(8/np.pi)*v0*weights[i]*nodes[i]*xsect_t) #interference btw. s- and t-(u-) channel xsect_intf = xsect_intf_part_wave(mX, mphi, alphaX, v, sign, width_sm, None, *other_params)[0] integ_intf_arr = np.append(integ_intf_arr, np.sqrt(8/np.pi)*v0*weights[i]*nodes[i]*xsect_intf) integ = np.sum(integ_t_arr + integ_intf_arr) if maxn > minn: # add sampling points until convergence integ_err = np.abs(integ-integ_old)/integ_old if integ_err < precision: break return integ
def mean_xsectv_intf(mX, mphi, alphaX, vmean, sign, width_sm, n_width=100, eval_N_peak=500, tol_peak=1e-3, h=1e-1, eval_N=5, tol_trp=1e-2, minn=10, maxn=15, tol_quad=1e-2, delta_arr_input=None, minb=0.1, tol=1e-2, eval_L=2, max_L=260, method='RK45', tol_convergence=0.01, max_itr=100, xtol_root=1e-4, rtol_root=1e-4, atol_ode=1e-4, rtol_ode=1e-5): """ Return <\sigma v>, assuming Boltzmann distribution. Note: the input velocity is vmean, <v> = 2\sqrt(2/pi)v0, not v0. n_width: if the resonance exists, we integrate around the peak with intercal h=(half width)/n_width eval_N_peak: for iteration > eval_N_peak, we evaluate convergence tol_peak: tolerance for the integration around the resonance h: the integration interval outside the resonance eval_N: for iteration > eval_N, we evaluate convergence tol_trp: tolerance of this region """ other_params = (delta_arr_input, minb, tol, eval_L, max_L, method, tol_convergence, max_itr, xtol_root, rtol_root, atol_ode, rtol_ode) v0 = np.sqrt(np.pi/8)*vmean vRsq = mphi**2/mX**2 - 4 if vRsq >= 0: # Integraion with mediator resonance vR = np.sqrt(vRsq) wR = alphaX*vR**3/8 + mphi*width_sm/mX**2 # width around peak # We first integrate the narrow region around the peak # we use x, v=sqrt(2)v0*x xR = vR/np.sqrt(2)/v0 width_xR = np.sqrt(2.)*wR/4.0/vR/v0 # half width around xR max_peak_width = (wR/2.0/v0**2)**2/2.0/xR / 5.0 # We integrate around the peak at most [xR-max_peak_width, xR+max_peak_width] h_peak = width_xR/n_width # intagration interval around the peak integ_arr = np.array([h_peak*4*np.sqrt(2/np.pi)*v0*xR**3*np.exp(-xR**2)*xsect_intf(mX, mphi, alphaX, np.sqrt(2)*v0*xR, sign, width_sm, *other_params)]) xs = np.arange(xR+h_peak, xR+max_peak_width, h_peak) for i, x in enumerate(xs): integ_arr = np.append(integ_arr, h_peak*4*np.sqrt(2/np.pi)*v0*x**3*np.exp(-x**2)*xsect_intf(mX, mphi, alphaX, np.sqrt(2)*v0*x, sign, width_sm, *other_params)) x = xR - (i+1)*h_peak integ_arr = np.append(integ_arr, h_peak*4*np.sqrt(2/np.pi)*v0*x**3*np.exp(-x**2)*xsect_intf(mX, mphi, alphaX, np.sqrt(2)*v0*x, sign, width_sm, *other_params)) if i>eval_N_peak: eval_err = np.sum(integ_arr[-eval_N:])/np.sum(integ_arr[:-eval_N]) if eval_err < tol_peak: break # Then we integrate outside the peak # We do not care the overlap on peak by taking the integration interval # larger than max_peak_width if h < max_peak_width: h = max_peak_width # Peak of x^3exp(-x^2) xGauss_peak = np.sqrt(3.0/2.0) # Points at which x^3exp(-x^2) beceoms 10^-3 smaller than the peak value xi = 0.074428 xf = 3.3849 # integration for x < xGauss_peak xs = np.arange(xGauss_peak, xi, -h) integ_arr_low = np.array([]) for i, x in enumerate(xs): integ_arr_low = np.append(integ_arr_low, h*4*np.sqrt(2/np.pi)*v0*x**3*np.exp(-x**2)*xsect_intf(mX, mphi, alphaX, np.sqrt(2)*v0*x, sign, width_sm, *other_params)) if i>eval_N: eval_err = np.sum(integ_arr_low[-eval_N:])/np.sum(integ_arr_low[:-eval_N]) if eval_err < tol_trp: break # integraion for x > xGauss_peak xs = np.arange(xGauss_peak+h, xf, h) integ_arr_high = np.array([]) for i, x in enumerate(xs): integ_arr_high = np.append(integ_arr_high, h*4*np.sqrt(2/np.pi)*v0*x**3*np.exp(-x**2)*xsect_intf(mX, mphi, alphaX, np.sqrt(2)*v0*x, sign, width_sm, *other_params)) if i>eval_N: eval_err = np.sum(integ_arr_high[-eval_N:])/np.sum(integ_arr_high[:-eval_N]) if eval_err < tol_trp: break return np.sum(integ_arr) + np.sum(integ_arr_low) + np.sum(integ_arr_high) else: # integraion without resonance # First minn sampling nodes, weights = roots_laguerre(minn) integ_arr = list(map(lambda i: np.sqrt(8/np.pi)*v0*weights[i]*nodes[i]*xsect_intf(mX, mphi, alphaX, np.sqrt(2*nodes[i])*v0, sign, width_sm, *other_params), range(minn))) integ = sum(integ_arr) if maxn > minn: # add sampling points until convergence integ_err = 1.0 for n in np.arange(minn+1, maxn+1,1): nodes, weights = roots_laguerre(n) integ_old = integ integ_arr = list(map(lambda i: np.sqrt(8/np.pi)*v0*weights[i]*nodes[i]*xsect_intf(mX, mphi, alphaX, np.sqrt(2*nodes[i])*v0, sign, width_sm, *other_params), range(minn))) integ = sum(integ_arr) integ_err = np.abs(integ-integ_old)/integ_old if integ_err < tol_quad: break return integ
def root(N): #zeros laguerre a = roots_laguerre(N)[0] return a
parsec = 3.08568025e+18 # cm # El = ['h','he','li','be','b','c','n','o','f','ne','na', \ 'mg','al','si','p','s','cl','ar','k','ca','sc','ti', \ 'v','cr','mn','fe','co','ni','cu','zn',\ 'ga','ge','as','se','br','kr'] Ionstage = ['I','II','III','IV','V','VI','VII','VIII','IX','X','XI','XII','XIII', \ 'XIV','XV','XVI','XVII','XVIII','XIX','XX','XXI',' XXII','XXIII','XXIV', \ 'XXV','XXVI','XXVII','XXVIII','XXIX','XXX','XXXI','XXXII','XXXIII','XXXIV', \ 'XXXV','XXXVI','XXXVII'] Spd = ['S', 'P', 'D', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'O', 'Q', 'R', 'T', 'U', 'V', 'W', \ 'X','Y', 'Z', 'A','B', 'C', 'S1', 'P1', 'D1', 'E1', 'F1', 'G1', 'H1', 'I1', 'K1', 'L1', \ 'M1', 'N1', 'O1', 'Q1', 'R1', 'T1', 'U1', 'V1', 'W1','X1','Y1', 'Z1', 'A1','B1', 'C1'] # # data for Gauss-Laguerre integration # ngl = 12 zgl = special.roots_laguerre(ngl) xgl = zgl[0] wgl = zgl[1] #ngl = 12 #xgl = np.asarray([0.115722117358021,0.611757484515131,1.512610269776419,2.833751337743509 # ,4.599227639418353,6.844525453115181,9.621316842456871,13.006054993306350 # ,17.116855187462260,22.151090379396983,28.487967250983992,37.099121044466926], 'float64') # # #wgl = np.asarray([2.647313710554435e-01,3.777592758731382e-01,2.440820113198774e-01,9.044922221168074e-02 # ,2.010238115463406e-02,2.663973541865321e-03,2.032315926629993e-04,8.365055856819753e-06 # ,1.668493876540914e-07,1.342391030515027e-09,3.061601635035012e-12,8.148077467426124e-16], 'float64')
nstart = args.n if nstart != 1: nstart = nstart -1 output = args.output resultLeg = [] errorLeg = [] resultLag = [] errorLag = [] timeLeg = [] timeLag = [] Ns = [] for n in range(nstart,N+1): print('Running for N = {}'.format(n)) xleg, wleg = leggauss(n) xlag, wlag = roots_laguerre(n) leQuad = gQuad(xleg,xlag,wleg,wlag) timer = timeit.Timer(lambda: leQuad.integrate_legrende(-2,2)) time = timer.timeit(1) resultLeg.append(leQuad.getResult) errorLeg.append(leQuad.error) timeLeg.append(time) leQuad.integrate_laguerre() timer = timeit.Timer(lambda: leQuad.integrate_laguerre()) time = timer.timeit(1) errorLag.append(leQuad.error) resultLag.append(leQuad.getResult) timeLag.append(time) Ns.append(n)
def root(x): #zeros laguerre a = roots_laguerre(x)[0] return a
for l in prange(N): for m in prange(N): for n in prange(N): x1, y1, z1, x2, y2, z2 = xm*x[i]+xl, xm*x[j]+xl, xm*x[k]+xl, xm*x[l]+xl, xm*x[m]+xl, xm*x[n]+xl exp1 = -2*alpha*np.sqrt(x1*x1+ y1*y1 + z1*z1) exp2 = -2*alpha*np.sqrt(x2*x2+y2*y2+z2*z2) deno = np.sqrt((x1-x2)**2 + (y1-y2)**2 + (z1-z2)**2) weight = w[i]*w[j]*w[k]*w[l]*w[m]*w[n] if deno > 10**-10: totalSum += weight*np.exp(exp1+ exp2)/deno return totalSum*((b-a)*0.5)**6 if __name__ == "__main__": leg, legw = leggauss(31) lag, lagw = roots_laguerre(31) quad = gQuad(leg,lag, legw,lagw) result_leg = quad.integrate_legrende(-2,2) result_lag = quad.integrate_laguerre() analytical = 5*np.pi**2/16**2 error_lag = analytical - result_lag error_leg = analytical - result_leg print('Analytical: {:.5f}'.format(analytical)) print('Result laguerre: {:.5f}'.format(result_lag)) print('Result legendre: {:.5f}'.format(result_leg)) print('Error leguerre: {:.5f}'.format(error_lag)) print('Error legendre: {:.5f}'.format(error_leg))
#krok z jest stosunkowo niewielki, aby w przejrzysty sposob pokazac przebieg całki #zakres calki #a = 0 #b = np.Infinity #nie bedzie konieczne definiowanie zakresu calki wynika to bezposrednio #ze specyfikacji scipy.special.roots_laguerre #https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.roots_laguerre.html #ilość wezłów #ilosc wybrana przy pomocy wolframalpha oraz obliczenia I_n dla przykładowych wartości z z zakresu [0.5,2.5], # gdzie I_n += ai[i]*function1(z, ti[i]) dla wybranych kilku próbnych z n = 20 #wezły oraz współczynniki kwadratury Gaussa- Laguerre'a ti, ai = roots_laguerre(n) #pomocnicza pusta tablica calki = [] print(" z ", "Obliczona całka") for j in range(len(z)): I_n = 0 for i in range(len(ai)): I_n += ai[i] * function1(z[j], ti[i]) calki.append(I_n) for i in range(len(calki)): print("%1.2f %18.15f" % (z[i], calki[i])) #wartość minimalna całki
def laguerreRoots(self, n): return special.roots_laguerre(n)