diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 31c9e1b..688be6a 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -16,8 +16,8 @@ jobs: with: java-version: 11 - - name: validate CAOM datas model version(s) - run: ./gradlew --info clean checkstyleTest test + - name: validate CAOM data model + run: ./gradlew --info clean vodmlValidate test - name: generate HTML documentation run: ./gradlew --info clean xslt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..85e7c1d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.idea/ diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..54aed0e --- /dev/null +++ b/Changelog.md @@ -0,0 +1,57 @@ +# CAOM changes +The following is a brief summary of changes in the current draft version (2.5). + +## general changes +- change `Plane.position.bounds` to be mandatory +- change `Plane.energy.bounds` to be mandatory +- change `Plane.time.bounds` to be mandatory +- change `Plane.polarization.states` to require at least 1 value + +The above changes mean that each of position/energy/time/polarization objects have one mandatory field and +queries with something like `Plane.position.bounds is not null` can be used to detect if the object is present. + +- add `ArtifactDescription` entity to support providing descriptions with links (eg in a DataLink output) +- add `Artifact.descriptionID` to refer to a shared `ArtifactDescription` + +## radio support +For radio observations, many properties such as field-of-view, spatial and spectral resolution are dependent on frequency. Modern, wideband facilities can have large frequency-dependent variation in these properties within a single observation. + +- propose `Plane.position.energyDependent` (Boolean) to flag that variable position information varies with energy (as opposed to some other reason) + +This flag would clarify the meaning of minBounds, maxAngularScale, and resolutionBounds; it is unclear if this is really needed here and it does not look necessary for energy and time axes. + +- add `Plane.position.minBounds` (Shape) to describe variable coverage (bounds is already max bounds) +- add `Plane.position.maxAngularScale` (Interval) to describe min/max scale of signal/objects in the data; could be in Plane.metrics? +- add `Plane.energy.resolution` (double) to describe the absolute resolution (representative value, probably mean/pixel) +- add `Plane.energy.resolutionBounds` (Interval) to describe the min/max absolute resolution when it varies across the data +- add `Plane.time.exposureBounds` (Interval) to describe the min/max absolute exposure time when it varies across the data +- remove `Plane.position.timeDependent` as it was only used to explain why Plane.position.bounds was null because of tracking mode + +- add `Observation.telescope.trackingMode` and refer to a non-existent IVOA vocabulary to describe the + tracking/pointing of the telescope during the observation; null indicates sidereal tracking (for backwards compat) + +- add `Plane.uv` (Visibility) to describe UV-plane (expect: only used when dataProductType=visibility) +- add `Plane.uv.distance` (Interval) to describe the min and max distance in the UV plane +- add `Plane.uv.distributionEccentricity` (double); mandatory or optional within Visibility? +- add `Plane.uv.distributionFill` (double); mandatory or optional within Visibility? + +- replace PolarizationState (enum) with PolarizationState vocabulary and refer to a non-existent IVOA vocabulary that could be extracted from WCS, ObsCore, and community usage/extensions + +## identifiers +- replace `Observation.observationID` (String) with `Observation.uri` (URI) to be the complete self contained identifier; values would be used in `DerivedObservation.members` to refer to other observations + +- replace `Plane.productID` (String) with `Plane.uri` (URI) to be the complete self-contained identifier; values would be used in `Plane.provenance.inputs` to refer to other planes +- remove `Plane.creatorID` because it is essentially redundant vs Plane.uri + +A `publisherID` value is strictly outside the core model because the value must be changed (generated) when CAOM metadata is synced from one _publisher_ to _a differnt publisher_. + +## reconcile with IVOA data models + +- change `Plane.dataProductType` to refer directly to the IVOA product-type vocabulary +- change `Artifact.productType` to refer directly to the IVOA DataLink Core (semantics) vocabulary +- change `Plane.observable.ucd` to refer directly to IVOA UCD1+ + +- add `Plane.position.calibration` and refer to a non-existent IVOA vocabulary that could be extracted from the ObsCore optional section +- add `Plane.energy.calibration` (as above) +- add `Plane.time.calibration` (as above) +- add `Plane.observable.calibration` (as above) diff --git a/build.gradle b/build.gradle index 68150b7..78a98b5 100644 --- a/build.gradle +++ b/build.gradle @@ -1,16 +1,14 @@ plugins { + id 'net.ivoa.vo-dml.vodmltools' version '0.5.5' id 'java' id 'checkstyle' id "com.github.eerohele.saxon-gradle" version "0.2.1" } -repositories { - mavenCentral() - mavenLocal() -} -sourceCompatibility = 1.8 +vodml { +} group = 'org.opencadc' version = '2.4' @@ -49,9 +47,9 @@ xslt { } dependencies { - testCompile 'org.opencadc:cadc-vodml:[1.0.9,1.1)' + testImplementation 'org.opencadc:cadc-vodml:[1.0.9,1.1)' - testCompile 'junit:junit:4.13' + testImplementation 'junit:junit:4.13' } apply from: 'opencadc.gradle' diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e708b1c..2c35211 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 442d913..09523c0 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4f906e0..f5feea6 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,69 +15,104 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # Attempt to set APP_HOME + # Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar @@ -87,9 +122,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -98,88 +133,120 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # For Cygwin or MSYS, switch paths to Windows format before running java -if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - 0) set -- ;; - 1) set -- "$args0" ;; - 2) set -- "$args0" "$args1" ;; - 3) set -- "$args0" "$args1" "$args2" ;; - 4) set -- "$args0" "$args1" "$args2" "$args3" ;; - 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=`save "$@"` -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index ac1b06f..9b42019 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,8 +13,10 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +27,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..203a8e9 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,7 @@ +rootProject.name = 'CAOM' +dependencyResolutionManagement { + repositories { + mavenLocal() + mavenCentral() + } +} \ No newline at end of file diff --git a/src/main/resources/draft-CAOM-2.5.png b/src/main/resources/draft-CAOM-2.5.png new file mode 100644 index 0000000..864443e Binary files /dev/null and b/src/main/resources/draft-CAOM-2.5.png differ diff --git a/src/main/resources/CAOM-current-vodml.xml b/src/main/vo-dml/CAOM-2.5.vo-dml.xml similarity index 91% rename from src/main/resources/CAOM-current-vodml.xml rename to src/main/vo-dml/CAOM-2.5.vo-dml.xml index 5934367..f7f6d84 100644 --- a/src/main/resources/CAOM-current-vodml.xml +++ b/src/main/vo-dml/CAOM-2.5.vo-dml.xml @@ -4,7 +4,7 @@ ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** * -* (c) 2019. (c) 2019. +* (c) 2024. (c) 2024. * Government of Canada Gouvernement du Canada * National Research Council Conseil national de recherches * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 @@ -57,8 +57,8 @@ Common Archive Observation Model Patrick Dowler, Canadian Astronomy Data Centre - 2.4 - 2019-07-12T12:00:00 + 2.5 + 2024-07-29T23:00:00 ivoa @@ -81,32 +81,11 @@ caom2 this package contains the CAOM object types and enumerations - - - ObservationURI - ObservationURI - Observation identifier of the form caom:{Observation.collection}/{Observation.observationID} - - ivo:anyURI - - - - - PlaneURI - PlaneURI - Plane identifier of the form caom:{Observation.collection}/{Observation.observationID}/{Plane.productID} - aka {observationURI}/{Plane.productID} - - ivo:anyURI - - - ObservationIntentType ObservationIntentType - the intent of the original observer in acquiring this observation; - work-around: using the name of the literal to convey the serialised value + the intent of the original creator (usually observer) in acquiring this observation ObservationIntentType.SCIENCE science @@ -117,6 +96,11 @@ calibration the intent of this observation was to create calibration data + + ObservationIntentType.OUTREACH + calibration + the intent of this observation was to create public outreach content + @@ -207,103 +191,6 @@ - - PolarizationState - PolarizationState - a classification of polarization (Stokes states plus other related quantities); - work-around: using the name of the literal to convey the serialised value - - PolarizationState.I - I - unpolarized - - - PolarizationState.Q - Q - Stokes linear Q - - - PolarizationState.U - U - Stokes linear U - - - PolarizationState.V - V - Stokes circular V - - - PolarizationState.RR - RR - right-right circular - - - PolarizationState.LL - LL - left-left circular - - - PolarizationState.RL - RL - right-left cross-circular - - - PolarizationState.LR - LR - left-right cross-circular - - - PolarizationState.XX - XX - X parallel linear - - - PolarizationState.YY - YY - Y parallel linear - - - PolarizationState.XY - XY - XY cross-linear - - - PolarizationState.YX - YX - YX cross-linear - - - PolarizationState.POLI - POLI - linear polarized intensity: sqrt(Q^2 + U^2) - - - PolarizationState.FPOLI - FPOLI - fractional linear polarization: POLI/I - - - PolarizationState.POLA - POLA - linear polarization angle: 1/2 arctan(U,Q) - - - PolarizationState.EPOLI - EPOLI - elliptical polarization intensity: sqrt(Q^2 + U^2 + V^2) - - - PolarizationState.CPOLI - CPOLI - circular polarization intensity: |V| - - - PolarizationState.NPOLI - NPOLI - unpolarized intensity: I - EPOLI - - - SegmentType SegmentType @@ -385,13 +272,21 @@ + + CalibrationStatus + DataProductType + term from the IVOA calibration-status vocabulary; this vocabulary does not yet exist + but can be created using optional terms in the ObsCore standard (NEW in CAOM-2.5) + + caom2:VocabularyTerm + + + DataProductType DataProductType - vocabulary term used in CAOM; this class defines constants for the CAOM - DataProductType vocabulary which includes all the terms from the IVOA ObsCore - data model plus additional terms used in CAOM and not in ObsCore - (CHANGED in CAOM-2.3) + term from the IVOA product-type vocabulary (CHANGED from CAOM DataProductType + vocabulary based on ObsCore in CAOM-2.5) caom2:VocabularyTerm @@ -428,15 +323,42 @@ - ProductType - ProductType - this class defines constants for the CAOM ProductType vocabulary - (CHANGED in CAOM-2.3) + DataLinkSemantics + DataLinkSemantics + term from the DataLink Core vocabulary (CHANGED from ProductType enumeration in CAOM-2.5) + + caom2:VocabularyTerm + + + + + PolarizationState + PolarizationState + this class defines constants for the PolarizationState vocabulary + (CHANGED from enumeration in CAOM-2.5) + + caom2:VocabularyTerm + + + + + Tracking + Tracking + term from the Tracking vocabulary NEW from enumeration in CAOM-2.5) caom2:VocabularyTerm + + UCD + UCD + term from the UCD1+ vocabulary (NEW from enumeration in CAOM-2.5) + + caom2:VocabularyTerm + + + CaomEntity CaomEntity @@ -578,11 +500,11 @@ - Observation.observationID - observationID - the collection-specific identifier for this observation + Observation.uri + uri + unique logical identifier for this observation (NEW in CAOM-2.5) - ivoa:string + ivoa:anyURI 1 @@ -787,7 +709,7 @@ the progenitor) - caom2:ObservationURI + ivoa:anyURI 0 @@ -804,11 +726,10 @@ caom2:CaomEntity - Plane.creatorID - creatorID - identifier for this product assigned by the creator; - typically made up of the Observation.collection, Observation.observationID, and Plane.productID - and in the form of an IVOA dataset identifier (NEW in CAOM-2.3) + Plane.uri + uri + unique logical identifier for this product; typically made by adding additional + path component(s) to the Observation.uri (NEW in CAOM-2.5) ivoa:anyURI @@ -817,18 +738,6 @@ 1 - - Plane.productID - productID - collection- and observationID-specific identifier for this product - - ivoa:string - - - 1 - 1 - - Plane.metaRelease metaRelease @@ -1007,6 +916,17 @@ 1 + + Plane.uv + uv + + caom2:Visibility + + + 0 + 1 + + Plane.provenance provenance @@ -1056,11 +976,9 @@ Artifact.productType productType - the primary product type of the artifact; for multi-part artifacts where the parts have different - types, this is the primary type; for example, if an artifact has a science part and an auxiliary part, the artifact - should have type science + the relationship of this Artifact to the parent Plane (DataLink semantics) - caom2:ProductType + caom2:DataLinkSemantics 1 @@ -1144,6 +1062,18 @@ -1 + + Artifact.descriptionID + descriptionID + identifier for an ArtifactDescription entity (new in CAOM-2.5) + + ivoa:anyURI + + + 0 + 1 + + Artifact.parts @@ -1159,6 +1089,39 @@ + + ArtifactDescription + ArtifactDescription + shared and referenceable description of an artitfact (NEW in CAOM-2.5) + + caom2:CaomEntity + + + ArtifactDescription.uri + uri + logical identifier for this description + + ivoa:anyURI + + + 1 + 1 + + + + Artifact.description + description + description of an artifact + + ivoa:string + + + 1 + 1 + + + + Part Part @@ -1183,9 +1146,9 @@ Part.productType productType - the type of content in this part, sometimes relative to the type of the artifact + the relationship of this Artifact to the parent Plane (DataLink semantics) - caom2:ProductType + caom2:DataLinkSemantics 0 @@ -1218,9 +1181,9 @@ Chunk.productType productType - the type of content in this chunk, sometimes relative to the type of the artifact + the relationship of this Artifact to the parent Plane (DataLink semantics) - caom2:ProductType + caom2:DataLinkSemantics 0 @@ -1502,6 +1465,19 @@ -1 + + Telescope.trackingMode + trackingMode + term from the (currently non-existent) IVOA Tracking vocabulary used to + indicate how the telescope moves during data acquisition + + caom2:VocabularyTerm + + + 0 + 1 + + @@ -1965,7 +1941,7 @@ inputs local identifier for input planes; these are the actual inputs that went into the product - caom2:PlaneURI + ivoa:anyURI 0 @@ -1980,16 +1956,28 @@ description of the sample (pixel) values Observable.ucd - flag + ucd Unified Content Descriptor (UCD) that says what kind of quantity is stored - ivoa:string + caom2:UCD 1 1 + + Observable.calibration + calibration + term describing the calibration of the observable values + + caom2:CalibrationStatus + + + 0 + 1 + + @@ -2099,6 +2087,32 @@ caom2:Shape + + 1 + 1 + + + + Position.minBounds + minBounds + minimum spatial boundary that includes the data; this value is smaller than + the bounds (maximum) when the field-of-view varies because it is dependent on another + axis (usually energy) + + caom2:Shape + + + 0 + 1 + + + + Position.calibration + calibration + term describing the calibration of the position axis values + + caom2:CalibrationStatus + 0 1 @@ -2116,10 +2130,22 @@ 1 + + Position.maxAngularScale + maxAngularScale + maximum size of spatial structure (signal) that can be recovered or seen in the data + + caom2:Interval + + + 0 + 1 + + Position.resolution resolution - median spatial resolution (full-width-half-max) per pixel + mean spatial resolution (full-width-half-max) per pixel ivoa:real @@ -2153,11 +2179,11 @@ - Position.timeDependent - timeDependent - indicates that the observation was taken with non-siderial tracking so - the resulting position is time-dependent; this usually explains why no bounds is - available + Position.energyDependent + energyDependent + flag indicating that variable positional characteristics are varying because the values + depend on energy; applies to minBounds, maxAngularScale, resolutionBounds + (TBD: sufficient or short-sighted?) ivoa:boolean @@ -2179,6 +2205,18 @@ caom2:SampledInterval + + 1 + 1 + + + + Energy.calibration + calibration + term describing the calibration of the energy axis values + + caom2:CalibrationStatus + 0 1 @@ -2212,7 +2250,7 @@ Energy.resolvingPower resolvingPower - median spectral resolving power per pixel + mean spectral resolving power per pixel (relative resolution) ivoa:real @@ -2224,7 +2262,31 @@ Energy.resolvingPowerBounds resolvingPowerBounds - range of resolving power within the bounds + range of resolving power within the bounds (relative resolution) + + caom2:Interval + + + 0 + 1 + + + + Energy.resolution + resolution + mean absolute spectral resolution per pixel + + ivoa:real + + + 0 + 1 + + + + Energy.resolutionBounds + resolutionBounds + range of absolute spectral resolution within the bounds caom2:Interval @@ -2236,7 +2298,7 @@ Energy.sampleSize sampleSize - median pixel size + mean pixel size ivoa:real @@ -2294,6 +2356,18 @@ caom2:SampledInterval + + 1 + 1 + + + + Time.calibration + calibration + term describing the calibration of the time axis values + + caom2:CalibrationStatus + 0 1 @@ -2350,7 +2424,7 @@ Time.exposure exposure - median exposure time per pixel + mean exposure time per pixel ivoa:real @@ -2359,6 +2433,18 @@ 1 + + Time.exposureBounds + exposureBounds + range of exposure within the bounds + + caom2:Interval + + + 0 + 1 + + @@ -2373,7 +2459,7 @@ caom2:PolarizationState - 0 + 1 -1 @@ -2431,9 +2517,50 @@ 1 + + + Visibility + Visibility + description of a UV-plane for interferometry data (new in CAOM-2.5) + + Visibility.distance + distance + range of distances in the UV plane + + caom2:Interval + + + 1 + 1 + + + + Visibility.distributionEccentricity + distance + eccentricity of the distribtuion of ??? in [0,1] + + ivoa:real + + + 1 + 1 + + + + Visibility.distributionFill + distance + fill-factor of the distribtuion of ??? in [0,1] + + ivoa:real + + + 1 + 1 + + - + types types diff --git a/src/main/vo-dml/CAOM-2.5.vodml-binding.xml b/src/main/vo-dml/CAOM-2.5.vodml-binding.xml new file mode 100644 index 0000000..2dfd5ee --- /dev/null +++ b/src/main/vo-dml/CAOM-2.5.vodml-binding.xml @@ -0,0 +1,12 @@ + + + + + caom2 + CAOM-2.5.vo-dml.xml + org.ivoa.dm.caom2 + http://ivoa.net/dm/models/vo-dml/experiment/caom2 + + \ No newline at end of file diff --git a/src/test/java/ca/nrc/cadc/caom2/VODMLValidationTest.java b/src/test/java/ca/nrc/cadc/caom2/VODMLValidationTest.java index 425fc3f..aa5573e 100644 --- a/src/test/java/ca/nrc/cadc/caom2/VODMLValidationTest.java +++ b/src/test/java/ca/nrc/cadc/caom2/VODMLValidationTest.java @@ -3,7 +3,7 @@ ******************* CANADIAN ASTRONOMY DATA CENTRE ******************* ************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** * -* (c) 2016. (c) 2016. +* (c) 2024. (c) 2024. * Government of Canada Gouvernement du Canada * National Research Council Conseil national de recherches * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 @@ -63,11 +63,10 @@ * . * ************************************************************************ -*/ + */ package ca.nrc.cadc.caom2; - import ca.nrc.cadc.util.FileUtil; import ca.nrc.cadc.util.Log4jInit; import ca.nrc.cadc.vodml.SchematronValidationException; @@ -86,109 +85,121 @@ * * @author pdowler */ -public class VODMLValidationTest -{ +public class VODMLValidationTest { + private static final Logger log = Logger.getLogger(VODMLValidationTest.class); private static final String VODML_FILE_22 = "CAOM-2.2-vodml.xml"; private static final String VODML_FILE_23 = "CAOM-2.3-vodml.xml"; private static final String VODML_FILE_24 = "CAOM-2.4-vodml.xml"; - - private static final String[] VODML_FILES = new String[] - { + private static final String VODML_FILE_CUR = "CAOM-current-vodml.xml"; + + private static final String[] VODML_FILES = new String[]{ VODML_FILE_22, VODML_FILE_23, VODML_FILE_24 }; - - static - { + + static { Log4jInit.setLevel("ca.nrc.cadc.caom2", Level.INFO); Log4jInit.setLevel("ca.nrc.cadc.vodml", Level.INFO); } - public VODMLValidationTest() { } - + + public VODMLValidationTest() { + } + @Test - public void testWellFormed() - { - for (String vodmlFile : VODML_FILES) - { - try - { - File testVODML = FileUtil.getFileFromResource(vodmlFile, VODMLValidationTest.class); - log.info("testWellFormed VO-DML/XML doc: " + testVODML); - - VOModelReader wf = new VOModelReader(false, false, false); - Document doc = wf.read(new FileInputStream(testVODML)); - Assert.assertNotNull(doc); - - VOModelWriter w = new VOModelWriter(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - w.write(doc, bos); - log.debug("well-formed document:\n" + bos.toString()); - log.info("testWellFormed VO-DML/XML doc: OK"); - } - catch(Exception unexpected) - { - log.error("unexpected exception", unexpected); - Assert.fail("unexpected exception: " + unexpected); - } + public void testDraftWellFormed() { + testWellFormed(VODML_FILE_CUR); + } + + @Test + public void testDraftSchemaValid() { + testSchemaValid(VODML_FILE_CUR); + } + + @Test + public void testDraftSchematronValid() { + testSchematronValid(VODML_FILE_CUR); + } + + @Test + public void testWellFormed() { + for (String vodmlFile : VODML_FILES) { + testWellFormed(vodmlFile); } } - + + private void testWellFormed(String vodmlFile) { + try { + File testVODML = FileUtil.getFileFromResource(vodmlFile, VODMLValidationTest.class); + log.info("testWellFormed VO-DML/XML doc: " + testVODML); + + VOModelReader wf = new VOModelReader(false, false, false); + Document doc = wf.read(new FileInputStream(testVODML)); + Assert.assertNotNull(doc); + + VOModelWriter w = new VOModelWriter(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + w.write(doc, bos); + log.debug("well-formed document:\n" + bos.toString()); + log.info("testWellFormed VO-DML/XML doc: OK"); + } catch (Exception unexpected) { + log.error("unexpected exception", unexpected); + Assert.fail("unexpected exception: " + unexpected); + } + } + @Test - public void testSchemaValid() - { - for (String vodmlFile : VODML_FILES) - { - try - { - File testVODML = FileUtil.getFileFromResource(vodmlFile, VODMLValidationTest.class); - log.info("testSchemaValid VO-DML/XML doc: " + testVODML); - - VOModelReader wf = new VOModelReader(true, false, false); - Document doc = wf.read(new FileInputStream(testVODML)); - Assert.assertNotNull(doc); - - VOModelWriter w = new VOModelWriter(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - w.write(doc, bos); - log.debug("schema-valid document:\n" + bos.toString()); - log.info("testSchemaValid VO-DML/XML doc: OK"); + public void testSchemaValid() { + for (String vodmlFile : VODML_FILES) { + testSchemaValid(vodmlFile); + } + } - } - catch(Exception unexpected) - { - log.error("unexpected exception", unexpected); - Assert.fail("unexpected exception: " + unexpected); - } + private void testSchemaValid(String vodmlFile) { + try { + File testVODML = FileUtil.getFileFromResource(vodmlFile, VODMLValidationTest.class); + log.info("testSchemaValid VO-DML/XML doc: " + testVODML); + + VOModelReader wf = new VOModelReader(true, false, false); + Document doc = wf.read(new FileInputStream(testVODML)); + Assert.assertNotNull(doc); + + VOModelWriter w = new VOModelWriter(); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + w.write(doc, bos); + log.debug("schema-valid document:\n" + bos.toString()); + log.info("testSchemaValid VO-DML/XML doc: OK"); + + } catch (Exception unexpected) { + log.error("unexpected exception", unexpected); + Assert.fail("unexpected exception: " + unexpected); } } - + @Test - public void testSchematronValid() - { - for (String vodmlFile : VODML_FILES) - { - try - { - File testVODML = FileUtil.getFileFromResource(vodmlFile, VODMLValidationTest.class); - log.info("testSchematronValid VO-DML/XML doc: " + testVODML); - - VOModelReader wf = new VOModelReader(true, true, true); - Document doc = wf.read(new FileInputStream(testVODML)); - Assert.assertNotNull(doc); - log.info("testSchematronValid VO-DML/XML doc: OK"); - } - catch(SchematronValidationException ex) - { - for (String msg : ex.getFailures()) - log.error(msg); - Assert.fail("schematron validation failed: " + ex); - } - catch(Exception unexpected) - { - log.error("unexpected exception", unexpected); - Assert.fail("unexpected exception: " + unexpected); + public void testSchematronValid() { + for (String vodmlFile : VODML_FILES) { + testSchematronValid(vodmlFile); + } + } + + private void testSchematronValid(String vodmlFile) { + try { + File testVODML = FileUtil.getFileFromResource(vodmlFile, VODMLValidationTest.class); + log.info("testSchematronValid VO-DML/XML doc: " + testVODML); + + VOModelReader wf = new VOModelReader(true, true, true); + Document doc = wf.read(new FileInputStream(testVODML)); + Assert.assertNotNull(doc); + log.info("testSchematronValid VO-DML/XML doc: OK"); + } catch (SchematronValidationException ex) { + for (String msg : ex.getFailures()) { + log.error(msg); } + Assert.fail("schematron validation failed: " + ex); + } catch (Exception unexpected) { + log.error("unexpected exception", unexpected); + Assert.fail("unexpected exception: " + unexpected); } } } diff --git a/src/uml/CAOM-2.4.zargo b/src/uml/CAOM-2.4.zargo new file mode 100644 index 0000000..f6c3de5 Binary files /dev/null and b/src/uml/CAOM-2.4.zargo differ diff --git a/src/uml/CAOM.zargo b/src/uml/CAOM.zargo index f6c3de5..9290b1b 100644 Binary files a/src/uml/CAOM.zargo and b/src/uml/CAOM.zargo differ diff --git a/src/uml/merge-uml-pngs.sh b/src/uml/merge-uml-pngs.sh index 6555c12..88bda79 100644 --- a/src/uml/merge-uml-pngs.sh +++ b/src/uml/merge-uml-pngs.sh @@ -1,10 +1,10 @@ #!/bin/bash -convert -append \ - CAOM1core.png \ - CAOM2datatypes.png \ - CAOM3wcs.png \ - CAOM4entities.png \ - CAOM5vocabularies.png \ - CAOM-2.4.png +## complete list +#convert -append CAOM1core.png CAOM2datatypes.png CAOM3wcs.png CAOM4entities.png CAOM5vocabularies.png \ + draft-CAOM-2.5.png + +## only changes +convert -append CAOM1core.png CAOM4entities.png CAOM5vocabularies.png \ + draft-CAOM-2.5.png