def sigma_z2(self, R, Z, ilist=None) : """ Compute SigmaZ^2 : the second centred velocity moment from an MGE model :param R: input Radial coordinate :param Z: input Vertical coordinate :param ilist: indices for the Gaussians to take into account """ ### Set the list of indices ilist = self._set_ilist(ilist) R2 = R*R Z2 = Z*Z r2 = R2 + Z2 r = sqrt(r2) r2soft = r2 + self.SoftarcMbh2 rsoft = sqrt(r2soft) ## Compute the mass density for individual gaussians as well as the sum [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) sigz2 = np.sum(Wquad[i] * self._intsigma_z2(Xquad[i], R2, Z2, ilist) for i in xrange(self.Nquad)) # Contribution from the BH if self.Mbh > 0. : for i in ilist : # facMbh in M arcsec2 pc-2 / 4PI G var = (r / self._pParam.dqSig3Darc[i]).astype(floatG) mask = (var < _Maximum_Value_forEXPERFC) lasterm = np.empty_like(var) # facMbh in M arcsec2 pc-2 / 4PI G lasterm[mask] = self._dParam.sqpi2s[i] * special.erfc(var[mask]) * np.exp(var[mask]**2) lasterm[~mask] = 2. / (r[~mask] + sqrt(r2[~mask] + self._dParam.qq2s2[i])) sigz2 += self.rho[i] * self.facMbh * (1. / rsoft - lasterm) # in rho * M arcsec pc-2 / 4 PI G return sigz2 * self.PIG / self.rhoT
def vtheta2(self, R, Z, ilist=None) : """ Compute Vtheta**2 : the first velocity moment from an MGE model Input : R, Z as input coordinates ilist: indices of the Gaussians """ ### Set the list of indices ilist = self._set_ilist(ilist) R2 = R*R Z2 = Z*Z r2 = R2 + Z2 r = sqrt(r2) r2soft = r2 + self.SoftarcMbh2 rsoft = sqrt(r2soft) ## Compute the mass density for individual gaussians as well as the sum [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) # MU2 VT2 = np.sum(Wquad[i] * self._intvtheta2(Xquad[i], R2, Z2, ilist=ilist) for i in xrange(self.Nquad)) # Contribution from the BH if self.Mbh > 0. : for i in ilist : var = (r / self._pParam.dqSig3Darc[i]).astype(floatG) mask = (var < _Maximum_Value_forEXPERFC) lasterm = np.empty_like(var) # facMbh in M arcsec2 pc-2 / 4PI G lasterm[mask] = self._dParam.sqpi2s[i] * special.erfc(var[mask]) * np.exp(var[mask]**2) lasterm[~mask] = 2. / (r[~mask] + sqrt(r2[~mask] + self._dParam.qq2s2[i])) VT2 += (1. + self._dParam.e2q2Sig3Darc2[i] * R2) * self.rho[i] * self.facMbh \ * (1. / rsoft - lasterm) # in rhoT * M arcsec pc-2 / 4 PI G return VT2 * self.PIG / self.rhoT
def Potential(self, R, Z, ilist=None) : """ Return, for a grid of R and Z the Gravitational potential in km^2.s^2 R and Z should be in arcseconds :param R: cylindrical radius (float or array) in arcseconds :param Z: vertical height (float or array) in arcseconds :param ilist: list of indices for the Gaussians to consider (0 to Ngauss-1) :returns: Gravitational potential :math:`\Phi` in Units of km^2.s-2 :rtype: float or array of float depending on input """ ### Set the list of indices ilist = self._set_ilist(ilist) ### First compute the gaussian quadrature points, and weights [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) R2 = R*R Z2 = Z*Z result = np.sum(Wquad[i] * self._IntPot(Xquad[i], R2, Z2, ilist) for i in xrange(self.Nquad)) if (self.Mbh > 0.) : mask = (R2 + Z2 == 0.) result[~mask] += self.facMbh / sqrt(R2[~mask] + Z2[~mask] + self.SoftarcMbh2) return -4. * np.pi * self.G * result # en km^2.s-2
def _sigma_z2_fromR2Z2(self, R2, Z2, ilist=None) : """ Compute SigmaZ**2 : the second centred velocity moment from an MGE model WARNING: this function takes R2 and Z2 as input, not R and Z Input : R2 and Z2: squares of the R and Z coordinates ilist: indices for Gaussians to take into account """ r2 = R2 + Z2 r = sqrt(r2) r2soft = r2 + self.SoftarcMbh2 rsoft = sqrt(r2soft) ## Compute the mass density for individual gaussians as well as the sum [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) sigz2 = np.sum(Wquad[i] * self._intsigma_z2(Xquad[i], R2, Z2, ilist) for i in xrange(self.Nquad)) # Contribution from the BH if self.Mbh > 0. : for i in ilist: var = (r / self._pParam.dqSig3Darc[i]).astype(floatG) mask = (var < _Maximum_Value_forEXPERFC) lasterm = np.empty_like(var) # facMbh in M arcsec2 pc-2 / 4PI G lasterm[mask] = self._dParam.sqpi2s[i] * special.erfc(var[mask]) * np.exp(var[mask]**2) lasterm[~mask] = 2. / (r[~mask] + sqrt(r2[~mask] + self._dParam.qq2s2[i])) sigz2 += self.rho[i] * self.facMbh * (1. / rsoft - lasterm) # in rho * M arcsec pc-2 / 4 PI G return sigz2 * self.PIG / self.rhoT
def _d2Potd2R(self, R, Z, ilist=None) : ### First compute the gaussian quadrature points, and weights [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) result = np.zeros_like(R) R2 = R*R Z2 = Z*Z for i in xrange(self.Nquad) : result += Wquad[i] * self._Intd2Potd2R(Xquad[i], R2, Z2, ilist) return self.PIG * result / (self.pc_per_arcsec*self/pc_per_arcsec) # en km^2.s-2.pc-2
def _Mu1(self, X, Y, inclin=90., ilist=None) : X2 = X * X Y2 = Y * Y inclin_rad = inclin * np.pi / 180. sini = sin(inclin_rad) cosi = cos(inclin_rad) [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) rhop = self._rhoL2D_fromX2Y2(X2, Y2, ilist) result = np.zeros_like(X2) for i in xrange(shape(X2)[0]) : for j in xrange(shape(X2)[1]) : print "%f %f \n" %(X[i,j], Y[i,j]) ### INTEGRAL between -infinity and infinity along the line of sight result[i,j] = float(scipy.integrate.quad(self._IntlosMu1, -inf, inf, epsabs=1.e-01, epsrel=1.e-01, args=(X2[i,j], Y[i,j], cosi, sini, Xquad, Wquad, ilist))[0]) return sqrt(4. * np.pi * self.G) * result * sini * X / rhop
def sigmaz2_muTheta2(self, R, Z, ilist) : """ Compute both Sigma_Z**2 and Mu_Z**2 the centred and non-centred second order velocity moments from an MGE model op can be "all" or "sigma" or "mu" depending on which quantity is needed Input : R and Z the coordinates ilist : Gaussian indices to take into account """ ### Set the list of indices ilist = self._set_ilist(ilist) R2 = R*R Z2 = Z*Z r2 = R2 + Z2 r = sqrt(r2) r2soft = r2 + self.SoftarcMbh2 rsoft = sqrt(r2soft) ## Compute the mass density for individual gaussians as well as the sum [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) sigz2 = np.zeros_like(R2) # sigmaz2 for i in xrange(self.Nquad) : sigz2 += Wquad[i] * self._intsigma_z2(Xquad[i], R2, Z2, ilist) # MU2 muTheta2 = np.zeros_like(R2) for i in xrange(self.Nquad) : muTheta2 += Wquad[i] * self._intvtheta2(Xquad[i], R2, Z2, ilist) # Contribution from the BH if self.Mbh > 0. : for i in ilist : var = (r / self._pParam.dqSig3Darc[i]).astype(floatG) mask = (var < _Maximum_Value_forEXPERFC) lasterm = np.empty_like(var) # facMbh in M arcsec2 pc-2 / 4PI G lasterm[mask] = self._dParam.sqpi2s[i] * special.erfc(var[mask]) * np.exp(var[mask]**2) lasterm[~mask] = 2. / (r [~mask]+ sqrt(r2[~mask] + self._dParam.qq2s2[i])) sigz2 += self.rho[i] * self.facMbh * (1. / rsoft - lasterm) # in rho * M arcsec pc-2 / 4 PI G muTheta2 += (1. + self._dParam.e2q2Sig3Darc2[i] * R2) * self.rho[i] * self.facMbh \ * (1. / rsoft - lasterm) # in rhoT * M arcsec pc-2 / 4 PI G sigz2 *= self.PIG / self.rhoT muTheta2 *= self.PIG / self.rhoT return sigz2, muTheta2
def _Mu2(self, X, Y, inclin=90., ilist=None) : ilist = self._set_ilist(ilist) ### First compute the gaussian quadrature points, and weights [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) X2 = X * X Y2 = Y * Y self.rhop = np.sum(self.Imax2D[ilist] * exp(- (X2[...,np.newaxis] + Y2[...,np.newaxis] / self.Q2D2[ilist]) / self.dSig2Darc2[ilist])) inclin_rad = inclin * np.pi / 180. sini = sin(inclin_rad) cosi = cos(inclin_rad) sini2 = sini * sini cosi2 = cosi * cosi result = np.zeros_like(X) for i in xrange(self.Nquad) : result += Wquad[i] * self._IntMu2(Xquad[i], X2, Y2, cosi2, sini2, ilist) return 4. * np.pi**1.5 * self.G * result / self.rhop # en km^2.s-2
def kappa(self, R, ilist=None) : """ Return :math:`\kappa`, the epicycle radial frequency for an MGE model :param R: cylindrical radius (float or array) in arcseconds :param Z: vertical height (float or array) in arcseconds :returns: :math:`\kappa` Radial Epicycle frequency [km.s-1.pc-1] :rtype: float or array of float depending on input """ ### Set the list of indices ilist = self._set_ilist(ilist) ### First compute the gaussian quadrature points, and weights [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) result = np.zeros_like(R) R2 = R*R for i in xrange(self.Nquad) : result += Wquad[i] * self._Intkappa(Xquad[i], R2, ilist) return sqrt(self.PIG * result) / self.pc_per_arcsec # en km.s-1.pc-1
def Omega(self, R, ilist=None) : """ Returns :math:`\Omega`, the circular frequency, for a grid of R. R should be in arcseconds :param R: cylindrical radius (float or array) in arcseconds :param Z: vertical height (float or array) in arcseconds :returns: :math:`\Omega` Circular frequency [km.s-1.pc-1] :rtype: float or array of float depending on input """ ### Set the list of indices ilist = self._set_ilist(ilist) ### First compute the gaussian quadrature points, and weights [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) R2 = R*R result = np.sum(Wquad[i] * self._IntVc(Xquad[i], R2, ilist) for i in xrange(self.Nquad)) if (self.Mbh > 0.) : mask = (R == 0.) result[mask] += self.facMbh / np.maximum(1.e-4, self.SoftarcMbh**3) result[~mask] += self.facMbh / (R2[~mask] + self.SoftarcMbh2)**(3.0/2.0) return sqrt(self.PIG * result) / self.pc_per_arcsec # en km.s-1.pc-1
def Vcirc(self, R, ilist=None) : """ Derive the circular velocity for the MGE model taking into account Only the Gaussians from the indice list (ilist) - counting from 0 A softening can be included (eps in pc) :param R: cylindrical radius (float or array) in arcseconds :param ilist: list of indices of Gaussians to count :returns: float/array -- Circular velocity [km.s-1] """ ### Set the list of indices ilist = self._set_ilist(ilist) ### First compute the gaussian quadrature points, and weights [Xquad, Wquad] = quadrat_ps_roots(self.Nquad) R2 = R*R result = R2 * np.sum(Wquad[i] * self._IntVc(Xquad[i], R2, ilist) for i in xrange(self.Nquad)) if (self.Mbh > 0.) : mask = (R == 0.) result[mask] += self.facMbh / np.maximum(1.e-2, self.SoftarcMbh) result[~mask] += self.facMbh / sqrt(R2[~mask] + self.SoftarcMbh2) return sqrt(result * self.PIG) # en km.s-1