diff --git a/build.sbt b/build.sbt index 849bf100..01bc0d7e 100644 --- a/build.sbt +++ b/build.sbt @@ -7,18 +7,18 @@ val catsScalacheckVersion = "0.3.1" val catsTimeVersion = "0.3.4" val circeVersion = "0.14.3" val cirisVersion = "3.1.0" -val clueVersion = "0.23.2" +val clueVersion = "0.24.1" val http4sVersion = "0.23.18" val http4sJdkHttpClientVersion = "0.9.0" val fs2Version = "3.6.1" val kindProjectorVersion = "0.13.2" -val lucumaCoreVersion = "0.63.2" +val lucumaCoreVersion = "0.67.0" val lucumaRefinedVersion = "0.1.1" val slf4jVersion = "2.0.6" val log4catsVersion = "2.5.0" val monocleVersion = "3.1.0" val munitCatsEffectVersion = "1.0.7" -val graphQLRoutesVersion = "0.5.9" +val graphQLRoutesVersion = "0.5.10" val refinedVersion = "0.10.1" val grackleVersion = "0.10.3" val natcchezHttp4sVersion = "0.5.0" @@ -36,7 +36,7 @@ Global / onChangedBuildSource := ReloadOnSourceChanges ThisBuild / scalaVersion := "3.2.2" ThisBuild / crossScalaVersions := Seq("3.2.2") -ThisBuild / tlBaseVersion := "0.5" +ThisBuild / tlBaseVersion := "0.6" ThisBuild / tlCiReleaseBranches := Seq("master") Global / onChangedBuildSource := ReloadOnSourceChanges diff --git a/modules/benchmarks/src/test/scala/lucuma/itc/LegacyITCSimulation.scala b/modules/benchmarks/src/test/scala/lucuma/itc/LegacyITCSimulation.scala index 3277dac3..72015798 100644 --- a/modules/benchmarks/src/test/scala/lucuma/itc/LegacyITCSimulation.scala +++ b/modules/benchmarks/src/test/scala/lucuma/itc/LegacyITCSimulation.scala @@ -16,6 +16,7 @@ import io.gatling.http.funspec.GatlingHttpFunSpec import lucuma.core.enums.* import lucuma.core.math.Angle import lucuma.core.math.BrightnessUnits.* +import lucuma.core.math.BrightnessValue import lucuma.core.math.Redshift import lucuma.core.math.Wavelength import lucuma.core.math.dimensional.* @@ -49,7 +50,10 @@ class LegacyITCSimulation extends GatlingHttpFunSpec { SpectralDefinition.BandNormalized( UnnormalizedSED.StellarLibrary(StellarLibrarySpectrum.A0V).some, SortedMap( - Band.R -> BigDecimal(5).withUnit[VegaMagnitude].toMeasureTagged + Band.R -> BrightnessValue + .unsafeFrom(5) + .withUnit[VegaMagnitude] + .toMeasureTagged ) ) ), @@ -377,7 +381,7 @@ class LegacyITCSimulation extends GatlingHttpFunSpec { .body( StringBody( bodyIntMagUnits( - f.withValueTagged(BigDecimal(5)) + f.withValueTagged(BrightnessValue.unsafeFrom(5)) ).asJson.noSpaces ) ) @@ -413,7 +417,7 @@ class LegacyITCSimulation extends GatlingHttpFunSpec { .body( StringBody( bodySurfaceMagUnits( - f.withValueTagged(BigDecimal(5)) + f.withValueTagged(BrightnessValue.unsafeFrom(5)) ).asJson.noSpaces ) ) @@ -450,7 +454,7 @@ class LegacyITCSimulation extends GatlingHttpFunSpec { .body( StringBody( bodyIntGaussianMagUnits( - f.withValueTagged(BigDecimal(5)) + f.withValueTagged(BrightnessValue.unsafeFrom(5)) ).asJson.noSpaces ) ) @@ -465,7 +469,10 @@ class LegacyITCSimulation extends GatlingHttpFunSpec { SpectralDefinition.BandNormalized( UnnormalizedSED.PowerLaw(c).some, SortedMap( - Band.R -> BigDecimal(5).withUnit[VegaMagnitude].toMeasureTagged + Band.R -> BrightnessValue + .unsafeFrom(5) + .withUnit[VegaMagnitude] + .toMeasureTagged ) ) ) @@ -500,7 +507,10 @@ class LegacyITCSimulation extends GatlingHttpFunSpec { SpectralDefinition.BandNormalized( UnnormalizedSED.BlackBody(c.withUnit[Kelvin]).some, SortedMap( - Band.R -> BigDecimal(5).withUnit[VegaMagnitude].toMeasureTagged + Band.R -> BrightnessValue + .unsafeFrom(5) + .withUnit[VegaMagnitude] + .toMeasureTagged ) ) ) diff --git a/modules/client/shared/src/main/scala/lucuma/itc/client/json/BandNormalizedJson.scala b/modules/client/shared/src/main/scala/lucuma/itc/client/json/BandNormalizedJson.scala index 2b35e6eb..d054b02e 100644 --- a/modules/client/shared/src/main/scala/lucuma/itc/client/json/BandNormalizedJson.scala +++ b/modules/client/shared/src/main/scala/lucuma/itc/client/json/BandNormalizedJson.scala @@ -5,6 +5,7 @@ package lucuma.itc.client.json import io.circe.Encoder import io.circe.Json +import io.circe.refined.* import io.circe.syntax.* import lucuma.core.model.SpectralDefinition.BandNormalized diff --git a/modules/client/shared/src/main/scala/lucuma/itc/client/json/EmissionLinesJson.scala b/modules/client/shared/src/main/scala/lucuma/itc/client/json/EmissionLinesJson.scala index c06fb677..876166ca 100644 --- a/modules/client/shared/src/main/scala/lucuma/itc/client/json/EmissionLinesJson.scala +++ b/modules/client/shared/src/main/scala/lucuma/itc/client/json/EmissionLinesJson.scala @@ -5,6 +5,7 @@ package lucuma.itc.client.json import io.circe.Encoder import io.circe.Json +import io.circe.refined.* import io.circe.syntax.* import lucuma.core.model.SpectralDefinition.EmissionLines @@ -17,14 +18,14 @@ given [T]: Encoder[EmissionLines[T]] with "lineWidth" -> l.lineWidth.value.asJson, "lineFlux" -> Json.obj( - "value" -> l.lineFlux.value.value.asJson, + "value" -> l.lineFlux.value.asJson, "units" -> l.lineFlux.units.serialized.asJson ) ) }: _*), "fluxDensityContinuum" -> Json.obj( - "value" -> el.fluxDensityContinuum.value.value.asJson, + "value" -> el.fluxDensityContinuum.value.asJson, "units" -> el.fluxDensityContinuum.units.serialized.asJson ) ) diff --git a/modules/itc/src/main/scala/lucuma/itc/legacy/encoders.scala b/modules/itc/src/main/scala/lucuma/itc/legacy/encoders.scala index c48da09a..657b80c9 100644 --- a/modules/itc/src/main/scala/lucuma/itc/legacy/encoders.scala +++ b/modules/itc/src/main/scala/lucuma/itc/legacy/encoders.scala @@ -7,6 +7,7 @@ import cats.data.NonEmptyList import cats.syntax.all._ import io.circe.* import io.circe.generic.semiauto._ +import io.circe.refined.* import io.circe.syntax.* import lucuma.core.enums._ import lucuma.core.math.Angle @@ -264,23 +265,20 @@ given Encoder[ItcSourceDefinition] = (s: ItcSourceDefinition) => if brightnesses.contains(s.normBand) => brightnesses .get(s.normBand) - .map(_.value.toDouble) - .flatMap(Json.fromDouble) - .getOrElse(Json.Null) + .map(_.value) + .asJson case SourceProfile.Uniform(SpectralDefinition.BandNormalized(_, brightnesses)) if brightnesses.contains(s.normBand) => brightnesses .get(s.normBand) - .map(_.value.toDouble) - .flatMap(Json.fromDouble) - .getOrElse(Json.Null) + .map(_.value) + .asJson case SourceProfile.Gaussian(_, SpectralDefinition.BandNormalized(_, brightnesses)) if brightnesses.contains(s.normBand) => brightnesses .get(s.normBand) - .map(_.value.toDouble) - .flatMap(Json.fromDouble) - .getOrElse(Json.Null) + .map(_.value) + .asJson // FIXME: Handle emission line case _ => Json.Null } diff --git a/modules/itc/src/main/scala/lucuma/itc/search/ObservingMode.scala b/modules/itc/src/main/scala/lucuma/itc/search/ObservingMode.scala index 1812ed94..163e22d8 100644 --- a/modules/itc/src/main/scala/lucuma/itc/search/ObservingMode.scala +++ b/modules/itc/src/main/scala/lucuma/itc/search/ObservingMode.scala @@ -9,13 +9,13 @@ import io.circe.* import io.circe.syntax.* import lucuma.core.enums._ import lucuma.core.math.Angle -import lucuma.core.math.Coverage import lucuma.core.math.Wavelength import lucuma.itc.GmosNITCParams import lucuma.itc.GmosSITCParams import lucuma.itc.encoders.given import lucuma.itc.search.hashes.given import lucuma.itc.search.syntax.* +import spire.math.Interval import spire.math.Rational case class GmosNorthFpuParam( @@ -42,7 +42,7 @@ object ObservingMode { sealed trait Spectroscopy extends ObservingMode derives Hash { def λ: Wavelength def resolution: Rational - def coverage: Coverage + def coverage: Interval[Wavelength] } object Spectroscopy { @@ -81,8 +81,8 @@ object ObservingMode { def resolution: Rational = disperser.resolution(λ, fpu.effectiveSlitWidth) - def coverage: Coverage = - filter.foldLeft(disperser.coverage(λ))(_ ⋂ _.coverageGN) + def coverage: Interval[Wavelength] = + filter.foldLeft(disperser.coverage(λ).toInterval)((a, b) => a.intersect(b.coverageGN)) } object GmosNorth: @@ -109,8 +109,8 @@ object ObservingMode { def resolution: Rational = disperser.resolution(λ, fpu.effectiveSlitWidth) - def coverage: Coverage = - filter.foldLeft(disperser.coverage(λ))(_ ⋂ _.coverageGS) + def coverage: Interval[Wavelength] = + filter.foldLeft(disperser.coverage(λ).toInterval)((a, b) => a.intersect(b.coverageGS)) } object GmosSouth: diff --git a/modules/itc/src/main/scala/lucuma/itc/search/syntax/GmosNorthFilter.scala b/modules/itc/src/main/scala/lucuma/itc/search/syntax/GmosNorthFilter.scala index f3fba756..255a2c44 100644 --- a/modules/itc/src/main/scala/lucuma/itc/search/syntax/GmosNorthFilter.scala +++ b/modules/itc/src/main/scala/lucuma/itc/search/syntax/GmosNorthFilter.scala @@ -6,17 +6,17 @@ package lucuma.itc.search.syntax import cats.implicits._ import lucuma.core.enums.GmosNorthFilter import lucuma.core.enums.GmosNorthFilter._ -import lucuma.core.math.Coverage import lucuma.core.math.Wavelength +import spire.math.Interval extension (self: GmosNorthFilter) // see http://www.gemini.edu/node/10621 - def coverageGN: Coverage = + def coverageGN: Interval[Wavelength] = import Wavelength.intPicometers - def cov(a: Int, b: Int = Int.MaxValue): Coverage = + def cov(a: Int, b: Int = Int.MaxValue): Interval[Wavelength] = (intPicometers.getOption(a), intPicometers.getOption(b)) - .mapN(Coverage.apply) + .mapN(Interval.closed) .getOrElse(sys.error("Invalid constant coverage.")) self match @@ -50,8 +50,8 @@ extension (self: GmosNorthFilter) // These are only used for engineering and will never be selected by search algorithm, but // we still need to handle them. For now we'll just pretend they have no coverage at all. - case HartmannA_RPrime => Coverage.Empty - case HartmannB_RPrime => Coverage.Empty + case HartmannA_RPrime => Interval.empty + case HartmannB_RPrime => Interval.empty // Allowed Filter Combinations case GPrime_GG455 => cov(460000, 552000) diff --git a/modules/itc/src/main/scala/lucuma/itc/search/syntax/GmosSouthFilter.scala b/modules/itc/src/main/scala/lucuma/itc/search/syntax/GmosSouthFilter.scala index 024d2d40..92c62c22 100644 --- a/modules/itc/src/main/scala/lucuma/itc/search/syntax/GmosSouthFilter.scala +++ b/modules/itc/src/main/scala/lucuma/itc/search/syntax/GmosSouthFilter.scala @@ -6,17 +6,17 @@ package lucuma.itc.search.syntax import cats.implicits._ import lucuma.core.enums.GmosSouthFilter import lucuma.core.enums.GmosSouthFilter._ -import lucuma.core.math.Coverage import lucuma.core.math.Wavelength +import spire.math.Interval extension (self: GmosSouthFilter) // see http://www.gemini.edu/node/10621 - def coverageGS: Coverage = + def coverageGS: Interval[Wavelength] = import Wavelength.intPicometers - def cov(a: Int, b: Int = Int.MaxValue): Coverage = + def cov(a: Int, b: Int = Int.MaxValue): Interval[Wavelength] = (intPicometers.getOption(a), intPicometers.getOption(b)) - .mapN(Coverage.apply) + .mapN(Interval.closed) .getOrElse(sys.error("Invalid constant coverage.")) self match @@ -49,8 +49,8 @@ extension (self: GmosSouthFilter) // These are only used for engineering and will never be selected by search algorithm, but // we still need to handle them. For now we'll just pretend they have no coverage at all. - case HartmannA_RPrime => Coverage.Empty - case HartmannB_RPrime => Coverage.Empty + case HartmannA_RPrime => Interval.empty + case HartmannB_RPrime => Interval.empty // Allowed Filter Combinations case GPrime_GG455 => cov(460000, 552000) diff --git a/modules/service/src/main/scala/lucuma/itc/service/ItcPartials.scala b/modules/service/src/main/scala/lucuma/itc/service/ItcPartials.scala index d86df4d6..249438db 100644 --- a/modules/service/src/main/scala/lucuma/itc/service/ItcPartials.scala +++ b/modules/service/src/main/scala/lucuma/itc/service/ItcPartials.scala @@ -30,6 +30,7 @@ import io.circe.Json import lucuma.core.enums.* import lucuma.core.math.Angle import lucuma.core.math.BrightnessUnits.* +import lucuma.core.math.BrightnessValue import lucuma.core.math.RadialVelocity import lucuma.core.math.Wavelength import lucuma.core.math.dimensional.Units.* @@ -226,14 +227,14 @@ trait GracklePartials extends GrackleParsers: ) ) => val band = bandItems.get(b) - val value = bigDecimalValue(v) + val value = bigDecimalValue(v).flatMap(bd => BrightnessValue.from(bd).toOption) val units = unitsItems.get(u) (band, value, units) .mapN { (b, v, u) => b -> u.withValueTagged(v) } .toRightIorNec("Invalid brightness") - case e => s"Invalid brighness entry $e".leftIorNec + case e => s"Invalid brightness entry $e".leftIorNec } .sequence .map(v => SortedMap(v: _*))