Beispiel #1
0
    double AiryInfoObs::chord(double r, double h, double rsq, double hsq) const
    {
        if (r==0.)
            return 0.;
#ifdef AIRY_DEBUG
        else if (r<h)
            throw SBError("Airy calculation r<h");
        else if (h < 0.)
            throw SBError("Airy calculation h<0");
#endif
        else
            return rsq*std::asin(h/r) - h*sqrt(rsq-hsq);
    }
Beispiel #2
0
    double MoffatCalculateScaleRadiusFromHLR(double re, double rm, double beta)
    {
        dbg<<"Start MoffatCalculateScaleRadiusFromHLR\n";
        // The basic equation that is relevant here is the flux of a Moffat profile
        // out to some radius.
        // flux(R) = int( (1+r^2/rd^2 )^(-beta) 2pi r dr, r=0..R )
        //         = (pi rd^2 / (beta-1)) (1 - (1+R^2/rd^2)^(1-beta) )
        // For now, we can ignore the first factor.  We call the second factor fluxfactor below,
        // or in this function f(R).
        //
        // We are given two values of R for which we know that the ratio of their fluxes is 1/2:
        // f(re) = 0.5 * f(rm)
        //
        if (rm == 0.) {
            // If rm = infinity (which we actually indicate with rm=0), then we can solve for
            // rd analytically:
            //
            // f(rm) = 1
            // f(re) = 0.5 = 1 - (1+re^2/rd^2)^(1-beta)
            // re^2/rd^2 = 0.5^(1/(1-beta)) - 1
            double rerd = std::sqrt( std::pow(0.5, 1./(1.-beta)) - 1.);
            dbg<<"rm = 0, so analytic.\n";
            xdbg<<"rd = re/rerd = "<<re<<" / "<<rerd<<" = "<<re/rerd<<std::endl;
            return re / rerd;
        } else {
            // If trunc < infinity, then the equations are slightly circular:
            // f(rm) = 1 - (1 + rm^2/rd^2)^(1-beta)
            // 2*f(re) = 2 - 2*(1 + re^2/rd^2)^(1-beta)
            // 2*(1+re^2/rd^2)^(1-beta) = 1 + (1+rm^2/rd^2)^(1-beta)
            //
            // As rm decreases, rd increases.
            // Eventually rd increases to infinity.  When does that happen:
            // Take the limit as rd->infinity in the above equation:
            // 2 + 2*(1-beta) re^2/rd^2) = 1 + 1 + (1-beta) rm^2/rd^2
            // 2 re^2 = rm^2
            // rm = sqrt(2) * re
            // So this is the limit for how low rm is allowed to be for a given re
            if (rm <= std::sqrt(2.) * re)
                throw SBError("Moffat truncation radius must be > sqrt(2) * half_light_radius.");

            dbg<<"rm != 0, so not analytic.\n";
            MoffatScaleRadiusFunc func(re,rm,beta);
            // For the lower bound of rd, we can use the untruncated value:
            double r1 = re / std::sqrt( std::pow(0.5, 1./(1.-beta)) - 1.);
            xdbg<<"r1 = "<<r1<<std::endl;
            // For the upper bound, we don't really have a good choice, so start with 2*r1
            // and we'll expand it if necessary.
            double r2 = 2. * r1;
            xdbg<<"r2 = "<<r2<<std::endl;
            Solve<MoffatScaleRadiusFunc> solver(func,r1,r2);
            solver.setMethod(Brent);
            solver.bracketUpper();
            xdbg<<"After bracket, range is "<<solver.getLowerBound()<<" .. "<<
                solver.getUpperBound()<<std::endl;
            double rd = solver.root();
            xdbg<<"Root is "<<rd<<std::endl;
            return rd;
        }
    }
