def _get_unit_conversion_operator(self, nu): """ Convert sky temperature into W / m^2 / Hz / pixel. If the scene has been initialised with the 'absolute' keyword, the scene is assumed to include the CMB background and the fluctuations (in Kelvin) and the operator follows the non-linear Planck law. Otherwise, the scene only includes the fluctuations (in microKelvin) and the operator is linear (i.e. the output also corresponds to power fluctuations). """ if not self.temperature: return IdentityOperator() # solid angle of a sky pixel omega = 4 * np.pi / self.shape[0] a = 2 * omega * h * nu**3 / c**2 if self.absolute: hnu_k = h * nu / k return a / asoperator(np.expm1)(hnu_k * ReciprocalOperator()) T = self.T_cmb hnu_kT = h * nu / (k * T) val = 1e-6 * a * hnu_kT * np.exp(hnu_kT) / (np.expm1(hnu_kT)**2 * T) return asoperator(val)
def __init__(self, name, layout, image2object=None, object2image=None): if image2object is None and object2image is None: raise ValueError('Neither the image2object nor the object2image tr' 'ansforms are speficied.') Instrument.__init__(self, name, layout) if object2image is not None: self.object2image = asoperator(object2image) self.image2object = self.object2image.I else: self.image2object = asoperator(image2object) self.object2image = self.image2object.I
def __new__(cls, A): A = op.asoperator(A) if isinstance(A, op.IdentityOperator): return norm2 norm = super(norm2_ellipsoid, cls).__new__(cls) norm.A = A return norm
def __new__(cls, A): A = op.asoperator(A) if isinstance(A, op.IdentityOperator): return norm2 norm = super(norm2_ellipsoid, cls).__new__(cls) norm.A = A return norm
def __init__(self, shape, topixel=None, ndim=None, dtype=float, **keywords): """ Parameters ---------- shape : tuple of integers The surface shape. ndim : int, optional The number of splittable (indexable) dimensions. It is the actual number of dimensions of the layout. It can be lower than that specified by the layout shape, in which case the extra dimensions are instructed not to be split. topixel : Operator, optional World-to-pixel coordinate transform. """ PackedTable.__init__(self, shape, ndim=ndim) if topixel is None: topixel = IdentityOperator(self.shape[:self.ndim]) else: topixel = asoperator(topixel) self.dtype = np.dtype(dtype) self.topixel = topixel self.toworld = topixel.I for k, v in keywords.items(): setattr(self, k, v)
def __init__(self, shape, topixel=None, to1d=None, origin='upper', startswith1=False, **keywords): """ Parameters ---------- shape : tuple of integers The surface shape. startswith1 : bool If True, columns and row starts with 1 instead of 0. topixel : Operator, optional World-to-pixel coordinate transform. to1d : Operator, optional Nd-to-1d pixel index transform. """ origins = 'upper', 'lower' if not isinstance(origin, str): raise TypeError('Invalid origin.') origin = origin.lower() if origin not in origins: raise ValueError( 'Invalid origin {0!r}. Expected values are {1}.'.format( origin, strenum(origins))) Scene.__init__(self, shape, topixel=topixel, **keywords) if self.ndim != 2: raise ValueError('The scene is not 2-dimensional.') self.origin = origin self.startswith1 = bool(startswith1) if to1d is not None: to1d = asoperator(to1d) self.toNd = to1d.I else: self.toNd = None self.to1d = to1d
def test_block_row2(): p = np.matrix([[1, 0], [0, 2], [1, 0]]) o = asoperator(np.matrix(p)) r = BlockRowOperator([o, 2*o], axisin=0) assert_eq(r.todense(), np.hstack([p, 2*p])) assert_eq(r.T.todense(), r.todense().T) r = BlockRowOperator([o, 2*o], new_axisin=0) assert_eq(r.todense(), np.hstack([p, 2*p])) assert_eq(r.T.todense(), r.todense().T)
def test_block_column2(): p = np.matrix([[1, 0], [0, 2], [1, 0]]) o = asoperator(np.matrix(p)) e = BlockColumnOperator([o, 2*o], axisout=0) assert_eq(e.todense(), np.vstack([p, 2*p])) assert_eq(e.T.todense(), e.todense().T) e = BlockColumnOperator([o, 2*o], new_axisout=0) assert_eq(e.todense(), np.vstack([p, 2*p])) assert_eq(e.T.todense(), e.todense().T)
def test_block_row2(): p = np.matrix([[1, 0], [0, 2], [1, 0]]) o = asoperator(np.matrix(p)) r = BlockRowOperator([o, 2 * o], axisin=0) assert_eq(r.todense(), np.hstack([p, 2 * p])) assert_eq(r.T.todense(), r.todense().T) r = BlockRowOperator([o, 2 * o], new_axisin=0) assert_eq(r.todense(), np.hstack([p, 2 * p])) assert_eq(r.T.todense(), r.todense().T)
def test_block_column2(): p = np.matrix([[1, 0], [0, 2], [1, 0]]) o = asoperator(np.matrix(p)) e = BlockColumnOperator([o, 2 * o], axisout=0) assert_eq(e.todense(), np.vstack([p, 2 * p])) assert_eq(e.T.todense(), e.todense().T) e = BlockColumnOperator([o, 2 * o], new_axisout=0) assert_eq(e.todense(), np.vstack([p, 2 * p])) assert_eq(e.T.todense(), e.todense().T)
def get_unit_conversion_operator(self, nu): """ Return an operator to convert sky temperatures into W / m^2 / Hz / pixel. If the scene has been initialized with the 'absolute' keyword, the scene is assumed to include the CMB background and the fluctuations (in Kelvin) and the operator follows the non-linear Planck law. Otherwise, the scene only includes the fluctuations (in microKelvin) and the operator is linear (i.e. the output also corresponds to power fluctuations). Parameter --------- nu : float The frequency, at which the conversion is performed [Hz]. Example ------- > scene = SceneHealpixCMB(256, absolute=False) > op = scene.get_unit_conversion_operator(150e9) > dT = 200 # µK > print(op(dT)) # W / m^2 / Hz / pixel 1.2734621598076659e-26 > scene = SceneHealpixCMB(256, absolute=True) > op = scene.get_unit_conversion_operator(150e9) > T = 2.7 # K > print(op(T)) # W / m^2 / Hz / pixel 5.94046610468e-23 """ a = 2 * self.solid_angle * h * nu**3 / c**2 if self.absolute: hnu_k = h * nu / k return a / asoperator(np.expm1)(hnu_k * ReciprocalOperator()) T = self.temperature hnu_kT = h * nu / (k * T) val = 1e-6 * a * hnu_kT * np.exp(hnu_kT) / (np.expm1(hnu_kT)**2 * T) return asoperator(val)
def get_unit_conversion_operator(self, nu): """ Return an operator to convert sky temperatures into W / m^2 / Hz / pixel. If the scene has been initialized with the 'absolute' keyword, the scene is assumed to include the CMB background and the fluctuations (in Kelvin) and the operator follows the non-linear Planck law. Otherwise, the scene only includes the fluctuations (in microKelvin) and the operator is linear (i.e. the output also corresponds to power fluctuations). Parameter --------- nu : float The frequency, at which the conversion is performed [Hz]. Example ------- > scene = SceneHealpixCMB(256, absolute=False) > op = scene.get_unit_conversion_operator(150e9) > dT = 200 # µK > print(op(dT)) # W / m^2 / Hz / pixel 1.2734621598076659e-26 > scene = SceneHealpixCMB(256, absolute=True) > op = scene.get_unit_conversion_operator(150e9) > T = 2.7 # K > print(op(T)) # W / m^2 / Hz / pixel 5.94046610468e-23 """ a = 2 * self.solid_angle * h * nu**3 / c**2 if self.absolute: hnu_k = h * nu / k return a / asoperator(np.expm1)(hnu_k * ReciprocalOperator()) T = self.temperature hnu_kT = h * nu / (k * T) val = 1e-6 * a * hnu_kT * np.exp(hnu_kT) / (np.expm1(hnu_kT)**2 * T) return asoperator(val)
def cg(A, b, x0=None, tol=1.e-5, maxiter=300, M=None, disp=False, callback=None): """ OpenMPI/MPI hybrid conjugate gradient solver with preconditioning. """ A = asoperator(A) comm = A.commin or MPI.COMM_WORLD if M is None: M = IdentityOperator() M = asoperator(M) maxRelError = tol**2 shape = b.shape x = np.empty(shape) d = np.empty(shape) q = np.empty(shape) r = np.empty(shape) s = np.empty(shape) xfinal = np.zeros(shape) if x0 is None: x[...] = 0 else: x[...] = x0 norm = norm2(b, comm=comm) if norm == 0: return xfinal, 0 r[...] = b r -= A(x) epsilon = norm2(r, comm=comm) / norm minEpsilon = epsilon M(r, d) delta0 = dot(r, d, comm=comm) deltaNew = delta0 for iter_ in xrange(maxiter): if epsilon <= maxRelError: break A(d, q) alpha = deltaNew / dot(d, q, comm=comm) x += alpha * d r -= alpha * q epsilon = norm2(r, comm=comm) / norm if disp: print '{0:4}: {1}'.format(iter_ + 1, np.sqrt(epsilon)) if callback is not None: resid = np.sqrt(epsilon) callback(x) if epsilon < minEpsilon: xfinal[...] = x minEpsilon = epsilon M(r, s) deltaOld = deltaNew deltaNew = dot(r, s, comm=comm) beta = deltaNew / deltaOld d *= beta d += s minEpsilon = np.sqrt(minEpsilon) maxRelError = np.sqrt(maxRelError) return xfinal.reshape(b.shape), int(minEpsilon > maxRelError)
def _tod2map(acq, tod, coverage_threshold, max_nbytes, callback, disp_pcg, maxiter, tol, criterion, full_output, save_map, hyper): # coverage normalization: # sum coverage = #detectors x #samplings for a uniform secondary beam H = acq.get_operator() coverage = H.T(ones(H.shapeout)) if acq.scene.kind == 'IQU': coverage = coverage[..., 0] elif acq.scene.kind == 'QU': raise NotImplementedError() theta, phi = acq.instrument.detector.theta, acq.instrument.detector.phi ndetectors = acq.instrument.detector.comm.allreduce( np.sum(acq.instrument.secondary_beam(theta, phi))) nsamplings = acq.sampling.comm.allreduce(len(acq.sampling)) coverage *= ndetectors * nsamplings / np.sum(coverage) cov = coverage[coverage > 0] i = np.argsort(cov) cdf = np.cumsum(cov[i]) j = np.argmax(cdf >= coverage_threshold * cdf[-1]) threshold = cov[i[j]] mask = coverage >= threshold rejected = 1 - np.sum(mask) / cov.size if acq.comm.rank == 0 and coverage_threshold > 0: print('Total coverage:', cdf[-1]) print('Threshold coverage set to:', threshold) print('Fraction of rejected observed pixels:', rejected) header = OrderedDict() coverage = coverage.view(ndarraywrap) coverage.header = header header['thresrel'] = coverage_threshold, 'Relative coverage threshold' header['thresabs'] = threshold, 'Absolute coverage threshold' header['fracrej'] = rejected, 'Fraction of rejected observed pixels' acq_restricted = acq[..., mask] H = acq_restricted.get_operator() invNtt = acq_restricted.get_invntt_operator() M = (H.T * H * np.ones(H.shapein))[..., 0] preconditioner = DiagonalOperator(1 / M, broadcast='rightward') # preconditioner = DiagonalOperator(1/coverage[mask], broadcast='rightward') nsamplings = acq.comm.allreduce(len(acq.sampling)) npixels = np.sum(mask) A = H.T * invNtt * H / nsamplings if hyper != 0: L = HealpixLaplacianOperator(acq.scene.nside) L = L.restrict(mask, inplace=True).corestrict(mask, inplace=True) A = A - hyper / npixels / 4e5 * L if criterion: def f(x): Hx_y = H(x) Hx_y -= tod out = [np.dot(Hx_y.ravel(), invNtt(Hx_y).ravel()) / nsamplings] if hyper != 0: out += [ -np.dot(x.ravel(), hyper / npixels / 4e5 * L(x).ravel()) ] else: out += [0.] return out def callback(self): criteria = f(self.x) if len(criteria) == 1: details = '' else: fmt = ', '.join(len(criteria) * ['{:e}']) details = ' (' + fmt.format(*criteria) + ')' print('{:4}: {:e} {:e}{}'.format(self.niterations, self.error, sum(criteria), details)) if not hasattr(self, 'history'): self.history = {} self.history['criterion'] = [] self.history['error'] = [] self.history['iteration'] = [] self.history['criterion'].append(criteria) self.history['error'].append(self.error) self.history['iteration'].append(self.niterations) if save_map is not None and self.niterations in save_map: if not hasattr(self, 'xs'): self.xs = {} self.xs[self.niterations] = self.x.copy() solution = pcg(A, H.T(invNtt(tod)) / nsamplings, M=preconditioner, callback=callback, disp=disp_pcg, maxiter=maxiter, tol=tol) output = acq_restricted.scene.unpack(solution['x']), coverage if full_output: algo = solution['algorithm'] algo.H = H if criterion: pack = PackOperator(mask, broadcast='rightward') algo.f = asoperator(f, shapeout=2)(pack) output += (algo, ) return output
def cg(A, b, x0=None, tol=1.e-5, maxiter=300, M=None, disp=False, callback=None): """ OpenMPI/MPI hybrid conjugate gradient solver with preconditioning. """ A = asoperator(A) comm = A.commin or MPI.COMM_WORLD if M is None: M = IdentityOperator() M = asoperator(M) maxRelError = tol**2 shape = b.shape x = np.empty(shape) d = np.empty(shape) q = np.empty(shape) r = np.empty(shape) s = np.empty(shape) xfinal = np.zeros(shape) if x0 is None: x[...] = 0 else: x[...] = x0 norm = norm2(b, comm=comm) if norm == 0: return xfinal, 0 r[...] = b r -= A(x) epsilon = norm2(r, comm=comm) / norm minEpsilon = epsilon M(r, d) delta0 = dot(r, d, comm=comm) deltaNew = delta0 for iter_ in xrange(maxiter): if epsilon <= maxRelError: break A(d, q) alpha = deltaNew / dot(d, q, comm=comm) x += alpha * d r -= alpha * q epsilon = norm2(r, comm=comm) / norm if disp: print '{0:4}: {1}'.format(iter_ + 1, np.sqrt(epsilon)) if callback is not None: resid = np.sqrt(epsilon) callback(x) if epsilon < minEpsilon: xfinal[...] = x minEpsilon = epsilon M(r, s) deltaOld = deltaNew deltaNew = dot(r, s, comm=comm) beta = deltaNew / deltaOld d *= beta d += s minEpsilon = np.sqrt(minEpsilon) maxRelError = np.sqrt(maxRelError) return xfinal.reshape(b.shape), int(minEpsilon > maxRelError)
def _tod2map(acq, tod, coverage_threshold, max_nbytes, callback, disp_pcg, maxiter, tol, criterion, full_output, save_map, hyper): # coverage normalization: # sum coverage = #detectors x #samplings for a uniform secondary beam H = acq.get_operator() coverage = H.T(ones(H.shapeout)) if acq.scene.kind == 'IQU': coverage = coverage[..., 0] elif acq.scene.kind == 'QU': raise NotImplementedError() theta, phi = acq.instrument.detector.theta, acq.instrument.detector.phi ndetectors = acq.instrument.detector.comm.allreduce( np.sum(acq.instrument.secondary_beam(theta, phi))) nsamplings = acq.sampling.comm.allreduce(len(acq.sampling)) coverage *= ndetectors * nsamplings / np.sum(coverage) cov = coverage[coverage > 0] i = np.argsort(cov) cdf = np.cumsum(cov[i]) j = np.argmax(cdf >= coverage_threshold * cdf[-1]) threshold = cov[i[j]] mask = coverage >= threshold rejected = 1 - np.sum(mask) / cov.size if acq.comm.rank == 0 and coverage_threshold > 0: print('Total coverage:', cdf[-1]) print('Threshold coverage set to:', threshold) print('Fraction of rejected observed pixels:', rejected) header = OrderedDict() coverage = coverage.view(ndarraywrap) coverage.header = header header['thresrel'] = coverage_threshold, 'Relative coverage threshold' header['thresabs'] = threshold, 'Absolute coverage threshold' header['fracrej'] = rejected, 'Fraction of rejected observed pixels' acq_restricted = acq[..., mask] H = acq_restricted.get_operator() invNtt = acq_restricted.get_invntt_operator() M = (H.T * H * np.ones(H.shapein))[..., 0] preconditioner = DiagonalOperator(1/M, broadcast='rightward') # preconditioner = DiagonalOperator(1/coverage[mask], broadcast='rightward') nsamplings = acq.comm.allreduce(len(acq.sampling)) npixels = np.sum(mask) A = H.T * invNtt * H / nsamplings if hyper != 0: L = HealpixLaplacianOperator(acq.scene.nside) L = L.restrict(mask, inplace=True).corestrict(mask, inplace=True) A = A - hyper / npixels / 4e5 * L if criterion: def f(x): Hx_y = H(x) Hx_y -= tod out = [np.dot(Hx_y.ravel(), invNtt(Hx_y).ravel()) / nsamplings] if hyper != 0: out += [-np.dot(x.ravel(), hyper / npixels / 4e5 * L(x).ravel())] else: out += [0.] return out def callback(self): criteria = f(self.x) if len(criteria) == 1: details = '' else: fmt = ', '.join(len(criteria) * ['{:e}']) details = ' (' + fmt.format(*criteria) + ')' print('{:4}: {:e} {:e}{}'.format(self.niterations, self.error, sum(criteria), details)) if not hasattr(self, 'history'): self.history = {} self.history['criterion'] = [] self.history['error'] = [] self.history['iteration'] = [] self.history['criterion'].append(criteria) self.history['error'].append(self.error) self.history['iteration'].append(self.niterations) if save_map is not None and self.niterations in save_map: if not hasattr(self, 'xs'): self.xs = {} self.xs[self.niterations] = self.x.copy() solution = pcg(A, H.T(invNtt(tod)) / nsamplings, M=preconditioner, callback=callback, disp=disp_pcg, maxiter=maxiter, tol=tol) output = acq_restricted.scene.unpack(solution['x']), coverage if full_output: algo = solution['algorithm'] algo.H = H if criterion: pack = PackOperator(mask, broadcast='rightward') algo.f = asoperator(f, shapeout=2)(pack) output += (algo,) return output