use std::{
collections::BTreeMap,
f64::consts::PI,
fs::File,
io::{stdin, BufRead, BufReader, BufWriter, Error as IoError, Write},
iter::{Enumerate, Map},
marker::PhantomData,
ops::{Add, AddAssign, Deref},
path::Path,
slice::Iter,
vec::IntoIter,
};
use itertools::Itertools;
use rayon::{
prelude::{
IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator,
IntoParallelRefMutIterator, ParallelIterator, ParallelSlice, ParallelSliceMut,
},
ThreadPool,
};
use super::{DegradableBySumming, SkyMap, SkyMapValue};
use crate::{
n_hash,
nested::{
get,
map::{
fits::{error::FitsError, write::write_implicit_skymap_fits},
mom::{
impls::zvec::MomVecImpl, new_chi2_count_ref_merger_no_depth_threshold,
new_chi2_count_ref_merger_with_depth_threshold,
new_chi2_density_ref_merger_no_depth_threshold,
new_chi2_density_ref_merger_with_depth_threshold, Mom, ZUniqHashT,
},
skymap::explicit::{ExplicitCountMap, ExplicitSkyMapBTree},
HHash,
},
sort::get_hpx_opt,
},
};
#[derive(Debug)]
pub struct ImplicitSkyMapArray<H: HHash, V: SkyMapValue> {
pub depth: u8,
pub values: Box<[V]>,
_htype: PhantomData<H>,
}
impl<V: SkyMapValue> From<ImplicitSkyMapArray<u32, V>> for ImplicitSkyMapArray<u64, V> {
fn from(value: ImplicitSkyMapArray<u32, V>) -> Self {
Self::new(value.depth, value.values)
}
}
impl<H: HHash, V: SkyMapValue> ImplicitSkyMapArray<H, V> {
pub fn new(depth: u8, values: Box<[V]>) -> Self {
assert_eq!(
n_hash(depth) as usize,
values.deref().len(),
"Wrong implicit skymap size. Expected: {}. Actual: {}.",
n_hash(depth),
values.len()
);
Self {
depth,
values,
_htype: PhantomData,
}
}
pub fn into_explicit_map(self, null_value: V) -> ExplicitSkyMapBTree<H, V> {
let depth = self.depth;
let btreemap: BTreeMap<H, V> = self
.owned_entries()
.filter(move |(_k, v)| null_value.ne(v))
.collect();
ExplicitSkyMapBTree::new(depth, btreemap)
}
}
impl<H: HHash, V: SkyMapValue + Send + Sync + AddAssign> ImplicitSkyMapArray<H, V> {
pub fn par_add(mut self, rhs: Self) -> Self {
self
.values
.as_parallel_slice_mut()
.par_iter_mut()
.zip_eq(rhs.values.into_vec().into_par_iter())
.for_each(|(l, r)| l.add_assign(r));
self
}
}
impl<'a, H: HHash, V: SkyMapValue + 'a> SkyMap<'a> for ImplicitSkyMapArray<H, V> {
type HashType = H;
type ValueType = V;
type ValuesIt = Iter<'a, Self::ValueType>;
type EntriesIt = Map<Enumerate<Self::ValuesIt>, fn((usize, &V)) -> (H, &V)>;
type OwnedEntriesIt = Map<Enumerate<IntoIter<Self::ValueType>>, fn((usize, V)) -> (H, V)>;
fn depth(&self) -> u8 {
self.depth
}
fn is_implicit(&self) -> bool {
true
}
fn len(&self) -> usize {
self.values.len()
}
fn get(&self, hash: Self::HashType) -> &Self::ValueType {
&self.values.deref()[hash.as_()]
}
fn values(&'a self) -> Self::ValuesIt {
self.values.deref().iter()
}
fn entries(&'a self) -> Self::EntriesIt {
self
.values
.deref()
.iter()
.enumerate()
.map(move |(h, v)| (H::from_usize(h), v))
}
fn owned_entries(self) -> Self::OwnedEntriesIt {
Box::into_iter(self.values)
.enumerate()
.map(move |(h, v)| (H::from_usize(h), v))
}
}
impl<H: HHash, V: SkyMapValue + Send + Sync + Add> DegradableBySumming
for ImplicitSkyMapArray<H, V>
{
type Degraded = Self;
fn degrade_sum(self, new_depth: u8) -> Self::Degraded {
if new_depth >= self.depth {
self
} else {
let twice_dd = (self.depth - new_depth) << 1;
let values = self
.values
.chunks_exact(1 << twice_dd)
.map(|chunk| {
chunk
.iter()
.cloned()
.reduce(|acc, e| acc + e)
.unwrap_or(V::zero())
})
.collect::<Vec<V>>()
.into_boxed_slice();
assert_eq!(values.len(), n_hash(new_depth) as usize);
Self::new(new_depth, values)
}
}
}
#[derive(Debug)]
pub struct ImplicitSkyMapArrayRef<'a, H: HHash, V: SkyMapValue> {
depth: u8,
values: &'a [V],
_htype: PhantomData<H>,
}
impl<'a, H: HHash, V: SkyMapValue + 'a> ImplicitSkyMapArrayRef<'a, H, V> {
pub fn new(depth: u8, values: &'a [V]) -> Self {
assert_eq!(
n_hash(depth) as usize,
values.len(),
"Wrong implicit skymap size. Epecgted: {}. Actual: {}.",
n_hash(depth),
values.len()
);
Self {
depth,
values,
_htype: PhantomData,
}
}
pub fn into_explicit_map(self, null_value: V) -> ExplicitSkyMapBTree<H, V> {
let depth = self.depth;
let btreemap: BTreeMap<H, V> = self
.owned_entries()
.filter(move |(_k, v)| null_value.ne(v))
.collect();
ExplicitSkyMapBTree::new(depth, btreemap)
}
}
impl<'a, H: HHash, V: SkyMapValue + Clone + 'a> SkyMap<'a> for ImplicitSkyMapArrayRef<'a, H, V> {
type HashType = H;
type ValueType = V;
type ValuesIt = Iter<'a, Self::ValueType>;
type EntriesIt = Map<Enumerate<Self::ValuesIt>, fn((usize, &V)) -> (H, &V)>;
type OwnedEntriesIt = Map<Enumerate<Self::ValuesIt>, fn((usize, &V)) -> (H, V)>;
fn depth(&self) -> u8 {
self.depth
}
fn is_implicit(&self) -> bool {
true
}
fn len(&self) -> usize {
self.values.len()
}
fn get(&self, hash: Self::HashType) -> &Self::ValueType {
&self.values[hash.as_()]
}
fn values(&'a self) -> Self::ValuesIt {
self.values.iter()
}
fn entries(&'a self) -> Self::EntriesIt {
self
.values
.iter()
.enumerate()
.map(move |(h, v)| (H::from_usize(h), v))
}
fn owned_entries(self) -> Self::OwnedEntriesIt {
self
.values
.iter()
.enumerate()
.map(move |(h, v)| (H::from_usize(h), v.clone()))
}
}
#[derive(Debug)]
pub struct ImplicitCountMap(ImplicitSkyMapArray<u64, u32>);
impl From<ImplicitSkyMapArray<u64, u32>> for ImplicitCountMap {
fn from(value: ImplicitSkyMapArray<u64, u32>) -> Self {
Self(value)
}
}
impl ImplicitCountMap {
pub fn as_implicit_skymap_array(&self) -> &ImplicitSkyMapArray<u64, u32> {
&self.0
}
pub fn into_implicit_skymap_array(self) -> ImplicitSkyMapArray<u64, u32> {
self.0
}
pub fn into_explicit_skymap(self, null_value: u32) -> ExplicitCountMap<u64> {
self.0.into_explicit_map(null_value).into()
}
pub fn from_hash_values<I>(depth: u8, hash_values_it: I) -> Self
where
I: Iterator<Item = u32>,
{
assert!(
depth < 13,
"Wrong count map input depth. Expected: < 13. Actual: {}",
depth
);
let mut counts = vec![0_u32; n_hash(depth) as usize].into_boxed_slice();
for h in hash_values_it {
counts[h as usize] += 1;
}
Self(ImplicitSkyMapArray::new(depth, counts))
}
pub fn from_positions<I>(depth: u8, pos_it_rad: I) -> Self
where
I: Iterator<Item = (f64, f64)>,
{
let layer = get(depth);
Self::from_hash_values(depth, pos_it_rad.map(|(l, b)| layer.hash(l, b) as u32))
}
pub fn par_add(mut self, rhs: Self) -> Self {
self.0 = self.0.par_add(rhs.0);
self
}
pub fn to_dens_map(&self) -> ImplicitDensityMap {
let depth = self.depth();
let on_over_area = (n_hash(depth) >> 2) as f64 / PI;
ImplicitDensityMap(ImplicitSkyMapArray::new(
depth,
self
.0
.values
.iter()
.map(|count| *count as f64 * on_over_area)
.collect::<Vec<f64>>()
.into_boxed_slice(),
))
}
pub fn to_dens_map_par(&self) -> ImplicitDensityMap {
let depth = self.depth();
let on_over_area = (n_hash(depth) >> 2) as f64 / PI;
ImplicitDensityMap(ImplicitSkyMapArray::new(
depth,
self
.0
.values
.par_iter()
.map(|count| *count as f64 * on_over_area)
.collect::<Vec<f64>>()
.into_boxed_slice(),
))
}
pub fn to_fits<W: Write>(&self, writer: W) -> Result<(), FitsError> {
write_implicit_skymap_fits(writer, self.as_implicit_skymap_array().values.deref())
}
pub fn to_fits_file<P: AsRef<Path>>(&self, path: P) -> Result<(), FitsError> {
File::create(path)
.map_err(FitsError::Io)
.and_then(|file| self.to_fits(BufWriter::new(file)))
}
pub fn to_upper_count_threshold_mom(&self, upper_count_threshold: u32) -> MomVecImpl<u64, u32> {
let merger = |_depth: u8, _hash: u64, [n0, n1, n2, n3]: [&u32; 4]| -> Option<u32> {
let sum = *n0 + *n1 + *n2 + *n3;
if sum < upper_count_threshold {
Some(sum)
} else {
None
}
};
MomVecImpl::from_skymap_ref(&self.0, merger)
}
pub fn to_chi2_count_mom(
&self,
chi2_of_3dof_threshold: f64,
depth_threshold: Option<u8>,
) -> MomVecImpl<u64, u32> {
match depth_threshold {
None => MomVecImpl::from_skymap_ref(
&self.0,
new_chi2_count_ref_merger_no_depth_threshold(chi2_of_3dof_threshold),
),
Some(depth_threshold) => MomVecImpl::from_skymap_ref(
&self.0,
new_chi2_count_ref_merger_with_depth_threshold(chi2_of_3dof_threshold, depth_threshold),
),
}
}
pub fn to_chi2_dens_mom(
&self,
chi2_of_3dof_threshold: f64,
depth_threshold: Option<u8>,
) -> MomVecImpl<u64, f64> {
let mom = self.to_chi2_count_mom(chi2_of_3dof_threshold, depth_threshold);
MomVecImpl::from_map(mom, |z, v| {
v as f64 / (4.0 * PI / (n_hash(u64::depth_from_zuniq(z))) as f64)
})
}
}
impl Add for ImplicitCountMap {
type Output = Self;
fn add(mut self, rhs: Self) -> Self::Output {
self
.0
.values
.iter_mut()
.zip_eq(rhs.0.values.iter())
.for_each(|(l, r)| *l += r);
self
}
}
impl<'a> SkyMap<'a> for ImplicitCountMap {
type HashType = u64;
type ValueType = u32;
type ValuesIt = Iter<'a, Self::ValueType>;
type EntriesIt = Map<Enumerate<Self::ValuesIt>, fn((usize, &u32)) -> (u64, &u32)>;
type OwnedEntriesIt = Map<Enumerate<IntoIter<Self::ValueType>>, fn((usize, u32)) -> (u64, u32)>;
fn depth(&self) -> u8 {
self.as_implicit_skymap_array().depth
}
fn is_implicit(&self) -> bool {
true
}
fn len(&self) -> usize {
self.as_implicit_skymap_array().values.len()
}
fn get(&self, hash: Self::HashType) -> &Self::ValueType {
&self.as_implicit_skymap_array().values.deref()[hash as usize]
}
fn values(&'a self) -> Self::ValuesIt {
self.as_implicit_skymap_array().values.deref().iter()
}
fn entries(&'a self) -> Self::EntriesIt {
self
.as_implicit_skymap_array()
.values
.deref()
.iter()
.enumerate()
.map(move |(h, v)| (u64::from_usize(h), v))
}
fn owned_entries(self) -> Self::OwnedEntriesIt {
Box::into_iter(self.into_implicit_skymap_array().values)
.enumerate()
.map(move |(h, v)| (u64::from_usize(h), v))
}
}
#[derive(Debug)]
pub struct ImplicitCountMapU32(ImplicitSkyMapArray<u32, u32>);
impl From<ImplicitSkyMapArray<u32, u32>> for ImplicitCountMapU32 {
fn from(value: ImplicitSkyMapArray<u32, u32>) -> Self {
Self(value)
}
}
impl ImplicitCountMapU32 {
pub fn as_implicit_skymap_array(&self) -> &ImplicitSkyMapArray<u32, u32> {
&self.0
}
pub fn into_implicit_skymap_array(self) -> ImplicitSkyMapArray<u32, u32> {
self.0
}
pub fn into_explicit_skymap(self, null_value: u32) -> ExplicitCountMap<u32> {
self.0.into_explicit_map(null_value).into()
}
pub fn from_hash_values<I>(depth: u8, hash_values_it: I) -> Self
where
I: Iterator<Item = u32>,
{
assert!(
depth < 13,
"Wrong count map input depth. Expected: < 13. Actual: {}",
depth
);
let mut counts = vec![0_u32; n_hash(depth) as usize].into_boxed_slice();
for h in hash_values_it {
counts[h as usize] += 1;
}
Self(ImplicitSkyMapArray::new(depth, counts))
}
pub fn from_positions<I>(depth: u8, pos_it_rad: I) -> Self
where
I: Iterator<Item = (f64, f64)>,
{
assert!(
depth < 13,
"Wrong count map input depth. Expected: < 13. Actual: {}",
depth
);
let layer = get(depth);
let mut counts = vec![0_u32; layer.n_hash as usize].into_boxed_slice();
for (l, b) in pos_it_rad {
counts[layer.hash(l, b) as usize] += 1;
}
Self(ImplicitSkyMapArray::new(depth, counts))
}
pub fn from_csv_stdin_par(
ilon: usize,
ilat: usize,
separator: Option<char>,
has_header: bool,
depth: u8,
chunk_size: usize,
thread_pool: &ThreadPool,
) -> Result<Self, IoError> {
Self::from_csv_gen_par(
BufReader::new(stdin()),
ilon,
ilat,
separator,
has_header,
depth,
chunk_size,
thread_pool,
)
}
pub fn from_csv_file_par<P: AsRef<Path>>(
path: P,
ilon: usize,
ilat: usize,
separator: Option<char>,
has_header: bool,
depth: u8,
chunk_size: usize,
thread_pool: &ThreadPool,
) -> Result<Self, IoError> {
Self::from_csv_gen_par(
BufReader::new(File::open(&path)?),
ilon,
ilat,
separator,
has_header,
depth,
chunk_size,
thread_pool,
)
}
pub fn from_csv_gen_par<R: BufRead + Send>(
bufr: R,
ilon: usize,
ilat: usize,
separator: Option<char>,
has_header: bool,
depth: u8,
chunk_size: usize,
thread_pool: &ThreadPool,
) -> Result<Self, IoError> {
let mut it = bufr.lines().peekable();
while let Some(Ok(_)) = it.next_if(|res| {
res
.as_ref()
.map(|line| line.starts_with('#'))
.unwrap_or(false)
}) {}
if has_header {
it.next().transpose()?;
}
Self::from_csv_it_par(it, ilon, ilat, separator, depth, chunk_size, thread_pool)
}
pub fn from_csv_it_par<I>(
mut it: I,
ilon: usize,
ilat: usize,
separator: Option<char>,
depth: u8,
chunk_size: usize,
thread_pool: &ThreadPool,
) -> Result<Self, IoError>
where
I: Iterator<Item = Result<String, IoError>> + Send,
{
let separator = separator.unwrap_or(',');
let layer = get(depth);
let n_hash = layer.n_hash as usize;
let n_thread = thread_pool.current_num_threads();
let hpx = get_hpx_opt(ilon, ilat, separator, layer);
let count_map_fn = |chunk: Vec<String>| {
chunk
.par_chunks((chunk.len() / (n_thread << 2)).max(10_000))
.map(|elems| {
ImplicitCountMapU32::from_hash_values(
depth,
elems.iter().filter_map(&hpx).map(|h| h as u32),
)
})
.reduce_with(|mapl, mapr| mapl.par_add(mapr))
};
fn load_n<I: Iterator<Item = Result<String, IoError>>>(
chunk_size: usize,
it: &mut I,
) -> Result<Vec<String>, IoError> {
it.take(chunk_size).collect()
}
let mut chunk = load_n(chunk_size, it.by_ref())?;
let mut count_map = Self(ImplicitSkyMapArray::new(
depth,
vec![0_u32; n_hash].into_boxed_slice(),
));
while !chunk.is_empty() {
let (next_chunk, new_count_map) = thread_pool.join(
|| load_n(chunk_size, it.by_ref()),
|| {
if let Some(local_count_map) = count_map_fn(chunk) {
count_map.par_add(local_count_map)
} else {
count_map
}
},
);
chunk = next_chunk?;
count_map = new_count_map;
}
Ok(count_map)
}
pub fn par_add(mut self, rhs: Self) -> Self {
self.0 = self.0.par_add(rhs.0);
self
}
pub fn to_fits<W: Write>(&self, writer: W) -> Result<(), FitsError> {
write_implicit_skymap_fits(writer, self.as_implicit_skymap_array().values.deref())
}
pub fn to_fits_file<P: AsRef<Path>>(&self, path: P) -> Result<(), FitsError> {
File::create(&path)
.map_err(|err| FitsError::IoWithPath {
path: path.as_ref().to_string_lossy().into(),
err,
})
.and_then(|file| self.to_fits(BufWriter::new(file)))
}
pub fn to_dens_map(&self) -> ImplicitDensityMapU32 {
let depth = self.depth();
let one_over_area = (n_hash(depth) >> 2) as f64 / PI;
ImplicitDensityMapU32(ImplicitSkyMapArray::new(
depth,
self
.0
.values
.iter()
.map(|count| *count as f64 * one_over_area)
.collect::<Vec<f64>>()
.into_boxed_slice(),
))
}
pub fn to_dens_map_par(&self) -> ImplicitDensityMapU32 {
let depth = self.depth();
let one_over_area = (n_hash(depth) >> 2) as f64 / PI;
ImplicitDensityMapU32(ImplicitSkyMapArray::new(
depth,
self
.0
.values
.par_iter()
.map(|count| *count as f64 * one_over_area)
.collect::<Vec<f64>>()
.into_boxed_slice(),
))
}
pub fn to_upper_count_threshold_mom(&self, upper_count_threshold: u32) -> MomVecImpl<u32, u32> {
let merger = |_depth: u8, _hash: u32, [n0, n1, n2, n3]: [&u32; 4]| -> Option<u32> {
let sum = *n0 + *n1 + *n2 + *n3;
if sum < upper_count_threshold {
Some(sum)
} else {
None
}
};
MomVecImpl::from_skymap_ref(&self.0, merger)
}
pub fn to_chi2_count_mom(
&self,
chi2_of_3dof_threshold: f64,
depth_threshold: Option<u8>,
) -> MomVecImpl<u32, u32> {
match depth_threshold {
None => MomVecImpl::from_skymap_ref(
&self.0,
new_chi2_count_ref_merger_no_depth_threshold(chi2_of_3dof_threshold),
),
Some(depth_threshold) => MomVecImpl::from_skymap_ref(
&self.0,
new_chi2_count_ref_merger_with_depth_threshold(chi2_of_3dof_threshold, depth_threshold),
),
}
}
pub fn to_chi2_dens_mom(
&self,
chi2_of_3dof_threshold: f64,
depth_threshold: Option<u8>,
) -> MomVecImpl<u32, f64> {
let mom = self.to_chi2_count_mom(chi2_of_3dof_threshold, depth_threshold);
MomVecImpl::from_map(mom, |z, v| {
v as f64 / (4.0 * PI / (n_hash(u32::depth_from_zuniq(z))) as f64)
})
}
}
impl Add for ImplicitCountMapU32 {
type Output = Self;
fn add(mut self, rhs: Self) -> Self::Output {
self
.0
.values
.iter_mut()
.zip_eq(rhs.0.values.iter())
.for_each(|(l, r)| *l += r);
self
}
}
impl<'a> SkyMap<'a> for ImplicitCountMapU32 {
type HashType = u32;
type ValueType = u32;
type ValuesIt = Iter<'a, Self::ValueType>;
type EntriesIt = Map<Enumerate<Self::ValuesIt>, fn((usize, &u32)) -> (u32, &u32)>;
type OwnedEntriesIt = Map<Enumerate<IntoIter<Self::ValueType>>, fn((usize, u32)) -> (u32, u32)>;
fn depth(&self) -> u8 {
self.as_implicit_skymap_array().depth
}
fn is_implicit(&self) -> bool {
true
}
fn len(&self) -> usize {
self.as_implicit_skymap_array().values.len()
}
fn get(&self, hash: Self::HashType) -> &Self::ValueType {
&self.as_implicit_skymap_array().values.deref()[hash as usize]
}
fn values(&'a self) -> Self::ValuesIt {
self.as_implicit_skymap_array().values.deref().iter()
}
fn entries(&'a self) -> Self::EntriesIt {
self
.as_implicit_skymap_array()
.values
.deref()
.iter()
.enumerate()
.map(move |(h, v)| (u32::from_usize(h), v))
}
fn owned_entries(self) -> Self::OwnedEntriesIt {
Box::into_iter(self.into_implicit_skymap_array().values) .enumerate()
.map(move |(h, v)| (u32::from_usize(h), v))
}
}
#[derive(Debug)]
pub struct ImplicitDensityMap(ImplicitSkyMapArray<u64, f64>);
impl From<ImplicitSkyMapArray<u64, f64>> for ImplicitDensityMap {
fn from(value: ImplicitSkyMapArray<u64, f64>) -> Self {
Self(value)
}
}
impl ImplicitDensityMap {
pub fn as_implicit_skymap_array(&self) -> &ImplicitSkyMapArray<u64, f64> {
&self.0
}
pub fn into_implicit_skymap_array(self) -> ImplicitSkyMapArray<u64, f64> {
self.0
}
pub fn from_positions<I>(depth: u8, pos_it_rad: I) -> Self
where
I: Iterator<Item = (f64, f64)>,
{
assert!(
depth < 13,
"Wrong count map input depth. Expected: < 13. Actual: {}",
depth
);
let layer = get(depth);
let mut densities = vec![0_f64; layer.n_hash as usize].into_boxed_slice();
let one_over_cell_area = layer.n_hash as f64 / (4.0 * PI);
for (l, b) in pos_it_rad {
densities[layer.hash(l, b) as usize] += one_over_cell_area;
}
Self(ImplicitSkyMapArray::new(depth, densities))
}
pub fn to_chi2_mom(
&self,
chi2_of_3dof_threshold: f64,
depth_threshold: Option<u8>,
) -> MomVecImpl<u64, f64> {
match depth_threshold {
None => MomVecImpl::from_skymap_ref(
&self.0,
new_chi2_density_ref_merger_no_depth_threshold(chi2_of_3dof_threshold),
),
Some(depth_threshold) => MomVecImpl::from_skymap_ref(
&self.0,
new_chi2_density_ref_merger_with_depth_threshold(chi2_of_3dof_threshold, depth_threshold),
),
}
}
pub fn to_fits<W: Write>(&self, writer: W) -> Result<(), FitsError> {
write_implicit_skymap_fits(writer, self.as_implicit_skymap_array().values.deref())
}
pub fn to_fits_file<P: AsRef<Path>>(&self, path: P) -> Result<(), FitsError> {
File::create(path)
.map_err(FitsError::Io)
.and_then(|file| self.to_fits(BufWriter::new(file)))
}
}
#[derive(Debug)]
pub struct ImplicitDensityMapU32(ImplicitSkyMapArray<u32, f64>);
impl From<ImplicitSkyMapArray<u32, f64>> for ImplicitDensityMapU32 {
fn from(value: ImplicitSkyMapArray<u32, f64>) -> Self {
Self(value)
}
}
impl ImplicitDensityMapU32 {
pub fn as_implicit_skymap_array(&self) -> &ImplicitSkyMapArray<u32, f64> {
&self.0
}
pub fn into_implicit_skymap_array(self) -> ImplicitSkyMapArray<u32, f64> {
self.0
}
pub fn from_positions<I>(depth: u8, pos_it_rad: I) -> Self
where
I: Iterator<Item = (f64, f64)>,
{
assert!(
depth < 13,
"Wrong count map input depth. Expected: < 13. Actual: {}",
depth
);
let layer = get(depth);
let mut densities = vec![0_f64; layer.n_hash as usize].into_boxed_slice();
let one_over_cell_area = layer.n_hash as f64 / (4.0 * PI);
for (l, b) in pos_it_rad {
densities[layer.hash(l, b) as usize] += one_over_cell_area;
}
Self(ImplicitSkyMapArray::new(depth, densities))
}
pub fn to_chi2_mom(
&self,
chi2_of_3dof_threshold: f64,
depth_threshold: Option<u8>,
) -> MomVecImpl<u32, f64> {
match depth_threshold {
None => MomVecImpl::from_skymap_ref(
&self.0,
new_chi2_density_ref_merger_no_depth_threshold(chi2_of_3dof_threshold),
),
Some(depth_threshold) => MomVecImpl::from_skymap_ref(
&self.0,
new_chi2_density_ref_merger_with_depth_threshold(chi2_of_3dof_threshold, depth_threshold),
),
}
}
pub fn to_fits<W: Write>(&self, writer: W) -> Result<(), FitsError> {
write_implicit_skymap_fits(writer, self.as_implicit_skymap_array().values.deref())
}
pub fn to_fits_file<P: AsRef<Path>>(&self, path: P) -> Result<(), FitsError> {
File::create(path)
.map_err(FitsError::Io)
.and_then(|file| self.to_fits(BufWriter::new(file)))
}
}