From 6f87e98d2f4c5bcd378414b777a318e2bb20cc0b Mon Sep 17 00:00:00 2001 From: fxpineau Date: Thu, 10 Nov 2022 09:48:30 +0100 Subject: [PATCH] Add TTYPE1=RANGE in RANGE FITS, add options to save V1.0 FITS compatible S-MOCs --- .github/workflows/deploy.yml | 29 ++++--- .github/workflows/deploy_mac.yml | 36 --------- CHANGELOG.md | 13 +++- crates/cli/CHANGELOG.md | 8 ++ crates/cli/Cargo.toml | 2 +- crates/cli/README.md | 2 - crates/cli/src/from.rs | 1 + crates/cli/src/output.rs | 126 ++++++++++++++++++++++--------- crates/set/CHANGELOG.md | 9 +++ crates/set/Cargo.toml | 2 +- crates/set/README.md | 2 - crates/set/src/extract.rs | 16 +++- crates/wasm/CHANGELOG.md | 10 +++ crates/wasm/Cargo.toml | 16 +++- crates/wasm/README.md | 2 - crates/wasm/src/common.rs | 49 +++++++----- crates/wasm/src/lib.rs | 25 ++++-- crates/wasm/src/store.rs | 1 - src/deser/fits/mod.rs | 6 +- src/moc/mod.rs | 104 ++++++++++++------------- 20 files changed, 275 insertions(+), 184 deletions(-) delete mode 100644 .github/workflows/deploy_mac.yml diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index e8f9f58..4a24a4c 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -27,14 +27,14 @@ jobs: cd crates/set for PYBIN in /opt/python/cp38*/bin; do "${PYBIN}/pip" install maturin - "${PYBIN}/maturin" publish -i "${PYBIN}/python" --skip-existing --compatibility manylinux2014 --username "$MATURIN_USERNAME" - "${PYBIN}/maturin" publish -i "${PYBIN}/python" --skip-existing --compatibility musllinux_1_2 --username "$MATURIN_USERNAME" + "${PYBIN}/maturin" publish -i "${PYBIN}/python" --no-sdist --skip-existing --compatibility manylinux2014 --username "$MATURIN_USERNAME" + "${PYBIN}/maturin" publish -i "${PYBIN}/python" --no-sdist --skip-existing --compatibility musllinux_1_2 --username "$MATURIN_USERNAME" done cd ../cli for PYBIN in /opt/python/cp38*/bin; do "${PYBIN}/pip" install maturin - "${PYBIN}/maturin" publish -i "${PYBIN}/python" --skip-existing --compatibility manylinux2014 --username "$MATURIN_USERNAME" - "${PYBIN}/maturin" publish -i "${PYBIN}/python" --skip-existing --compatibility musllinux_1_2 --username "$MATURIN_USERNAME" + "${PYBIN}/maturin" publish -i "${PYBIN}/python" --no-sdist --skip-existing --compatibility manylinux2014 --username "$MATURIN_USERNAME" + "${PYBIN}/maturin" publish -i "${PYBIN}/python" --no-sdist --skip-existing --compatibility musllinux_1_2 --username "$MATURIN_USERNAME" done @@ -61,19 +61,19 @@ jobs: # cd crates/set # for PYBIN in /opt/python/cp38*/bin; do # "${PYBIN}/pip" install maturin - # "${PYBIN}/maturin" publish -i "${PYBIN}/python" --skip-existing --compatibility manylinux2014 --username "$MATURIN_USERNAME" - # "${PYBIN}/maturin" publish -i "${PYBIN}/python" --skip-existing --compatibility musllinux_1_2 --username "$MATURIN_USERNAME" + # "${PYBIN}/maturin" publish -i "${PYBIN}/python" --no-sdist --skip-existing --compatibility manylinux2014 --username "$MATURIN_USERNAME" + # "${PYBIN}/maturin" publish -i "${PYBIN}/python" --no-sdist --skip-existing --compatibility musllinux_1_2 --username "$MATURIN_USERNAME" # done # cd ../cli # for PYBIN in /opt/python/cp38*/bin; do # "${PYBIN}/pip" install maturin - # "${PYBIN}/maturin" publish -i "${PYBIN}/python" --skip-existing --compatibility manylinux2014 --username "$MATURIN_USERNAME" - # "${PYBIN}/maturin" publish -i "${PYBIN}/python" --skip-existing --compatibility musllinux_1_2 --username "$MATURIN_USERNAME" + # "${PYBIN}/maturin" publish -i "${PYBIN}/python" --no-sdist --skip-existing --compatibility manylinux2014 --username "$MATURIN_USERNAME" + # "${PYBIN}/maturin" publish -i "${PYBIN}/python" --no-sdist --skip-existing --compatibility musllinux_1_2 --username "$MATURIN_USERNAME" # done - # Deploy for Windows and MoxOS 64 bits. + # Deploy for Windows 64 bits. # If Windows 32 bits neede, check e.g. https://github.com/marketplace/actions/setup-msys2 build-windows-wheels: runs-on: ${{ matrix.os }} @@ -99,12 +99,11 @@ jobs: run: | pip install maturin cd crates/set - maturin publish --interpreter python${{matrix.python_version}} --skip-existing --username fxpineau + maturin publish --interpreter python${{matrix.python_version}} --no-sdist --skip-existing --username fxpineau cd ../cli - maturin publish --interpreter python${{matrix.python_version}} --skip-existing --username fxpineau + maturin publish --interpreter python${{matrix.python_version}} --no-sdist --skip-existing --username fxpineau - # Deploy for Windows and MoxOS 64 bits. - # If Windows 32 bits neede, check e.g. https://github.com/marketplace/actions/setup-msys2 + # Deploy for MocOS 64 bits (also support M1 archi). build-macos-wheels: runs-on: ${{ matrix.os }} strategy: @@ -131,8 +130,8 @@ jobs: rustup target add aarch64-apple-darwin pip install maturin cd crates/set - maturin publish --interpreter python${{matrix.python_version}} --universal2 --skip-existing --username "$MATURIN_USERNAME" + maturin publish --interpreter python${{matrix.python_version}} --no-sdist --universal2 --skip-existing --username "$MATURIN_USERNAME" cd ../cli - maturin publish --interpreter python${{matrix.python_version}} --universal2 --skip-existing --username "$MATURIN_USERNAME" + maturin publish --interpreter python${{matrix.python_version}} --no-sdist --universal2 --skip-existing --username "$MATURIN_USERNAME" diff --git a/.github/workflows/deploy_mac.yml b/.github/workflows/deploy_mac.yml deleted file mode 100644 index d02f153..0000000 --- a/.github/workflows/deploy_mac.yml +++ /dev/null @@ -1,36 +0,0 @@ -name: build-wheel-macosi - -on: [push] - -jobs: - # Deploy for Windows and MoxOS 64 bits. - # If Windows 32 bits neede, check e.g. https://github.com/marketplace/actions/setup-msys2 - build-macos-wheels: - runs-on: ${{ matrix.os }} - strategy: - # Run all matrix jobs even if one is failling (default behaviour is to stop all jobs) - # To be changed when option --skip-existing will be available in maturin - fail-fast: false - matrix: - os: [macOS-latest] - python-version: ['3.8'] - steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Build and publish wheel for Python ${{ matrix.python-version }} on ${{ matrix.os }} - # We do not use environement variable for user, because it seems that the way of providing it in the command - # line is not the same for macos and for windows. We should create 2 different actions (see - # https://docs.github.com/en/actions/reference/encrypted-secrets ) - env: - MATURIN_USERNAME: ${{ secrets.PYPI_USERNAME_FXP }} - MATURIN_PASSWORD: ${{ secrets.PYPI_PASSWORD_FXP }} - run: | - rustup target add aarch64-apple-darwin - pip install maturin - cd crates/set - maturin publish -b bin --interpreter python${{matrix.python_version}} --no-sdist --universal2 --skip-existing --username "$MATURIN_USERNAME" - cd ../cli - maturin publish -b bin --interpreter python${{matrix.python_version}} --no-sdist --universal2 --skip-existing --username "$MATURIN_USERNAME" diff --git a/CHANGELOG.md b/CHANGELOG.md index ece2b31..2c51c1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # `moc` Change Log +### x.x.x + +Released XXX-XX-XX + +### Added + +* Add `TTYPE1=RANGE` keyword in FITS files (TTYPE is optional in the FITS standard but without + it astropy seems not to be able to read the file) +* Add the `CellHpxMOCIterator` trait to easily save S-MOC in FITS files compatible with v1.0 + of the MOC standard. + + ## 0.9.0 Released 2022-09-09 @@ -9,7 +21,6 @@ Released 2022-09-09 * Print the deepest order in JSON output even when it contains no cell - ## 0.9.0-alpha Released 2022-06-17 diff --git a/crates/cli/CHANGELOG.md b/crates/cli/CHANGELOG.md index e4ebaae..1a8b714 100644 --- a/crates/cli/CHANGELOG.md +++ b/crates/cli/CHANGELOG.md @@ -1,5 +1,13 @@ # `moc-cli` Change Log +## 0.5.3 + +Realeased 2022-11-10 + +* Add `TTYPE1=RANGE` keyword in FITS files (TTYPE is optional in the FITS standard but without + it astropy seems not to be able to read the file) +* Add option `force_v1` to save a FITS file compatible with v1.0 of the MOC standard (S-MOC only). + ## 0.5.2 diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 6fcb724..9eb6cdf 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moc-cli" -version = "0.5.2" +version = "0.5.3" authors = ["F.-X. Pineau "] description = "Command-line to create and manipulate HEALPix Multi-Order Coverages maps (MOCs)" license = "MIT OR Apache-2.0" diff --git a/crates/cli/README.md b/crates/cli/README.md index 3299e40..ec7eb44 100644 --- a/crates/cli/README.md +++ b/crates/cli/README.md @@ -1,5 +1,3 @@ - - # `moc-cli` A command-line to create and manipulate HEALPix **M**ulti-**O**rder **C**overage maps (**MOC**s), diff --git a/crates/cli/src/from.rs b/crates/cli/src/from.rs index bc926c5..a44c7b4 100644 --- a/crates/cli/src/from.rs +++ b/crates/cli/src/from.rs @@ -1408,6 +1408,7 @@ mod tests { separator: String::from(","), out: OutputFormat::Fits { force_u64: true, + force_v1: false, moc_id: None, moc_type: None, file: PathBuf::from("test/resources/xmmlog.range.stmoc.fits") diff --git a/crates/cli/src/output.rs b/crates/cli/src/output.rs index d4d90ae..2ca513d 100644 --- a/crates/cli/src/output.rs +++ b/crates/cli/src/output.rs @@ -1,28 +1,32 @@ -use std::fs::File; -use std::io::{self, BufWriter}; -use std::str; -use std::path::PathBuf; -use std::error::Error; +use std::{ + str, + fs::File, + error::Error, + path::PathBuf, + io::{self, BufWriter}, +}; + use structopt::StructOpt; -use moclib::idx::Idx; -use moclib::qty::{MocQty, Hpx, Time, Frequency}; -use moclib::deser::fits; -use moclib::moc::{ - RangeMOCIterator, CellMOCIterator, - range::op::convert::{convert_to_u64, convert_from_u64} -}; -use moclib::moc2d::{ - RangeMOC2Iterator, - RangeMOC2ElemIt, - CellMOC2IntoIterator, - CellOrCellRangeMOC2IntoIterator, -}; -use moclib::deser::{ - fits::{ranges_to_fits_ivoa, ranges2d_to_fits_ivoa}, - json::{to_json_aladin, cellmoc2d_to_json_aladin}, - ascii::{to_ascii_ivoa, to_ascii_stream, moc2d_to_ascii_ivoa}, +use moclib::{ + idx::Idx, + qty::{MocQty, Hpx, Time, Frequency}, + moc::{ + RangeMOCIterator, CellMOCIterator, CellHpxMOCIterator, + range::op::convert::{convert_to_u64, convert_from_u64} + }, + moc2d::{ + RangeMOC2Iterator, + RangeMOC2ElemIt, + CellMOC2IntoIterator, + CellOrCellRangeMOC2IntoIterator, + }, + deser::{ + fits::{self, ranges_to_fits_ivoa, ranges2d_to_fits_ivoa}, + json::{to_json_aladin, cellmoc2d_to_json_aladin}, + ascii::{to_ascii_ivoa, to_ascii_stream, moc2d_to_ascii_ivoa}, + } }; #[derive(StructOpt, Clone, Debug)] @@ -54,6 +58,9 @@ pub enum OutputFormat { #[structopt(short = "-f", long = "--force-u64")] /// Force indices to be stored on u64 (ignored after operations involving 2 MOCs) force_u64: bool, + #[structopt(short = "-p", long = "--force-v1")] + /// Force compatibility with MOC v1.0 (i.e. save NUNIQ instead of Ranges; ignored if MOC is not a S-MOC) + force_v1: bool, #[structopt(short="-i", long = "--moc-id")] /// MOC ID to be written in the FITS header moc_id: Option, @@ -86,30 +93,42 @@ impl OutputFormat { matches!(self, OutputFormat::Fits { .. }) } + pub fn is_fits_forced_to_v1_std(&self) -> bool { + matches!(self, OutputFormat::Fits { force_v1: true, .. }) + } + pub fn is_fits_forced_to_u64(&self) -> bool { matches!(self, OutputFormat::Fits { force_u64: true, .. }) } pub fn is_fits_not_forced_to_u64(&self) -> bool { matches!(self, OutputFormat::Fits { force_u64: false, .. }) - } pub fn write_smoc_possibly_auto_converting_from_u64(self, it: I) -> Result<(), Box> where I: RangeMOCIterator> { - if self.is_fits_not_forced_to_u64() { - let depth = it.depth_max(); + let depth = it.depth_max(); + if self.is_fits_not_forced_to_u64() && depth <= Hpx::::MAX_DEPTH { if depth <= Hpx::::MAX_DEPTH { - self.write_moc(convert_from_u64::, u16, Hpx, _>(it)) - } else if depth <= Hpx::::MAX_DEPTH { - self.write_moc(convert_from_u64::, u32, Hpx, _>(it)) + if self.is_fits_forced_to_v1_std() { + self.write_smoc_fits_v1(convert_from_u64::, u16, Hpx, _>(it)) + } else { + self.write_moc(convert_from_u64::, u16, Hpx, _>(it)) + } } else { - self.write_moc(it) + assert!(depth <= Hpx::::MAX_DEPTH); + if self.is_fits_forced_to_v1_std() { + self.write_smoc_fits_v1(convert_from_u64::, u32, Hpx, _>(it)) + } else { + self.write_moc(convert_from_u64::, u32, Hpx, _>(it)) + } } + } else if self.is_fits_forced_to_v1_std() { + self.write_smoc_fits_v1(it) } else { - self.write_moc(it) + self.write_moc(it) } } @@ -118,7 +137,13 @@ impl OutputFormat { I: RangeMOCIterator> { if self.is_fits_forced_to_u64() { - self.write_moc(convert_to_u64::, _, Hpx>(it)) + if self.is_fits_forced_to_v1_std() { + self.write_smoc_fits_v1(convert_to_u64::, _, Hpx>(it)) + } else { + self.write_moc(convert_to_u64::, _, Hpx>(it)) + } + } else if self.is_fits_forced_to_v1_std() { + self.write_smoc_fits_v1(it) } else { self.write_moc(it) } @@ -129,9 +154,15 @@ impl OutputFormat { I: CellMOCIterator> { if self.is_fits_forced_to_u64() { - self.write_moc(convert_to_u64::, _, Hpx>(it.ranges())) + if self.is_fits_forced_to_v1_std() { + self.write_smoc_fits_v1_from_cells(it) + } else { + self.write_moc(convert_to_u64::, _, Hpx>(it.ranges())) + } + } else if self.is_fits_forced_to_v1_std() { + self.write_smoc_fits_v1_from_cells(it) } else { - self.write_moc_from_cells(it) + self.write_moc_from_cells(it) } } @@ -216,7 +247,7 @@ impl OutputFormat { let file = File::create(path)?; to_json_aladin(it.cells(), &fold, "", BufWriter::new(file)).map_err(|e| e.into()) }, - OutputFormat::Fits { force_u64: _, moc_id, moc_type, file } => { + OutputFormat::Fits { force_u64: _, force_v1: _ , moc_id, moc_type, file } => { // Here I don't know how to convert the generic qty MocQty into MocQty... let file = File::create(file)?; ranges_to_fits_ivoa(it, moc_id, moc_type, BufWriter::new(file)).map_err(|e| e.into()) @@ -228,6 +259,29 @@ impl OutputFormat { } } + pub fn write_smoc_fits_v1(self, it: I) -> Result<(), Box> + where + T: Idx, + I: RangeMOCIterator> + { + self.write_smoc_fits_v1_from_cells(it.cells()) + } + + pub fn write_smoc_fits_v1_from_cells(self, it: I) -> Result<(), Box> + where + T: Idx, + I: CellMOCIterator> + { + match self { + OutputFormat::Fits { force_u64: _, force_v1: _, moc_id, moc_type, file } => { + // Here I don't know how to convert the generic qty MocQty into MocQty... + let file = File::create(file)?; + it.hpx_cells_to_fits_ivoa(moc_id, moc_type, BufWriter::new(file)).map_err(|e| e.into()) + }, + _ => unreachable!() + } + } + pub fn write_moc_from_cells(self, it: I) -> Result<(), Box> where T: Idx, @@ -251,7 +305,7 @@ impl OutputFormat { let file = File::create(path)?; to_json_aladin(it, &fold, "", BufWriter::new(file)).map_err(|e| e.into()) }, - OutputFormat::Fits { force_u64: _, moc_id, moc_type, file } => { + OutputFormat::Fits { force_u64: _, force_v1: _, moc_id, moc_type, file } => { // Here I don't know how to convert the generic qty MocQty into MocQty... let file = File::create(file)?; ranges_to_fits_ivoa(it.ranges(), moc_id, moc_type, BufWriter::new(file)).map_err(|e| e.into()) @@ -297,7 +351,7 @@ impl OutputFormat { let file = File::create(path)?; cellmoc2d_to_json_aladin(stmoc.into_cell_moc2_iter(), &fold, BufWriter::new(file)).map_err(|e| e.into()) }, - OutputFormat::Fits { force_u64: _, moc_id, moc_type, file } => { + OutputFormat::Fits { force_u64: _, force_v1: _ , moc_id, moc_type, file } => { // TODO handle the forced to u64?? let file = File::create(file)?; ranges2d_to_fits_ivoa(stmoc, moc_id, moc_type, BufWriter::new(file)).map_err(|e| e.into()) diff --git a/crates/set/CHANGELOG.md b/crates/set/CHANGELOG.md index 118544a..f68a692 100644 --- a/crates/set/CHANGELOG.md +++ b/crates/set/CHANGELOG.md @@ -1,5 +1,14 @@ # `moc-set` Change Log +## 0.5.3 + +Realeased 2022-11-10 + +* Add `TTYPE1=RANGE` keyword in FITS files (TTYPE is optional in the FITS standard but without + it astropy seems not to be able to read the file) +* Add option `force_v1` to extract a FITS file compatible with v1.0 of the MOC standard. + + ## 0.5.2 Released 2022-09-12. diff --git a/crates/set/Cargo.toml b/crates/set/Cargo.toml index fd9a467..30c7ebc 100644 --- a/crates/set/Cargo.toml +++ b/crates/set/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moc-set" -version = "0.5.2" +version = "0.5.3" authors = ["F.-X. Pineau "] description = "command-line tool to build, update and query a persistent set of HEALPix Multi-Order Coverages maps (MOCs)" license = "MIT OR Apache-2.0" diff --git a/crates/set/README.md b/crates/set/README.md index a8d4fbb..9323813 100644 --- a/crates/set/README.md +++ b/crates/set/README.md @@ -1,5 +1,3 @@ - - # moc-set A command-line tool to build, update and query a persistent set of diff --git a/crates/set/src/extract.rs b/crates/set/src/extract.rs index 053246d..43a02d2 100644 --- a/crates/set/src/extract.rs +++ b/crates/set/src/extract.rs @@ -25,6 +25,7 @@ use moclib::{ ascii::to_ascii_ivoa, } }; +use moclib::moc::CellHpxMOCIterator; use crate::{StatusFlag, MocSetFileReader}; @@ -96,6 +97,9 @@ pub enum OutputFormat { #[clap(short = 'f', long = "force-u64")] /// Force indices to be stored on u64 (ignored after operations involving 2 MOCs) force_u64: bool, + #[clap(short = 'p', long = "force-v1")] + /// Force compatibility with MOC v1.0 (i.e. save NUNIQ instead of Ranges; ignored if MOC is not a S-MOC) + force_v1: bool, #[clap(short = 'i', long = "moc-id")] /// MOC ID to be written in the FITS header moc_id: Option, @@ -124,11 +128,10 @@ impl OutputFormat { } } - pub fn write_moc(self, it: I) -> Result<(), Box> + pub fn write_moc(self, it: I) -> Result<(), Box> where T: Idx, - Q: MocQty, - I: RangeMOCIterator + I: RangeMOCIterator> { match self { OutputFormat::Ascii { fold, range_len, opt_file: None } => { @@ -147,10 +150,15 @@ impl OutputFormat { let file = File::create(path)?; to_json_aladin(it.cells(), &fold, "", BufWriter::new(file)).map_err(|e| e.into()) }, - OutputFormat::Fits { force_u64: _, moc_id, moc_type, file } => { + OutputFormat::Fits { force_u64: _, force_v1: false, moc_id, moc_type, file } => { let file = File::create(file)?; let writer = BufWriter::new(file); ranges_to_fits_ivoa(it, moc_id, moc_type, writer).map_err(|e| e.into()) + }, + OutputFormat::Fits { force_u64: _, force_v1: true, moc_id, moc_type, file } => { + let file = File::create(file)?; + let writer = BufWriter::new(file); + it.cells().hpx_cells_to_fits_ivoa(moc_id, moc_type, writer).map_err(|e| e.into()) } } } diff --git a/crates/wasm/CHANGELOG.md b/crates/wasm/CHANGELOG.md index 8670cb3..8477a25 100644 --- a/crates/wasm/CHANGELOG.md +++ b/crates/wasm/CHANGELOG.md @@ -1,5 +1,15 @@ # `moc-wasm` Change Log +## 0.5.3 + +Realeased 2022-11-10 + +* Add `TTYPE1=RANGE` keyword in FITS files (TTYPE is optional in the FITS standard but without + it astropy seems not to be able to read the file) +* Add option in `toFits` functions to generate a FITS file compatible with v1.0 + of the MOC standard (S-MOC only). + + ## 0.5.2 Realeased 2022-09-12 diff --git a/crates/wasm/Cargo.toml b/crates/wasm/Cargo.toml index 39c6472..72c759d 100644 --- a/crates/wasm/Cargo.toml +++ b/crates/wasm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "moc-wasm" -version = "0.5.2" +version = "0.5.3" authors = ["F.-X. Pineau "] description = """ WASM library to create and manipulate HEALPix @@ -60,5 +60,15 @@ features = [ ] # To reduce WASM size, see https://rustwasm.github.io/book/reference/code-size.html -#[profile.release] -#lto = true +[profile.release] +panic = 'unwind' +debug = false +debug-assertions = false +overflow-checks = false +opt-level = 3 +lto = true + + +[package.metadata.wasm-pack.profile.release] +wasm-opt = true + diff --git a/crates/wasm/README.md b/crates/wasm/README.md index c98ed47..068f5fd 100644 --- a/crates/wasm/README.md +++ b/crates/wasm/README.md @@ -1,5 +1,3 @@ - - # `moc-wasm` WebAssembly Library to read/write/create/manipulate HEALPix **M**ulti-**O**rder **C**overage maps (**MOC**s) in a web page. diff --git a/crates/wasm/src/common.rs b/crates/wasm/src/common.rs index 3aba2e2..87fbf9c 100644 --- a/crates/wasm/src/common.rs +++ b/crates/wasm/src/common.rs @@ -6,22 +6,23 @@ use unreachable::UncheckedResultExt; use wasm_bindgen::JsValue; -use moclib::qty::{Hpx, Time, Frequency}; -use moclib::moc::{ - RangeMOCIterator, RangeMOCIntoIterator, - CellMOCIterator, - CellOrCellRangeMOCIterator, - range::RangeMOC +use moclib::{ + qty::{Hpx, Time, Frequency}, + moc::{ + RangeMOCIterator, RangeMOCIntoIterator, CellHpxMOCIterator, + CellMOCIterator, + CellOrCellRangeMOCIterator, + range::RangeMOC + }, + moc2d::{ + HasTwoMaxDepth, + RangeMOC2IntoIterator, + CellMOC2Iterator, CellMOC2IntoIterator, + CellOrCellRangeMOC2Iterator, CellOrCellRangeMOC2IntoIterator, + range::RangeMOC2 + }, + deser::fits::ranges2d_to_fits_ivoa }; -use moclib::moc2d::{ - HasTwoMaxDepth, - RangeMOC2IntoIterator, - CellMOC2Iterator, CellMOC2IntoIterator, - CellOrCellRangeMOC2Iterator, CellOrCellRangeMOC2IntoIterator, - range::RangeMOC2 -}; -use moclib::deser::fits::ranges2d_to_fits_ivoa; - use super::MocQType; @@ -155,7 +156,10 @@ impl InternalMoc { } } - pub(crate) fn to_fits(&self) -> Box<[u8]> { + /// # Params + /// * `force_v1_compatibility`: set to `true` to save a S-MOC using NUNIQ (to be compatible with + /// MOC standard v1). + pub(crate) fn to_fits(&self, force_v1_compatibility: bool) -> Box<[u8]> { let mut buf: Vec = Default::default(); // Uses unsafe [unchecked_unwrap_ok](https://docs.rs/unreachable/1.0.0/unreachable/trait.UncheckedResultExt.html) // for wasm size optimisation. @@ -163,9 +167,16 @@ impl InternalMoc { unsafe { match self { InternalMoc::Space(moc) => - moc.into_range_moc_iter() - .to_fits_ivoa(None, None, &mut buf) - .unchecked_unwrap_ok(), + if force_v1_compatibility { + moc.into_range_moc_iter() + .cells() + .hpx_cells_to_fits_ivoa(None, None, &mut buf) + .unchecked_unwrap_ok() + } else { + moc.into_range_moc_iter() + .to_fits_ivoa(None, None, &mut buf) + .unchecked_unwrap_ok() + }, InternalMoc::Time(moc) => moc.into_range_moc_iter() .to_fits_ivoa(None, None, &mut buf) diff --git a/crates/wasm/src/lib.rs b/crates/wasm/src/lib.rs index 1a85886..08e2abf 100644 --- a/crates/wasm/src/lib.rs +++ b/crates/wasm/src/lib.rs @@ -443,6 +443,7 @@ pub fn from_fits(name: &str, data: &[u8]) -> Result<(), JsValue> { } /// Create o S-MOC from a FITS multi-order map plus other parameters. +/// # Args /// * `from_threshold`: Cumulative value at which we start putting cells in he MOC (often = 0). /// * `to_threshold`: Cumulative value at which we stop putting cells in the MOC. /// * `asc`: Compute cumulative value from ascending density values instead of descending (often = false). @@ -474,6 +475,7 @@ pub fn from_multiordermap_fits_file( } /// Create o S-MOC from a FITS skymap plus other parameters. +/// # Args /// * `skip_values_le`: skip cells associated to values lower or equal to the given value /// * `from_threshold`: Cumulative value at which we start putting cells in he MOC (often = 0). /// * `to_threshold`: Cumulative value at which we stop putting cells in the MOC. @@ -775,6 +777,9 @@ pub async fn stmoc_from_json_url(name: String, url: String) -> Result<(), JsValu // SAVE MOC // // return a string or an array of u8? +/// Returns the ASCII serialization of the given MOC. +/// # Args +/// #[wasm_bindgen(js_name = "toAscii")] pub fn to_ascii(name: &str, fold: Option) -> JsValue { // from_str creates a copy :o/ @@ -789,9 +794,13 @@ pub fn to_json(name: &str, fold: Option) -> JsValue { .unwrap_or(JsValue::NULL) } +/// Returns in memory the FITS serialization of the MOC of given `name`. +/// # Args +/// * `name`: name of the MOC in the internal store +/// * `force_v1_compatibility`: for S-MOCs, force compatibility with Version 1 of the MOC standard. #[wasm_bindgen(js_name = "toFits")] -pub fn to_fits(name: &str) -> Option> { - store::exec(name, move |moc| moc.to_fits()) +pub fn to_fits(name: &str, force_v1_compatibility: Option) -> Option> { + store::exec(name, move |moc| moc.to_fits(force_v1_compatibility.unwrap_or(false))) } #[wasm_bindgen(js_name = "toAsciiFile", catch)] @@ -808,9 +817,13 @@ pub fn to_json_file(name: &str, fold: Option) -> Result<(), JsValue> { to_file(name, ".json", "application/json", data.into_bytes().into_boxed_slice()) } +/// Download the FITS serialization of the MOC of given `name`. +/// # Args +/// * `name`: name of the MOC in the internal store +/// * `force_v1_compatibility`: for S-MOCs, force compatibility with Version 1 of the MOC standard. #[wasm_bindgen(js_name = "toFitsFile", catch)] -pub fn to_fits_file(name: &str) -> Result<(), JsValue> { - let data: Box<[u8]> = store::exec(name, move |moc| moc.to_fits()) +pub fn to_fits_file(name: &str, force_v1_compatibility: Option) -> Result<(), JsValue> { + let data: Box<[u8]> = store::exec(name, move |moc| moc.to_fits(force_v1_compatibility.unwrap_or(false))) .ok_or_else(|| JsValue::from_str("MOC not found"))?; to_file(name,".fits", "application/fits", data) } @@ -1314,7 +1327,7 @@ pub fn space_fold(space_moc: &str, st_moc: &str, res_tmoc_name: &str) -> Result< /// Returns an array of boolean (u8 set to 1 or 0) telling if the pairs of coordinates /// in the input array are in (true=1) or out of (false=0) the S-MOC of given name. -/// # Params +/// # Args /// * `name`: the name of the S-MOC to be used for filtering /// * `coos_deg`: list of coordinates in degrees `[lon_1, lat_1, lon_2, lat_2, ..., lon_n, lat_n]` /// # Remarks @@ -1355,7 +1368,7 @@ pub fn filter_pos(name: &str, coos_deg: Box<[f64]>) -> Result, JsValu /// Returns an array of boolean (u8 set to 1 or 0) telling if the time (in Julian Days) /// in the input array are in (true=1) or out of (false=0) the T-MOC of given name. -/// # Params +/// # Args /// * `name`: the name of the S-MOC to be used for filtering /// * `jds`: array of decimal JD time (`f64`) /// # Remarks diff --git a/crates/wasm/src/store.rs b/crates/wasm/src/store.rs index f21e411..e06efce 100644 --- a/crates/wasm/src/store.rs +++ b/crates/wasm/src/store.rs @@ -80,7 +80,6 @@ pub(crate) fn get_info(name: &str) -> Option { pub(crate) fn exec(name: &str, op: F) -> Option where - R: , F: Fn(&InternalMoc) -> R { get_store().read().unwrap() diff --git a/src/deser/fits/mod.rs b/src/deser/fits/mod.rs index d70297a..12c0f9d 100644 --- a/src/deser/fits/mod.rs +++ b/src/deser/fits/mod.rs @@ -124,6 +124,7 @@ impl STMocType { // We could have avoided to create Cell and directly write uniq, to be changed later. // we lazily re-use the Cell iterator made to save in JSON format. +/// To be compatible with version 1.0 of the MOC standard. pub fn hpx_cells_to_fits_ivoa( moc_it: I, moc_id: Option, @@ -222,7 +223,7 @@ fn write_fits_header( } /* -pub fn cells_to_fits_ivoa( // using GUNIQ (to be done +pub fn cells_to_fits_ivoa( moc_it: I, moc_id: Option, moc_type: Option, @@ -245,8 +246,6 @@ pub fn cells_to_fits_ivoa( // using GUNIQ (to be done }, } } - - fn cells_to_fits_internal( n_cells: usize, mut range_it: I, @@ -339,6 +338,7 @@ fn build_range_moc_keywords>( } // BINTABLE specific moc_kws.insert(MocKeywords::TForm1(T::TFORM)); + moc_kws.insert(MocKeywords::TType1(TType1{ ttype: String::from("RANGE") })); // No ttype moc_kws } diff --git a/src/moc/mod.rs b/src/moc/mod.rs index 1e9bfa4..2d8a097 100644 --- a/src/moc/mod.rs +++ b/src/moc/mod.rs @@ -1,39 +1,47 @@ //! A MOC is a set of ordered, non-overlapping MOC elements, associated to a maximum depth. -use std::io::Write; -use std::ops::Range; -use std::marker::PhantomData; +use std::{ + io::Write, + ops::Range, + marker::PhantomData +}; use healpix::nested::bmoc::{BMOC, BMOCBuilderUnsafe}; -use crate::deser::{ - self, - fits::{ - keywords, ranges_to_fits_ivoa, - error::FitsError +use crate::{ + idx::Idx, + qty::{MocQty, Bounded, Hpx}, + elem::{ + cell::Cell, + cellcellrange::CellOrCellRange, + range::MocRange, }, -}; -use crate::idx::Idx; -use crate::qty::{MocQty, Bounded}; -use crate::elem::{ - cell::Cell, - cellcellrange::CellOrCellRange, - range::MocRange, -}; -use crate::moc::adapters::{ - RangeMOCIteratorFromCells, RangeMOCIteratorFromCellOrCellRanges, CellMOCIteratorFromRanges, - CellOrCellRangeMOCIteratorFromCells, DepthMaxCellsFromRanges -}; -use crate::moc::range::RangeMOC; -use crate::moc::range::op::{ - check::{check, CheckedIterator}, - convert::{convert, ConvertIterator}, - degrade::{degrade, DegradeRangeIter}, - not::{not, NotRangeIter}, - and::{and, AndRangeIter}, - or::{or, OrRangeIter}, - xor::{xor, XorRangeIter}, - minus::{minus, MinusRangeIter}, + moc::{ + adapters::{ + RangeMOCIteratorFromCells, RangeMOCIteratorFromCellOrCellRanges, CellMOCIteratorFromRanges, + CellOrCellRangeMOCIteratorFromCells, DepthMaxCellsFromRanges + }, + range::{ + RangeMOC, + op::{ + check::{check, CheckedIterator}, + convert::{convert, ConvertIterator}, + degrade::{degrade, DegradeRangeIter}, + not::{not, NotRangeIter}, + and::{and, AndRangeIter}, + or::{or, OrRangeIter}, + xor::{xor, XorRangeIter}, + minus::{minus, MinusRangeIter}, + } + } + }, + deser::{ + self, + fits::{ + keywords, ranges_to_fits_ivoa, hpx_cells_to_fits_ivoa, + error::FitsError + }, + } }; pub mod range; @@ -59,27 +67,6 @@ pub trait NonOverlapping {} /// Commodity trait containing all MOC properties pub trait MOCProperties: HasMaxDepth + ZSorted + NonOverlapping { } -//////////////////////////// -// En cours d'elobaration -/*pub trait MOC: MOCProperties { - type Idx: Idx; - type Qty: MocQty; - type RangeIt: Iterator>; - /// If we need to reuse the MOC, two solutions: clone or implement MOC on &Self. - /// Then use Cow in operations (if needed). - fn into_iter(self) -> RangeIt; -} -pub trait MOCIterator: Iterator> { - type Qty: MocQty; -} - -struct SweepLine { - left_it - right_it -} -Iterator.. ?*/ -///////////////////////////// - /// Iterator over MOC cells pub trait CellMOCIterator: Sized + MOCProperties + Iterator> { type Qty: MocQty; @@ -101,8 +88,22 @@ pub trait CellMOCIterator: Sized + MOCProperties + Iterator fn to_json_aladin(self, fold: Option, writer: W) -> std::io::Result<()> { deser::json::to_json_aladin(self, &fold, "", writer) } +} +pub trait CellHpxMOCIterator: CellMOCIterator> { + fn hpx_cells_to_fits_ivoa( + self, + moc_id: Option, + moc_type: Option, + writer: W + ) -> Result<(), FitsError> { + hpx_cells_to_fits_ivoa(self, moc_id, moc_type, writer) + } } +/// All types that implement `CellMOCIterator>` get methods defined in +/// `CellHpxMOCIterator` for free. +impl>> CellHpxMOCIterator for I { } + pub trait IntoBMOC>: CellMOCIterator { fn into_bmoc(self) -> BMOC { @@ -117,7 +118,6 @@ pub trait IntoBMOC>: CellMOCIterator { impl, U: CellMOCIterator> IntoBMOC for U {} - /// Transform an object into an iterator over MOC cells. pub trait CellMOCIntoIterator: Sized { type Qty: MocQty;