Beispiel #3
0
    void SBConvolve::SBConvolveImpl::add(const SBProfile& rhs) 
    {
        dbg<<"Start SBConvolveImpl::add.  Adding item # "<<_plist.size()+1<<std::endl;

        // Add new terms(s) to the _plist:
        assert(GetImpl(rhs));
        const SBProfileImpl* p = GetImpl(rhs);
        const SBConvolveImpl* sbc = dynamic_cast<const SBConvolveImpl*>(p);
        const SBAutoConvolve::SBAutoConvolveImpl* sbc2 =
            dynamic_cast<const SBAutoConvolve::SBAutoConvolveImpl*>(p);
        const SBAutoCorrelate::SBAutoCorrelateImpl* sbc3 =
            dynamic_cast<const SBAutoCorrelate::SBAutoCorrelateImpl*>(p);
        if (sbc) {
            dbg<<"  (Item is really "<<sbc->_plist.size()<<" items.)"<<std::endl;
            // If rhs is an SBConvolve, copy its list here
            for (ConstIter pptr = sbc->_plist.begin(); pptr!=sbc->_plist.end(); ++pptr) {
                if (!pptr->isAnalyticK() && !_real_space) 
                    throw SBError("SBConvolve requires members to be analytic in k");
                if (!pptr->isAnalyticX() && _real_space)
                    throw SBError("Real_space SBConvolve requires members to be analytic in x");
                _plist.push_back(*pptr);
            }
        } else if (sbc2) {
            dbg<<"  (Item is really AutoConvolve.)"<<std::endl;
            // If rhs is an SBAutoConvolve, put two of its item here:
            const SBProfile& obj = sbc2->getAdaptee();
            if (!obj.isAnalyticK() && !_real_space) 
                throw SBError("SBConvolve requires members to be analytic in k");
            if (!obj.isAnalyticX() && _real_space)
                throw SBError("Real_space SBConvolve requires members to be analytic in x");
            _plist.push_back(obj);
            _plist.push_back(obj);
        } else if (sbc3) {
            dbg<<"  (Item is really AutoCorrelate items.)"<<std::endl;
            // If rhs is an SBAutoCorrelate, put its item and 180 degree rotated verion here:
            const SBProfile& obj = sbc3->getAdaptee();
            if (!obj.isAnalyticK() && !_real_space) 
                throw SBError("SBConvolve requires members to be analytic in k");
            if (!obj.isAnalyticX() && _real_space)
                throw SBError("Real_space SBConvolve requires members to be analytic in x");
            _plist.push_back(obj);
            SBProfile temp = obj;
            temp.applyRotation(180. * degrees);
            _plist.push_back(temp);
        } else {
            if (!rhs.isAnalyticK() && !_real_space) 
                throw SBError("SBConvolve requires members to be analytic in k");
            if (!rhs.isAnalyticX() && _real_space)
                throw SBError("Real-space SBConvolve requires members to be analytic in x");
            _plist.push_back(rhs);
        }
    }
Beispiel #4
0
    void SBConvolve::SBConvolveImpl::add(const SBProfile& sbp)
    {
        dbg<<"Start SBConvolveImpl::add.  Adding item # "<<_plist.size()+1<<std::endl;

        // Add new terms(s) to the _plist:
        assert(GetImpl(sbp));
        const SBProfileImpl* p = GetImpl(sbp);
        const SBConvolveImpl* sbc = dynamic_cast<const SBConvolveImpl*>(p);
        const SBAutoConvolve::SBAutoConvolveImpl* sbc2 =
            dynamic_cast<const SBAutoConvolve::SBAutoConvolveImpl*>(p);
        const SBAutoCorrelate::SBAutoCorrelateImpl* sbc3 =
            dynamic_cast<const SBAutoCorrelate::SBAutoCorrelateImpl*>(p);
        if (sbc) {
            dbg<<"  (Item is really "<<sbc->_plist.size()<<" items.)"<<std::endl;
            // If sbp is an SBConvolve, copy its list here
            for (ConstIter pptr = sbc->_plist.begin(); pptr!=sbc->_plist.end(); ++pptr) add(*pptr);
        } else if (sbc2) {
            dbg<<"  (Item is really AutoConvolve.)"<<std::endl;
            // If sbp is an SBAutoConvolve, put two of its item here:
            const SBProfile& obj = sbc2->getAdaptee();
            add(obj);
            add(obj);
        } else if (sbc3) {
            dbg<<"  (Item is really AutoCorrelate items.)"<<std::endl;
            // If sbp is an SBAutoCorrelate, put its item and 180 degree rotated verion here:
            const SBProfile& obj = sbc3->getAdaptee();
            add(obj);
            SBProfile temp = obj.rotate(180. * degrees);
            add(temp);
        } else {
            if (!sbp.isAnalyticK() && !_real_space)
                throw SBError("SBConvolve requires members to be analytic in k");
            if (!sbp.isAnalyticX() && _real_space)
                throw SBError("Real-space SBConvolve requires members to be analytic in x");
            _plist.push_back(sbp);
        }
        _x0 += sbp.centroid().x;
        _y0 += sbp.centroid().y;
        _isStillAxisymmetric = _isStillAxisymmetric && sbp.isAxisymmetric();
        _fluxProduct *= sbp.getFlux();
    }
