Keys and Parameters
The library offers a flexible and typesafe means to create Parameters to store values like primitive types, collection types or domain specific types.
A Parameter is a Key and Value where the Value must be from a set of defined primitive types including binary data. The Value of a Parameter
is always considered to be an Array of the type (i.e. if a single value is stored it is at array location 0). A Parameter
is immutable; a modification to an existing Parameter
will return a new instance.
A Value can also have Units
, which must be of the defined types. See Units for more information. At this time Units are informational only–no calculation or conversion support is provided. Some systems may provide a key value with different units, and receiver can inspect the Units
to make a decision on how to handle the value.
A ParameterSet is a Set of Parameter
. Various other message types include a ParameterSet
(e.g. Setup, Event). A key is unique in a ParameterSet
since it is a Set.
How to Create a Parameter
- choose an appropriate KeyType from the tables below for your language(Scala/Java).
- calling the
make
method on KeyType and supplying a String keyName will return a suitably typed Key instance. - exploit the overloaded
set
and->
methods, which will allow you to store values of the based on chosen KeyType. e.g.JKeyType.BooleanKey
will allow storing onlyjava.lang.Boolean
values.
Primitive Datatypes
Primitive | Scala KeyType | Java KeyType |
---|---|---|
Boolean | KeyType.BooleanKey | JKeyType.BooleanKey |
Character | KeyType.CharKey | JKeyType.JCharKey |
Byte | KeyType.ByteKey | JKeyType.ByteKey |
Short | KeyType.ShortKey | JKeyType.ShortKey |
Long | KeyType.LongKey | JKeyType.LongKey |
Int | KeyType.IntKey | JKeyType.IntKey |
Float | KeyType.FloatKey | JKeyType.FloatKey |
Double | KeyType.DoubleKey | JKeyType.DoubleKey |
String | KeyType.StringKey | JKeyType.StringKey |
UtcTime | KeyType.UTCTimeKey | JKeyType.UTCTimeKey |
TaiTime | KeyType.TAITimeKey | JKeyType.TAITimeKey |
- Scala
-
//declare keyName val s1: String = "encoder" //making 3 keys val k1: Key[Boolean] = KeyType.BooleanKey.make(s1) val k2: Key[Short] = KeyType.ShortKey.make("RandomKeyName") val k3: Key[String] = KeyType.StringKey.make(s1) //storing a single value val booleanParam: Parameter[Boolean] = k1.set(true) //storing multiple values val paramWithShorts1: Parameter[Short] = k2.set(1, 2, 3, 4) val paramWithShorts3: Parameter[Short] = k2.setAll(Array[Short](1, 2, 3, 4)) //associating units val weekDays: Array[String] = Array("Sunday", "Monday", "Tuesday") val paramWithUnits1: Parameter[String] = k3.setAll(weekDays) val paramWithUnits2: Parameter[String] = k3.setAll(weekDays) withUnits Units.day //default unit is NoUnits assert(booleanParam.units === Units.NoUnits) //set units explicitly on an existing Parameter val paramWithUnits3: Parameter[Short] = paramWithShorts1.withUnits(Units.meter) //retrieve values from Parameter val allValues: Array[Short] = paramWithShorts1.values //retrieve just top value val head: Short = paramWithShorts1.head
- Java
-
//making 3 keys String keyName = "encoder"; Key<Boolean> k1 = JKeyType.BooleanKey().make(keyName); Key<Short> k2 = JKeyType.ShortKey().make(keyName, JUnits.NoUnits); Key<String> k3 = JKeyType.StringKey().make(keyName, JUnits.day); //storing a single value Parameter<Boolean> booleanParam = k1.set(true); //storing multiple values Short[] shortArray = {1, 2, 3, 4}; Parameter<Short> paramWithManyShorts1 = k2.setAll(shortArray); Parameter<Short> paramWithManyShorts2 = k2.set((short) 1, (short) 2, (short) 3, (short) 4); //associating units String[] weekDays = {"Sunday", "Monday", "Tuesday"}; Parameter<String> paramWithUnits1 = k3.setAll(weekDays); Parameter<String> paramWithUnits2 = k3.setAll(weekDays).withUnits(JUnits.day); //deault unit is NoUnits() boolean hasDefaultUnit = booleanParam.units() == JUnits.NoUnits; //true //set units explicitly on an existing Parameter Parameter<Short> paramWithUnits3 = paramWithManyShorts1.withUnits(JUnits.meter); //retrieve values from Parameter Short[] allValues = (Short[]) paramWithManyShorts1.values(); //retrieve just top value Short head = paramWithManyShorts1.head();
Arrays
Primitive | Scala KeyType | Java KeyType |
---|---|---|
ByteArray | KeyType.ByteArrayKey | JKeyType.ByteArrayKey |
ShortArray | KeyType.ShortArrayKey | JKeyType.ShortArrayKey |
LongArray | KeyType.LongArrayKey | JKeyType.LongArrayKey |
IntArray | KeyType.IntArrayKey | JKeyType.IntArrayKey |
FloatArray | KeyType.FloatArrayKey | JKeyType.FloatArrayKey |
DoubleArray | KeyType.DoubleArrayKey | JKeyType.DoubleArrayKey |
- Scala
-
//make some arrays val arr1: Array[Double] = Array(1.0, 2.0, 3.0, 4.0, 5.0) val arr2: Array[Double] = Array(10.0, 20.0, 30.0, 40.0, 50.0) //keys val filterKey: Key[ArrayData[Double]] = KeyType.DoubleArrayKey.make("filter") //Store some values using helper class ArrayData val p1: Parameter[ArrayData[Double]] = filterKey.set(ArrayData(arr1), ArrayData(arr2)) val p2: Parameter[ArrayData[Double]] = filterKey -> ArrayData(arr1 ++ arr2) withUnits Units.liter //add units to existing parameters val p1AsCount = p1.withUnits(Units.count) //default unit is NoUnits assert(p1.units === Units.NoUnits) //retrieving values val head: Array[Double] = p1.head.data.toArray val allValues: Array[ArrayData[Double]] = p1.values
- Java
-
//make some arrays Double[] arr1 = {1.0, 2.0, 3.0, 4.0, 5.0}; Double[] arr2 = {10.0, 20.0, 30.0, 40.0, 50.0}; //keys Key<ArrayData<Double>> filterKey = JKeyType.DoubleArrayKey().make("filter", JUnits.NoUnits); //Store some values using helper method in ArrayData Parameter<ArrayData<Double>> p1 = filterKey.set(ArrayData.fromArray(arr1), ArrayData.fromArray(arr2)); Parameter<ArrayData<Double>> p2 = filterKey.set(ArrayData.fromArray(arr2)).withUnits(JUnits.liter); //add units to existing parameters Parameter<ArrayData<Double>> p1AsCount = p1.withUnits(JUnits.count); //default unit is NoUnits() boolean bDefaultUnit = JUnits.NoUnits == p1.units(); //retrieving values List<Double> head = p1.head().jValues(); List<ArrayData<Double>> listOfArrayData = p1.jValues(); Double[] arrayOfDoubles = (Double[]) p2.jValues().get(0).values();
Matrices
Primitive | Scala KeyType | Java KeyType |
---|---|---|
ByteMatrix | KeyType.ByteMatrixKey | JKeyType.ByteMatrixKey |
ShortMatrix | KeyType.ShortMatrixKey | JKeyType.ShortMatrixKey |
LongMatrix | KeyType.LongMatrixKey | JKeyType.LongMatrixKey |
IntMatrix | KeyType.IntMatrixKey | JKeyType.IntMatrixKey |
FloatMatrix | KeyType.FloatMatrixKey | JKeyType.FloatMatrixKey |
DoubleMatrix | KeyType.DoubleMatrixKey | JKeyType.DoubleMatrixKey |
- Scala
-
//make some arrays val m1: Array[Array[Byte]] = Array(Array[Byte](1, 2, 3), Array[Byte](4, 5, 6), Array[Byte](7, 8, 9)) val m2: Array[Array[Byte]] = Array(Array[Byte](1, 2, 3, 4, 5), Array[Byte](10, 20, 30, 40, 50)) //keys val encoderKey: Key[MatrixData[Byte]] = KeyType.ByteMatrixKey.make("encoder") //Store some values using helper class MatrixData val p1: Parameter[MatrixData[Byte]] = encoderKey.set(MatrixData.fromArrays(m1)) val p2: Parameter[MatrixData[Byte]] = encoderKey.set(m1, m2) withUnits Units.liter //add units to existing parameters val p1AsLiter = p1.withUnits(Units.liter) //default unit is NoUnits assert(p1.units === Units.NoUnits) //retrieving values val head: Array[Array[Byte]] = p1.head.data.map(_.toArray).toArray val allValues: Array[MatrixData[Byte]] = p1.values
- Java
-
//make some arrays Byte[][] m1 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; Byte[][] m2 = {{1, 2, 3, 4, 5}, {10, 20, 30, 40, 50}}; //keys Key<MatrixData<Byte>> encoderKey = JKeyType.ByteMatrixKey().make("encoder", JUnits.NoUnits); //Store some values using helper method in ArrayData Parameter<MatrixData<Byte>> p1 = encoderKey.set( MatrixData.fromArrays(m1), MatrixData.fromArrays(m2)); Parameter<MatrixData<Byte>> p2 = encoderKey.set( MatrixData.fromArrays(m2) ).withUnits(JUnits.liter); //add units to existing parameters Parameter<MatrixData<Byte>> p1AsLiter = p1.withUnits(JUnits.liter); //default unit is NoUnits() boolean bDefaultUnit = JUnits.NoUnits == p1.units(); //retrieving values MatrixData<Byte> head = p1.head(); List<MatrixData<Byte>> matrixData1 = p1.jValues(); List<MatrixData<Byte>> matrixData2 = p2.jValues();
Domain Specific Types
Primitive | Scala KeyType | Java KeyType |
---|---|---|
Choice | KeyType.ChoiceKey | JKeyType.ChoiceKey |
Struct | KeyType.StructKey | JKeyType.StructKey |
Coordinate Types
Primitive | Scala KeyType | Java KeyType |
---|---|---|
RaDec | KeyType.RaDecKey | JKeyType.RaDecKey |
EqCoord | KeyType.EqCoordKey | JKeyType.EqCoordKey |
SolarSystemCoord | KeyType.SolarSystemCoordKey | JKeyType.SolarSystemCoordKey |
MinorPlanetCoord | KeyType.MinorPlanetCoordKey | JKeyType.MinorPlanetCoordKey |
CometCoord | KeyType.CometCoordKey | JKeyType.CometCoordKey |
AltAzCoord | KeyType.AltAzCoordKey | JKeyType.AltAzCoordKey |
Coord (*) | KeyType.CoordKey | JKeyType.CoordKey |
Note that since Coord
is the base trait of the other coordinate types, you can use it as the key for any of the coordinate types.
Coordinate Types Example
The following example demonstrates the basic usage of the coordinate parameter types:
- Scala
-
import Angle._ import Coords._ // Coordinate types val pm = ProperMotion(0.5, 2.33) val eqCoord = EqCoord(ra = "12:13:14.15", dec = "-30:31:32.3", frame = FK5, pmx = pm.pmx, pmy = pm.pmy) val solarSystemCoord = SolarSystemCoord(Tag("BASE"), Venus) val minorPlanetCoord = MinorPlanetCoord(Tag("GUIDER1"), 2000, 90.degree, 2.degree, 100.degree, 1.4, 0.234, 220.degree) val cometCoord = CometCoord(Tag("BASE"), 2000.0, 90.degree, 2.degree, 100.degree, 1.4, 0.234) val altAzCoord = AltAzCoord(Tag("BASE"), 301.degree, 42.5.degree) // Can use base trait CoordKey to store values for all types val basePosKey = CoordKey.make("BasePosition") val posParam = basePosKey.set(eqCoord, solarSystemCoord, minorPlanetCoord, cometCoord, altAzCoord) //retrieving values assert(posParam.values.length == 5) assert(posParam.values(0) == eqCoord) assert(posParam.values(1) == solarSystemCoord) assert(posParam.values(2) == minorPlanetCoord) assert(posParam.values(3) == cometCoord) assert(posParam.values(4) == altAzCoord)
- Java
-
//import csw.params.core.models.Coords.*; //import static csw.params.core.models.JCoords.*; //import static csw.params.core.models.Coords.*; // Coordinate types ProperMotion pm = new ProperMotion(0.5, 2.33); EqCoord eqCoord = new EqCoord("12:13:14.15", "-30:31:32.3", FK5(), BASE(), DEFAULT_CATNAME(), pm.pmx(), pm.pmy()); SolarSystemCoord solarSystemCoord = new SolarSystemCoord(BASE(), Venus()); MinorPlanetCoord minorPlanetCoord = new MinorPlanetCoord(GUIDER1(), 2000, JAngle.degree(90), JAngle.degree(2), JAngle.degree(100), 1.4, 0.234, JAngle.degree(220)); CometCoord cometCoord = new CometCoord(BASE(), 2000.0, JAngle.degree(90), JAngle.degree(2), JAngle.degree(100), 1.4, 0.234); AltAzCoord altAzCoord = new AltAzCoord(BASE(), JAngle.degree(301), JAngle.degree(42.5)); // Can use base trait CoordKey to store values for all types Key<Coord> basePosKey = JKeyType.CoordKey().make("BasePosition", JUnits.NoUnits); Parameter<Coord> posParam = basePosKey.set(eqCoord, solarSystemCoord, minorPlanetCoord, cometCoord, altAzCoord); //retrieving values assert (posParam.jValues().size() == 5); assert (posParam.jValues().get(0).equals(eqCoord)); assert (posParam.jValues().get(1).equals(solarSystemCoord)); assert (posParam.jValues().get(2).equals(minorPlanetCoord)); assert (posParam.jValues().get(3).equals(cometCoord)); assert (posParam.jValues().get(4).equals(altAzCoord));
Choice
A key for a choice item similar to an enumeration.
- Scala
-
//Choice val choices = Choices.from("A", "B", "C") //keys val choice1Key: GChoiceKey = ChoiceKey.make("mode", NoUnits, choices) val choice2Key: GChoiceKey = ChoiceKey.make( "mode-reset", NoUnits, Choices.fromChoices(Choice("c"), Choice("b"), Choice("a")) ) //store values val p1: Parameter[Choice] = choice1Key .setAll(Array(Choice("A"))) .withUnits(Units.foot) val p2: Parameter[Choice] = choice2Key.setAll(Array(Choice("c"))) //add units val paramWithFoot = p1.withUnits(Units.foot) //default unit is NoUnits assert(p2.units === Units.NoUnits) //retrieving values val head: Choice = p1.head val values: Array[Choice] = p2.values
- Java
-
//Choice final Choices choices = Choices.from("A", "B", "C"); //keys GChoiceKey choice1Key = JKeyType.ChoiceKey().make("mode", JUnits.NoUnits, choices); GChoiceKey choice2Key = JKeyType.ChoiceKey().make( "mode-reset", JUnits.NoUnits, Choices.fromChoices( new Choice("c"), new Choice("b"), new Choice("a"))); //store values Parameter<Choice> p1 = choice1Key.set(new Choice("A")).withUnits(JUnits.foot); Parameter<Choice> p2 = choice2Key.set(new Choice("c")); //add units Parameter<Choice> paramWithFoot = p1.withUnits(JUnits.foot); //default unit is NoUnits() boolean bDefaultUnit = JUnits.NoUnits == p2.units(); //retrieving values Choice head = p1.head(); List<Choice> values = p2.jValues();
Struct
Structs can be used to create a hierarchy of parameters. The following snippet also demonstrates some of the utility functions available for manipulating parameter sets:
- Scala
-
//keys val skey: Key[Struct] = StructKey.make("myStruct") val ra = KeyType.StringKey.make("ra") val dec = KeyType.StringKey.make("dec") val epoch = KeyType.DoubleKey.make("epoch") //initialize struct val struct1: Struct = Struct().madd(ra.set("12:13:14.1"), dec.set("32:33:34.4"), epoch.set(1950.0)) val struct2: Struct = Struct().madd(dec.set("32:33:34.4"), ra.set("12:13:14.1"), epoch.set(1970.0)) //make parameters val p1: Parameter[Struct] = skey.set(struct1) val p2: Parameter[Struct] = skey.set(struct1, struct2) //add units val paramWithLightYear = p1.withUnits(Units.lightyear) //default unit is NoUnits assert(p2.units === Units.NoUnits) //retrieving values val head: Struct = p1.head val values: Array[Struct] = p2.values //get individual keys val firstKey: Option[Parameter[String]] = struct1.get(KeyType.StringKey.make("ra")) val secondKey: Option[Parameter[String]] = struct1.get("dec", KeyType.StringKey) val thirdKey: Option[Parameter[Double]] = struct1.get("epoch", KeyType.DoubleKey) //access parameter using 'parameter' or 'apply' method assert(struct1.parameter(ra) === struct1(ra)) //remove a parameter and verify it doesn't exist val mutated1: Struct = struct1.remove(ra) //using key val mutated2 = struct1.remove(firstKey.get) assert(mutated1.exists(ra) === false) assert(mutated2.exists(ra) === false) //find out missing keys val missingKeySet: Set[String] = mutated1.missingKeys(ra, dec, epoch, KeyType.FloatKey.make("missingKey")) assert(missingKeySet === Set("ra", "missingKey"))
- Java
-
//keys Key<Struct> skey = JKeyType.StructKey().make("myStruct", JUnits.NoUnits); Key<String> ra = JKeyType.StringKey().make("ra", JUnits.NoUnits); Key<String> dec = JKeyType.StringKey().make("dec", JUnits.NoUnits); Key<Double> epoch = JKeyType.DoubleKey().make("epoch", JUnits.year); //initialize struct Struct struct1 = new Struct().madd( ra.set("12:13:14.1"), dec.set("32:33:34.4"), epoch.set(1950.0)); Struct struct2 = new Struct().madd( dec.set("32:33:34.4"), ra.set("12:13:14.1"), epoch.set(1970.0)); //make parameters Parameter<Struct> p1 = skey.set(struct1); Parameter<Struct> p2 = skey.set(struct1, struct2); //add units Parameter<Struct> paramWithLightYear = p1.withUnits(JUnits.lightyear); //default unit is NoUnits() boolean bDefaultUnit = JUnits.NoUnits == p1.units(); //retrieving values Struct head = p1.head(); List<Struct> structs = p2.jValues(); //get individual keys Optional<Parameter<String>> firstKey = struct1.jGet(JKeyType.StringKey().make("ra", JUnits.NoUnits)); Optional<Parameter<String>> secondKey = struct1.jGet("dec", JKeyType.StringKey()); Optional<Parameter<Double>> thirdKey = struct1.jGet("epoch", JKeyType.DoubleKey()); //access parameter using 'parameter' and 'apply' method boolean bSuccess = struct1.parameter(ra) == struct1.apply(ra); //remove a parameter and verify it doesn't exist Struct mutated1 = struct1.remove(ra); //using key Struct mutated2 = struct1.remove(firstKey.orElseThrow()); //find out missing keys Set<String> missingKeySet = mutated1.jMissingKeys(ra, dec, epoch, JKeyType.StringKey().make("someRandomKey", JUnits.NoUnits)); Set<String> expectedMissingKeys = Set.of("ra", "someRandomKey");