void SBGaussian::SBGaussianImpl::shoot(PhotonArray& photons, UniformDeviate ud) const { const int N = photons.size(); dbg<<"Gaussian shoot: N = "<<N<<std::endl; dbg<<"Target flux = "<<getFlux()<<std::endl; double fluxPerPhoton = _flux/N; for (int i=0; i<N; i++) { // First get a point uniformly distributed on unit circle #ifdef USE_COS_SIN double theta = 2.*M_PI*ud(); double rsq = ud(); // cumulative dist function P(<r) = r^2 for unit circle double sint,cost; math::sincos(theta, sint, cost); // Then map radius to the desired Gaussian with analytic transformation double rFactor = _sigma * std::sqrt( -2. * std::log(rsq)); photons.setPhoton(i, rFactor*cost, rFactor*sint, fluxPerPhoton); #else double xu, yu, rsq; do { xu = 2.*ud()-1.; yu = 2.*ud()-1.; rsq = xu*xu+yu*yu; } while (rsq>=1. || rsq==0.); // Then map radius to the desired Gaussian with analytic transformation double rFactor = _sigma * std::sqrt( -2. * std::log(rsq) / rsq); photons.setPhoton(i, rFactor*xu, rFactor*yu, fluxPerPhoton); #endif } dbg<<"Gaussian Realized flux = "<<photons.getTotalFlux()<<std::endl; }
void SBAutoConvolve::SBAutoConvolveImpl::shoot(PhotonArray& photons, UniformDeviate ud) const { const int N = photons.size(); dbg<<"AutoConvolve shoot: N = "<<N<<std::endl; dbg<<"Target flux = "<<getFlux()<<std::endl; _adaptee.shoot(photons, ud); PhotonArray temp(N); _adaptee.shoot(temp, ud); photons.convolve(temp, ud); dbg<<"AutoConvolve Realized flux = "<<photons.getTotalFlux()<<std::endl; }
void SBAutoCorrelate::SBAutoCorrelateImpl::shoot(PhotonArray& photons, UniformDeviate ud) const { const int N = photons.size(); dbg<<"AutoCorrelate shoot: N = "<<N<<std::endl; dbg<<"Target flux = "<<getFlux()<<std::endl; _adaptee.shoot(photons, ud); PhotonArray temp(N); _adaptee.shoot(temp, ud); // Flip sign of (x,y) in one of the results temp.scaleXY(-1.); photons.convolve(temp, ud); dbg<<"AutoCorrelate Realized flux = "<<photons.getTotalFlux()<<std::endl; }
void PhotonArray::convolveShuffle(const PhotonArray& rhs, UniformDeviate ud) { int N = size(); if (rhs.size() != N) throw std::runtime_error("PhotonArray::convolve with unequal size arrays"); double xSave=0.; double ySave=0.; double fluxSave=0.; for (int iOut = N-1; iOut>=0; iOut--) { // Randomly select an input photon to use at this output // NB: don't need floor, since rhs is positive, so floor is superfluous. int iIn = int((iOut+1)*ud()); if (iIn > iOut) iIn=iOut; // should not happen, but be safe if (iIn < iOut) { // Save input information xSave = _x[iOut]; ySave = _y[iOut]; fluxSave = _flux[iOut]; } _x[iOut] = _x[iIn] + rhs._x[iOut]; _y[iOut] = _y[iIn] + rhs._y[iOut]; _flux[iOut] = _flux[iIn] * rhs._flux[iOut] * N; if (iIn < iOut) { // Move saved info to new location in array _x[iIn] = xSave; _y[iIn] = ySave ; _flux[iIn] = fluxSave; } } }
void PhotonArray::takeYFrom(const PhotonArray& rhs) { assert(rhs.size()==size()); int N = size(); for (int i=0; i<N; i++) { _y[i] = rhs._x[i]; _flux[i] *= rhs._flux[i]*N; } }
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; }
void PhotonArray::assignAt(int istart, const PhotonArray& rhs) { if (istart + rhs.size() > size()) throw std::runtime_error("Trying to assign past the end of PhotonArray"); std::copy(rhs._x.begin(), rhs._x.end(), _x.begin()+istart); std::copy(rhs._y.begin(), rhs._y.end(), _y.begin()+istart); std::copy(rhs._flux.begin(), rhs._flux.end(), _flux.begin()+istart); if (rhs._dxdz.size() > 0) { allocateAngleVectors(); std::copy(rhs._dxdz.begin(), rhs._dxdz.end(), _dxdz.begin()+istart); std::copy(rhs._dydz.begin(), rhs._dydz.end(), _dydz.begin()+istart); } if (rhs._wavelength.size() > 0) { allocateWavelengthVector(); std::copy(rhs._wavelength.begin(), rhs._wavelength.end(), _wavelength.begin()+istart); } }
void PhotonArray::convolve(const PhotonArray& rhs, UniformDeviate ud) { // If both arrays have correlated photons, then we need to shuffle the photons // as we convolve them. if (_is_correlated && rhs._is_correlated) return convolveShuffle(rhs,ud); // If neither or only one is correlated, we are ok to just use them in order. if (rhs.size() != size()) throw std::runtime_error("PhotonArray::convolve with unequal size arrays"); // Add x coordinates: std::transform(_x.begin(), _x.end(), rhs._x.begin(), _x.begin(), std::plus<double>()); // Add y coordinates: std::transform(_y.begin(), _y.end(), rhs._y.begin(), _y.begin(), std::plus<double>()); // Multiply fluxes, with a factor of N needed: std::transform(_flux.begin(), _flux.end(), rhs._flux.begin(), _flux.begin(), MultXYScale(size())); // If rhs was correlated, then the output will be correlated. // This is ok, but we need to mark it as such. if (rhs._is_correlated) _is_correlated = true; }