Beispiel #5
0
    SpergelInfo::SpergelInfo(double nu, const GSParamsPtr& gsparams) :
        _nu(nu), _gsparams(gsparams),
        _gamma_nup1(boost::math::tgamma(_nu+1.0)),
        _gamma_nup2(_gamma_nup1 * (_nu+1)),
        _xnorm0((_nu > 0.) ? _gamma_nup1 / (2. * _nu) * std::pow(2., _nu) : INFINITY),
        _maxk(0.), _stepk(0.), _re(0.)
    {
        dbg<<"Start SpergelInfo constructor for nu = "<<_nu<<std::endl;

        if (_nu < sbp::minimum_spergel_nu || _nu > sbp::maximum_spergel_nu)
            throw SBError("Requested Spergel index out of range");
    }
Beispiel #6
0
    double AiryInfoNoObs::kValue(double ksq_over_pisq) const
    {
        if (ksq_over_pisq >= 4.) return 0.;
        if (ksq_over_pisq == 0.) return M_PI;

        /* in between we calculate half-height at intersection */
        double hsq = 1. - ksq_over_pisq/4.;
#ifdef AIRY_DEBUG
        if (hsq<0.) throw SBError("Airy calculation half-height invalid");
#endif
        double h = sqrt(hsq);

        return 2. * (std::asin(h) - h*sqrt(1.-hsq));
    }
Beispiel #7
0
    /* area inside intersection of 2 circles both with radius r, seperated by t*/
    double AiryInfoObs::circle_intersection(
        double r, double rsq, double tsq) const
    {
        assert(r >= 0.);
        if (tsq >= 4.*rsq) return 0.;
        if (tsq == 0.) return M_PI*rsq;

        /* in between we calculate half-height at intersection */
        double hsq = rsq - tsq/4.;
#ifdef AIRY_DEBUG
        if (hsq<0.) throw SBError("Airy calculation half-height invalid");
#endif
        double h = sqrt(hsq);

        return 2.*chord(r,h,rsq,hsq);
    }
Beispiel #8
0
 boost::shared_ptr<PhotonArray> SBConvolve::SBConvolveImpl::shoot(int N, UniformDeviate u) const
 {
     dbg<<"Convolve shoot: N = "<<N<<std::endl;
     dbg<<"Target flux = "<<getFlux()<<std::endl;
     std::list<SBProfile>::const_iterator pptr = _plist.begin();
     if (pptr==_plist.end())
         throw SBError("Cannot shoot() for empty SBConvolve");
     boost::shared_ptr<PhotonArray> result = pptr->shoot(N, u);
     // It may be necessary to shuffle when convolving because we do
     // do not have a gaurantee that the convolvee's photons are
     // uncorrelated, e.g. they might both have their negative ones
     // at the end.
     // However, this decision is now made by the convolve method.
     for (++pptr; pptr != _plist.end(); ++pptr)
         result->convolve(*pptr->shoot(N, u), u);
     dbg<<"Convolve Realized flux = "<<result->getTotalFlux()<<std::endl;
     return result;
 }
 void SBConvolve::SBConvolveImpl::shoot(PhotonArray& photons, UniformDeviate ud) const
 {
     const int N = photons.size();
     dbg<<"Convolve shoot: N = "<<N<<std::endl;
     dbg<<"Target flux = "<<getFlux()<<std::endl;
     std::list<SBProfile>::const_iterator pptr = _plist.begin();
     if (pptr==_plist.end())
         throw SBError("Cannot shoot() for empty SBConvolve");
     pptr->shoot(photons, ud);
     // It may be necessary to shuffle when convolving because we do
     // do not have a gaurantee that the convolvee's photons are
     // uncorrelated, e.g. they might both have their negative ones
     // at the end.
     // However, this decision is now made by the convolve method.
     for (++pptr; pptr != _plist.end(); ++pptr) {
         PhotonArray temp(N);
         pptr->shoot(temp, ud);
         photons.convolve(temp, ud);
     }
     dbg<<"Convolve Realized flux = "<<photons.getTotalFlux()<<std::endl;
 }
Beispiel #10
0
    double SBConvolve::SBConvolveImpl::xValue(const Position<double>& pos) const
    {
        // Perform a direct calculation of the convolution at a particular point by
        // doing the real-space integral.
        // Note: This can only really be done one pair at a time, so it is
        // probably rare that this will be more efficient if N > 2.
        // For now, we don't bother implementing this for N > 2.

        if (_plist.size() == 2) {
            const SBProfile& p1 = _plist.front();
            const SBProfile& p2 = _plist.back();
            if (p2.isAxisymmetric())
                return RealSpaceConvolve(p2,p1,pos,_fluxProduct,this->gsparams);
            else
                return RealSpaceConvolve(p1,p2,pos,_fluxProduct,this->gsparams);
        } else if (_plist.empty())
            return 0.;
        else if (_plist.size() == 1)
            return _plist.front().xValue(pos);
        else
            throw SBError("Real-space integration of more than 2 profiles is not implemented.");
    }
Beispiel #11
0
    /* area inside intersection of 2 circles radii r & s, seperated by t*/
    double AiryInfoObs::circle_intersection(
        double r, double s, double rsq, double ssq, double tsq) const
    {
        assert(r >= s);
        assert(s >= 0.);
        double rps_sq = (r+s)*(r+s);
        if (tsq >= rps_sq) return 0.;
        double rms_sq = (r-s)*(r-s);
        if (tsq <= rms_sq) return M_PI*ssq;

        /* in between we calculate half-height at intersection */
        double hsq = 0.5*(rsq + ssq) - (tsq*tsq + rps_sq*rms_sq)/(4.*tsq);
#ifdef AIRY_DEBUG
        if (hsq<0.) throw SBError("Airy calculation half-height invalid");
#endif
        double h = sqrt(hsq);

        if (tsq < rsq - ssq)
            return M_PI*ssq - chord(s,h,ssq,hsq) + chord(r,h,rsq,hsq);
        else
            return chord(s,h,ssq,hsq) + chord(r,h,rsq,hsq);
    }
Beispiel #12
0
    SBMoffat::SBMoffatImpl::SBMoffatImpl(double beta, double size, RadiusType rType,
                                         double trunc, double flux,
                                         const GSParamsPtr& gsparams) :
        SBProfileImpl(gsparams),
        _beta(beta), _flux(flux), _trunc(trunc),
        _ft(Table<double,double>::spline),
        _re(0.), // initially set to zero, may be updated by size or getHalfLightRadius().
        _stepk(0.), // calculated by stepK() and stored.
        _maxk(0.) // calculated by maxK() and stored.
    {
        xdbg<<"Start SBMoffat constructor: \n";
        xdbg<<"beta = "<<_beta<<"\n";
        xdbg<<"flux = "<<_flux<<"\n";
        xdbg<<"trunc = "<<_trunc<<"\n";

        if (_trunc == 0. && beta <= 1.1)
            throw SBError("Moffat profiles with beta <= 1.1 must be truncated.");

        if (_trunc < 0.)
            throw SBError("Invalid negative truncation radius provided to SBMoffat.");

        // First, relation between FWHM and rD:
        double FWHMrD = 2.* std::sqrt(std::pow(2., 1./_beta)-1.);
        xdbg<<"FWHMrD = "<<FWHMrD<<"\n";

        // Set size of this instance according to type of size given in constructor:
        switch (rType) {
          case FWHM:
               _rD = size / FWHMrD;
               break;
          case HALF_LIGHT_RADIUS:
               {
                   _re = size;
                   // This is a bit complicated, so break it out into its own function.
                   _rD = MoffatCalculateScaleRadiusFromHLR(_re,_trunc,_beta);
               }
               break;
          case SCALE_RADIUS:
               _rD = size;
               break;
          default:
               throw SBError("Unknown SBMoffat::RadiusType");
        }

        _rD_sq = _rD * _rD;
        _inv_rD = 1./_rD;
        _inv_rD_sq = _inv_rD*_inv_rD;

        if (_trunc > 0.) {
            _maxRrD = _trunc * _inv_rD;
            xdbg<<"maxRrD = "<<_maxRrD<<"\n";

            // Analytic integration of total flux:
            _fluxFactor = 1. - std::pow( 1+_maxRrD*_maxRrD, (1.-_beta));
        } else {
            _fluxFactor = 1.;

            // Set maxRrD to the radius where missing fractional flux is xvalue_accuracy
            // (1+R^2)^(1-beta) = xvalue_accuracy
            _maxRrD = std::sqrt(std::pow(this->gsparams->xvalue_accuracy, 1. / (1. - _beta))- 1.);
            xdbg<<"Not truncated.  Calculated maxRrD = "<<_maxRrD<<"\n";
        }

        _FWHM = FWHMrD * _rD;
        _maxR = _maxRrD * _rD;
        _maxR_sq = _maxR * _maxR;
        _maxRrD_sq = _maxRrD * _maxRrD;
        _norm = _flux * (_beta-1.) / (M_PI * _fluxFactor * _rD_sq);
        _knorm = _flux;

        dbg << "Moffat rD " << _rD << " fluxFactor " << _fluxFactor
            << " norm " << _norm << " maxR " << _maxR << std::endl;

        if (std::abs(_beta-1) < this->gsparams->xvalue_accuracy)
            _pow_beta = &SBMoffatImpl::pow_1;
        else if (std::abs(_beta-1.5) < this->gsparams->xvalue_accuracy)
            _pow_beta = &SBMoffatImpl::pow_15;
        else if (std::abs(_beta-2) < this->gsparams->xvalue_accuracy)
            _pow_beta = &SBMoffatImpl::pow_2;
        else if (std::abs(_beta-2.5) < this->gsparams->xvalue_accuracy)
            _pow_beta = &SBMoffatImpl::pow_25;
        else if (std::abs(_beta-3) < this->gsparams->xvalue_accuracy)
            _pow_beta = &SBMoffatImpl::pow_3;
        else if (std::abs(_beta-3.5) < this->gsparams->xvalue_accuracy)
            _pow_beta = &SBMoffatImpl::pow_35;
        else if (std::abs(_beta-4) < this->gsparams->xvalue_accuracy)
            _pow_beta = &SBMoffatImpl::pow_4;
        else _pow_beta = &SBMoffatImpl::pow_gen;

        if (_trunc > 0.) _kV = &SBMoffatImpl::kV_trunc;
        else if (std::abs(_beta-1.5) < this->gsparams->kvalue_accuracy)
            _kV = &SBMoffatImpl::kV_15;
        else if (std::abs(_beta-2) < this->gsparams->kvalue_accuracy)
            _kV = &SBMoffatImpl::kV_2;
        else if (std::abs(_beta-2.5) < this->gsparams->kvalue_accuracy)
            _kV = &SBMoffatImpl::kV_25;
        else if (std::abs(_beta-3) < this->gsparams->kvalue_accuracy) {
            _kV = &SBMoffatImpl::kV_3; _knorm /= 2.;
        } else if (std::abs(_beta-3.5) < this->gsparams->kvalue_accuracy) {
            _kV = &SBMoffatImpl::kV_35; _knorm /= 3.;
        } else if (std::abs(_beta-4) < this->gsparams->kvalue_accuracy) {
            _kV = &SBMoffatImpl::kV_4; _knorm /= 8.;
        } else {
            _kV = &SBMoffatImpl::kV_gen;
            _knorm *= 4. / (boost::math::tgamma(beta-1.) * std::pow(2.,beta));
        }
    }