diff --git a/explore/app/src/main/scala/explore/config/BasicConfigurationPanel.scala b/explore/app/src/main/scala/explore/config/BasicConfigurationPanel.scala index fb7422446f..421194ff9c 100644 --- a/explore/app/src/main/scala/explore/config/BasicConfigurationPanel.scala +++ b/explore/app/src/main/scala/explore/config/BasicConfigurationPanel.scala @@ -28,8 +28,8 @@ import japgolly.scalajs.react.* import japgolly.scalajs.react.vdom.html_<^.* import lucuma.core.enums.CalibrationRole import lucuma.core.enums.ScienceMode +import lucuma.core.math.Coordinates import lucuma.core.model.ConstraintSet -import lucuma.core.model.CoordinatesAt import lucuma.core.model.User import lucuma.core.util.NewBoolean import lucuma.core.util.Timestamp @@ -51,7 +51,7 @@ case class BasicConfigurationPanel( selectedConfig: View[ConfigSelection], constraints: ConstraintSet, itcTargets: EitherNec[ItcTargetProblem, NonEmptyList[ItcTarget]], - baseCoordinates: Option[CoordinatesAt], + baseCoordinates: Option[Coordinates], calibrationRole: Option[CalibrationRole], createConfig: IO[Unit], confMatrix: ScienceModes, diff --git a/explore/app/src/main/scala/explore/config/ConfigurationTile.scala b/explore/app/src/main/scala/explore/config/ConfigurationTile.scala index c960a9deb0..99506b0e81 100644 --- a/explore/app/src/main/scala/explore/config/ConfigurationTile.scala +++ b/explore/app/src/main/scala/explore/config/ConfigurationTile.scala @@ -48,7 +48,7 @@ import explore.undo.* import japgolly.scalajs.react.* import japgolly.scalajs.react.vdom.html_<^.* import lucuma.core.math.Angle -import lucuma.core.model.CoordinatesAt +import lucuma.core.math.Coordinates import lucuma.core.model.PosAngleConstraint import lucuma.core.model.Program import lucuma.core.model.User @@ -72,7 +72,7 @@ object ConfigurationTile: requirements: UndoSetter[ScienceRequirements], pacAndMode: UndoSetter[PosAngleConstraintAndObsMode], scienceTargetIds: AsterismIds, - baseCoordinates: Option[CoordinatesAt], + baseCoordinates: Option[Coordinates], obsConf: ObsConfiguration, selectedConfig: View[ConfigSelection], revertedInstrumentConfig: List[ItcInstrumentConfig], // configuration rows selected if reverted @@ -206,7 +206,7 @@ object ConfigurationTile: pacAndMode: UndoSetter[PosAngleConstraintAndObsMode], obsConf: ObsConfiguration, itcTargets: EitherNec[ItcTargetProblem, NonEmptyList[ItcTarget]], - baseCoordinates: Option[CoordinatesAt], + baseCoordinates: Option[Coordinates], selectedConfig: View[ConfigSelection], revertedInstrumentConfig: List[ItcInstrumentConfig], modes: ScienceModes, diff --git a/explore/app/src/main/scala/explore/config/ImagingModesTable.scala b/explore/app/src/main/scala/explore/config/ImagingModesTable.scala index b8cebb7184..432fa1f8d2 100644 --- a/explore/app/src/main/scala/explore/config/ImagingModesTable.scala +++ b/explore/app/src/main/scala/explore/config/ImagingModesTable.scala @@ -34,11 +34,11 @@ import lucuma.core.enums.* import lucuma.core.math.Angle import lucuma.core.math.BoundedInterval import lucuma.core.math.BoundedInterval.* +import lucuma.core.math.Coordinates import lucuma.core.math.SignalToNoise import lucuma.core.math.Wavelength import lucuma.core.math.WavelengthDelta import lucuma.core.model.ConstraintSet -import lucuma.core.model.CoordinatesAt import lucuma.core.model.ExposureTimeMode import lucuma.core.model.User import lucuma.core.syntax.all.* @@ -64,7 +64,7 @@ final case class ImagingModesTable( matrix: ImagingModesMatrix, constraints: ConstraintSet, targets: EitherNec[ItcTargetProblem, NonEmptyList[ItcTarget]], - baseCoordinates: Option[CoordinatesAt], + baseCoordinates: Option[Coordinates], customSedTimestamps: List[Timestamp], units: WavelengthUnits, targetView: View[Option[ItcTarget]] diff --git a/explore/app/src/main/scala/explore/config/SpectroscopyModesTable.scala b/explore/app/src/main/scala/explore/config/SpectroscopyModesTable.scala index 8b2ab24250..1e72ad01be 100644 --- a/explore/app/src/main/scala/explore/config/SpectroscopyModesTable.scala +++ b/explore/app/src/main/scala/explore/config/SpectroscopyModesTable.scala @@ -64,7 +64,7 @@ case class SpectroscopyModesTable( spectroscopyRequirements: ScienceRequirements.Spectroscopy, constraints: ConstraintSet, targets: EitherNec[ItcTargetProblem, NonEmptyList[ItcTarget]], - baseCoordinates: Option[CoordinatesAt], + baseCoordinates: Option[Coordinates], matrix: SpectroscopyModesMatrix, customSedTimestamps: List[Timestamp], units: WavelengthUnits @@ -246,7 +246,7 @@ private object SpectroscopyModesTable extends ModesTableCommon: (props.matrix, props.exposureTimeMode, props.spectroscopyRequirements, - props.baseCoordinates.map(_.value.dec), + props.baseCoordinates.map(_.dec), itcResults.get.cache.size, props.targets, props.constraints, diff --git a/explore/app/src/main/scala/explore/plots/ElevationPlotTile.scala b/explore/app/src/main/scala/explore/plots/ElevationPlotTile.scala index d22b2301c9..85ff723a90 100644 --- a/explore/app/src/main/scala/explore/plots/ElevationPlotTile.scala +++ b/explore/app/src/main/scala/explore/plots/ElevationPlotTile.scala @@ -21,12 +21,13 @@ import explore.model.display.given import explore.model.enums.PlotRange import explore.model.enums.TimeDisplay import explore.model.enums.Visible +import explore.model.extensions.* import japgolly.scalajs.react.* import japgolly.scalajs.react.vdom.html_<^.* import lucuma.core.enums.Site import lucuma.core.enums.TimingWindowInclusion import lucuma.core.math.BoundedInterval -import lucuma.core.model.CoordinatesAt +import lucuma.core.math.Coordinates import lucuma.core.model.Semester import lucuma.core.model.TimingWindow import lucuma.core.model.User @@ -213,11 +214,11 @@ object ElevationPlotTile: ) case PlotRange.Semester => props.plotData.value.headOption.map { case (_, data) => - val coords: CoordinatesAt = + val coords: Coordinates = data.tracking .at(semesterView.get.start.atSite(siteView.get).toInstant) .getOrElse: - CoordinatesAt(data.tracking.baseCoordinates) + data.tracking.baseCoordinates SemesterPlot( plotOptions.get, diff --git a/explore/app/src/main/scala/explore/plots/ObjectPlotData.scala b/explore/app/src/main/scala/explore/plots/ObjectPlotData.scala index a5e45ea6eb..e406d08f7f 100644 --- a/explore/app/src/main/scala/explore/plots/ObjectPlotData.scala +++ b/explore/app/src/main/scala/explore/plots/ObjectPlotData.scala @@ -8,13 +8,13 @@ import cats.Order import cats.derived.* import eu.timepit.refined.cats.given import eu.timepit.refined.types.string.NonEmptyString +import explore.model.extensions.* import japgolly.scalajs.react.* import lucuma.core.enums.Site import lucuma.core.math.skycalc.SkyCalcResults -import lucuma.core.model.CoordinatesAt -import lucuma.core.model.ObjectTracking import lucuma.core.model.Observation import lucuma.core.model.Target +import lucuma.core.model.Tracking import lucuma.core.util.NewType import lucuma.typed.highcharts.mod.Point import lucuma.typed.highcharts.mod.PointOptionsObject @@ -37,7 +37,7 @@ trait ElevationPointWithAirmass extends Point: // Can wrap data for a target or an asterism. case class ObjectPlotData( name: NonEmptyString, - tracking: ObjectTracking, + tracking: Tracking, sites: List[Site] ) derives Eq: private val PlotEvery: Duration = Duration.ofMinutes(1) @@ -51,7 +51,9 @@ case class ObjectPlotData( PlotEvery, // We are computing the coordinates at each point in time, this may be expensive // and could be optimized for sidereals, but it's probably necessary for non-sidereals. - tracking.at(_).map(_.value).getOrElse(tracking.baseCoordinates) + tracking + .at(_) + .getOrElse(tracking.baseCoordinates) ) object ObjectPlotData: diff --git a/explore/app/src/main/scala/explore/plots/ObjectPlotOptions.scala b/explore/app/src/main/scala/explore/plots/ObjectPlotOptions.scala index 46c9a2d8ca..7f4018eb36 100644 --- a/explore/app/src/main/scala/explore/plots/ObjectPlotOptions.scala +++ b/explore/app/src/main/scala/explore/plots/ObjectPlotOptions.scala @@ -9,16 +9,16 @@ import cats.syntax.all.* import explore.model.ElevationPlotScheduling import explore.model.enums.PlotRange import explore.model.enums.TimeDisplay +import explore.model.extensions.* import japgolly.scalajs.react.ReactCats.* import japgolly.scalajs.react.Reusability import lucuma.core.enums.Site import lucuma.core.enums.TwilightType import lucuma.core.math.BoundedInterval import lucuma.core.math.Coordinates -import lucuma.core.model.CoordinatesAt -import lucuma.core.model.ObjectTracking import lucuma.core.model.ObservingNight import lucuma.core.model.Semester +import lucuma.core.model.Tracking import monocle.Focus import org.typelevel.cats.time.given @@ -101,13 +101,13 @@ object ObjectPlotOptions: def default( predefinedSite: Option[Site], observationTime: Option[Instant], - tracking: Option[ObjectTracking] + tracking: Option[Tracking] ) = val coords: Option[Coordinates] = for time <- observationTime t <- tracking - yield t.at(time).map(_.value).getOrElse(t.baseCoordinates) + yield t.at(time).getOrElse(t.baseCoordinates) val site: Site = predefinedSite .orElse: diff --git a/explore/app/src/main/scala/explore/plots/SemesterPlot.scala b/explore/app/src/main/scala/explore/plots/SemesterPlot.scala index 111d1c84c9..fc2ef450b2 100644 --- a/explore/app/src/main/scala/explore/plots/SemesterPlot.scala +++ b/explore/app/src/main/scala/explore/plots/SemesterPlot.scala @@ -14,7 +14,7 @@ import explore.model.WorkerClients.PlotClient import fs2.Stream import japgolly.scalajs.react.* import lucuma.core.math.BoundedInterval -import lucuma.core.model.CoordinatesAt +import lucuma.core.math.Coordinates import lucuma.core.util.time.format.GppDateFormatter import lucuma.react.common.ReactFnProps import lucuma.react.highcharts.Chart @@ -36,7 +36,7 @@ import js.JSConverters.* case class SemesterPlot( options: ObjectPlotOptions, - coords: CoordinatesAt, + coords: Coordinates, excludeIntervals: List[BoundedInterval[Instant]] ) extends ReactFnProps(SemesterPlot.component) @@ -55,7 +55,7 @@ object SemesterPlot: .useState(none[Chart_]) // chart handler (chartOpt) .useEffectStreamResourceWithDepsBy((props, _, chartOpt) => chartOpt.value.map: chart => - (props.options.semester, props.options.site, props.coords.value, Reusable.always(chart)) + (props.options.semester, props.options.site, props.coords, Reusable.always(chart)) ): (_, ctx, _) => _.map { (semester, site, coords, chart) => import ctx.given diff --git a/explore/app/src/main/scala/explore/tabs/ObsTabTiles.scala b/explore/app/src/main/scala/explore/tabs/ObsTabTiles.scala index a46cef515a..1fe573857a 100644 --- a/explore/app/src/main/scala/explore/tabs/ObsTabTiles.scala +++ b/explore/app/src/main/scala/explore/tabs/ObsTabTiles.scala @@ -56,15 +56,15 @@ import lucuma.core.enums.CalibrationRole import lucuma.core.enums.ProgramType import lucuma.core.enums.Site import lucuma.core.math.Angle +import lucuma.core.math.Coordinates import lucuma.core.math.Offset import lucuma.core.math.skycalc.averageParallacticAngle import lucuma.core.model.ConstraintSet -import lucuma.core.model.CoordinatesAt import lucuma.core.model.IntCentiPercent -import lucuma.core.model.ObjectTracking import lucuma.core.model.PosAngleConstraint import lucuma.core.model.Program import lucuma.core.model.Target +import lucuma.core.model.Tracking import lucuma.core.optics.syntax.lens.* import lucuma.core.syntax.all.* import lucuma.core.util.TimeSpan @@ -117,7 +117,7 @@ case class ObsTabTiles( val obsAttachmentAssignments: ObsAttachmentAssignmentMap = programSummaries.obsAttachmentAssignments - val asterismTracking: Option[ObjectTracking] = + val asterismTracking: Option[Tracking] = observation.get.asterismTracking(obsTargets) val posAngleConstraint: PosAngleConstraint = observation.get.posAngleConstraint @@ -133,7 +133,7 @@ case class ObsTabTiles( NonEmptyList.fromList: obsTargets.toList.map((_, t) => t) - def targetCoords(obsTime: Instant): Option[CoordinatesAt] = + def targetCoords(obsTime: Instant): Option[Coordinates] = asterismAsNel .flatMap(asterismNel => asterismNel.baseTracking.flatMap(_.at(obsTime))) @@ -150,7 +150,7 @@ case class ObsTabTiles( ) def obsIQLikelihood(obsTime: Instant): Option[IntCentiPercent] = - (centralWavelength, targetCoords(obsTime).map(_.value.dec), site).mapN((cw, dec, site) => + (centralWavelength, targetCoords(obsTime).map(_.dec), site).mapN((cw, dec, site) => site .minimumAirMassFor(dec) .fold(IntCentiPercent.Min): airMass => @@ -158,7 +158,7 @@ case class ObsTabTiles( ) def obsConditionsLikelihood(obsTime: Instant): Option[IntCentiPercent] = - (centralWavelength, targetCoords(obsTime).map(_.value.dec), site).mapN((cw, dec, site) => + (centralWavelength, targetCoords(obsTime).map(_.dec), site).mapN((cw, dec, site) => conditionsLikelihood( constraintSet.get.skyBackground, constraintSet.get.cloudExtinction.toCloudExtinction, diff --git a/explore/app/src/main/scala/explore/tabs/TargetTabContents.scala b/explore/app/src/main/scala/explore/tabs/TargetTabContents.scala index a557279682..ad66df4a91 100644 --- a/explore/app/src/main/scala/explore/tabs/TargetTabContents.scala +++ b/explore/app/src/main/scala/explore/tabs/TargetTabContents.scala @@ -38,9 +38,9 @@ import japgolly.scalajs.react.* import japgolly.scalajs.react.extra.router.SetRouteVia import japgolly.scalajs.react.vdom.html_<^.* import lucuma.core.enums.Site -import lucuma.core.model.ObjectTracking import lucuma.core.model.Program import lucuma.core.model.Target +import lucuma.core.model.Tracking import lucuma.core.model.User import lucuma.core.model.sequence.ExecutionDigest import lucuma.core.optics.syntax.lens.* @@ -329,7 +329,7 @@ object TargetTabContents extends TwoPanels: props.targets.get .get(targetId) .flatMap: targetWithId => - ObjectTracking + Tracking .fromTarget(targetWithId.target) .map: tracking => ObjectPlotData.Id(targetId.asRight) -> ObjectPlotData( diff --git a/explore/app/src/main/scala/explore/targeteditor/AladinCell.scala b/explore/app/src/main/scala/explore/targeteditor/AladinCell.scala index 82dd7d6db9..93a3f9e17b 100644 --- a/explore/app/src/main/scala/explore/targeteditor/AladinCell.scala +++ b/explore/app/src/main/scala/explore/targeteditor/AladinCell.scala @@ -26,6 +26,7 @@ import explore.model.boopickle.* import explore.model.boopickle.CatalogPicklers.given import explore.model.enums.AgsState import explore.model.enums.Visible +import explore.model.extensions.* import explore.model.reusability.given import explore.optics.ModelOptics import japgolly.scalajs.react.* @@ -39,7 +40,7 @@ import lucuma.core.enums.PortDisposition import lucuma.core.math.Angle import lucuma.core.math.Coordinates import lucuma.core.math.Offset -import lucuma.core.model.ObjectTracking +import lucuma.core.model.Tracking import lucuma.core.model.User import lucuma.core.model.sequence.flamingos2.Flamingos2FpuMask import lucuma.react.common.* @@ -64,7 +65,7 @@ case class AladinCell( uid: User.Id, obsId: Option[Observation.Id], asterism: Asterism, - asterismTracking: ObjectTracking, + asterismTracking: Tracking, obsTime: Instant, obsConf: Option[ObsConfiguration], fullScreen: View[AladinFullScreen], @@ -352,7 +353,7 @@ object AladinCell extends ModelOptics with AladinCommon: props.asterism.focus.id, constraints, centralWavelength.value, - base.value, + base, props.sciencePositionsAt(vizTime), positions, p, diff --git a/explore/app/src/main/scala/explore/targeteditor/AladinContainer.scala b/explore/app/src/main/scala/explore/targeteditor/AladinContainer.scala index ad30553193..364bd7eb06 100644 --- a/explore/app/src/main/scala/explore/targeteditor/AladinContainer.scala +++ b/explore/app/src/main/scala/explore/targeteditor/AladinContainer.scala @@ -17,6 +17,7 @@ import explore.model.ConfigurationForVisualization import explore.model.Constants import explore.model.GlobalPreferences import explore.model.enums.Visible +import explore.model.extensions.* import explore.model.reusability.given import japgolly.scalajs.react.* import japgolly.scalajs.react.Reusability.* @@ -31,8 +32,7 @@ import lucuma.core.math.Angle import lucuma.core.math.Coordinates import lucuma.core.math.Offset import lucuma.core.math.Wavelength -import lucuma.core.model.CoordinatesAt -import lucuma.core.model.ObjectTracking +import lucuma.core.model.Tracking import lucuma.react.common.Css import lucuma.react.common.ReactFnProps import lucuma.react.resizeDetector.hooks.* @@ -49,7 +49,7 @@ import scala.concurrent.duration.* case class AladinContainer( asterism: Asterism, - asterismTracking: ObjectTracking, + asterismTracking: Tracking, obsTime: Instant, vizConf: Option[ConfigurationForVisualization], globalPreferences: GlobalPreferences, @@ -84,9 +84,9 @@ object AladinContainer extends AladinCommon { ExploreStyles.GuideSpeedSlow private def baseAndScience(p: Props) = { - val base: CoordinatesAt = p.asterismTracking + val base: Coordinates = p.asterismTracking .at(p.obsTime) - .getOrElse(CoordinatesAt(p.asterismTracking.baseCoordinates)) + .getOrElse(p.asterismTracking.baseCoordinates) val science = p.asterism.toSidereal .map(t => @@ -96,6 +96,7 @@ object AladinContainer extends AladinCommon { t.target.tracking.baseCoordinates ) ) + (base, science) } @@ -114,19 +115,19 @@ object AladinContainer extends AladinCommon { baseCoords <- useState(baseAndScience(props)) // View coordinates base coordinates with pm correction + user panning currentPos <- - useState(baseCoords.value._1.value.offsetBy(Angle.Angle0, props.options.viewOffset)) + useState(baseCoords.value._1.offsetBy(Angle.Angle0, props.options.viewOffset)) // Update coordinates if asterism or obsTime changes _ <- useEffectWithDeps((props.asterism, props.obsTime)): _ => val (base, science) = baseAndScience(props) baseCoords.setState((base, science)) *> currentPos.setState: - base.value.offsetBy(Angle.Angle0, props.options.viewOffset) + base.offsetBy(Angle.Angle0, props.options.viewOffset) // Ref to the aladin component aladinRef <- useState(none[Aladin]) // If view offset changes upstream to zero, redraw _ <- useEffectWithDeps((baseCoords, props.options.viewOffset)): (_, offset) => - val newCoords = baseCoords.value._1.value.offsetBy(Angle.Angle0, offset) + val newCoords = baseCoords.value._1.offsetBy(Angle.Angle0, offset) newCoords .map: coords => aladinRef.value @@ -146,7 +147,7 @@ object AladinContainer extends AladinCommon { case ObservingModeType.Flamingos2LongSlit => (Css.Empty, Flamingos2Geometry.f2Geometry( - baseCoords.value._1.value, + baseCoords.value._1, props.vizConf.flatMap(_.scienceOffsets), props.vizConf.flatMap(_.acquisitionOffsets), props.vizConf.map(_.posAngle), @@ -159,7 +160,7 @@ object AladinContainer extends AladinCommon { case ObservingModeType.GmosNorthLongSlit | ObservingModeType.GmosSouthLongSlit => (Css.Empty, GmosGeometry.gmosGeometry( - baseCoords.value._1.value, + baseCoords.value._1, props.vizConf.flatMap(_.scienceOffsets), props.vizConf.flatMap(_.acquisitionOffsets), props.vizConf.map(_.posAngle), @@ -172,7 +173,7 @@ object AladinContainer extends AladinCommon { case ObservingModeType.GmosNorthImaging | ObservingModeType.GmosSouthImaging => (VisualizationStyles.GmosCcdVisible, GmosGeometry.gmosGeometry( - baseCoords.value._1.value, + baseCoords.value._1, props.vizConf.flatMap(_.scienceOffsets), props.vizConf.flatMap(_.acquisitionOffsets), props.vizConf.map(_.posAngle), @@ -285,16 +286,16 @@ object AladinContainer extends AladinCommon { .flatten // Use fov from aladin - fov <- useState(none[Fov]) + fov <- useState(none[Fov]) // Survey - survey <- useState( - props.vizConf - .flatMap(_.centralWavelength) - .map(w => surveyForWavelength(w.value)) - .getOrElse(ImageSurvey.DSS) - ) + survey <- useState( + props.vizConf + .flatMap(_.centralWavelength) + .map(w => surveyForWavelength(w.value)) + .getOrElse(ImageSurvey.DSS) + ) // Update survey if conf changes - _ <- + _ <- useEffectWithDeps(props.vizConf.flatMap(_.centralWavelength.map(_.value))): w => w.map(w => survey.setState(surveyForWavelength(w))).getOrEmpty } yield { @@ -306,7 +307,7 @@ object AladinContainer extends AladinCommon { */ def onPositionChanged(u: PositionChanged): Callback = { val viewCoords = Coordinates(u.ra, u.dec) - val viewOffset = baseCoordinates.value.diff(viewCoords).offset + val viewOffset = baseCoordinates.diff(viewCoords).offset currentPos.setState(Some(viewCoords)) *> props.updateViewOffset(viewOffset) } @@ -334,14 +335,14 @@ object AladinContainer extends AladinCommon { val baseCoordinatesForAladin: String = currentPos.value .map(Coordinates.fromHmsDms.reverseGet) - .getOrElse(Coordinates.fromHmsDms.reverseGet(baseCoordinates.value)) + .getOrElse(Coordinates.fromHmsDms.reverseGet(baseCoordinates)) val basePosition = List( - SVGTarget.CrosshairTarget(baseCoordinates.value, Css.Empty, 10), - SVGTarget.CircleTarget(baseCoordinates.value, ExploreStyles.BaseTarget, 3), + SVGTarget.CrosshairTarget(baseCoordinates, Css.Empty, 10), + SVGTarget.CircleTarget(baseCoordinates, ExploreStyles.BaseTarget, 3), SVGTarget.LineTo( - baseCoordinates.value, + baseCoordinates, props.asterismTracking.baseCoordinates, ExploreStyles.PMCorrectionLine ) @@ -376,7 +377,7 @@ object AladinContainer extends AladinCommon { for { idx <- refineV[NonNegative](i).toOption gs <- props.selectedGuideStar - c <- baseCoordinates.value.offsetBy(gs.posAngle, o) if visible + c <- baseCoordinates.offsetBy(gs.posAngle, o) if visible } yield SVGTarget.OffsetIndicator(c, idx, o, oType, css, 4) } @@ -401,7 +402,7 @@ object AladinContainer extends AladinCommon { (acquisitionOffsetIndicators |+| scienceOffsetIndicators).flattenOption val screenOffset = - currentPos.value.map(_.diff(baseCoordinates.value).offset).getOrElse(Offset.Zero) + currentPos.value.map(_.diff(baseCoordinates).offset).getOrElse(Offset.Zero) // Use explicit reusability that excludes target changes given Reusability[AladinOptions] = reusability.withoutTarget @@ -423,7 +424,7 @@ object AladinContainer extends AladinCommon { _, _, screenOffset, - baseCoordinates.value, + baseCoordinates, // Order matters candidates ++ basePosition ++ sciencePositions ++ offsetTargets ) diff --git a/explore/common/src/main/scala/explore/model/reusability.scala b/explore/common/src/main/scala/explore/model/reusability.scala index a1eefdc072..90a7692b52 100644 --- a/explore/common/src/main/scala/explore/model/reusability.scala +++ b/explore/common/src/main/scala/explore/model/reusability.scala @@ -41,9 +41,9 @@ import lucuma.core.math.WavelengthDither import lucuma.core.model.Configuration import lucuma.core.model.ConfigurationRequest import lucuma.core.model.ExposureTimeMode -import lucuma.core.model.ObjectTracking import lucuma.core.model.PosAngleConstraint import lucuma.core.model.TimingWindow +import lucuma.core.model.Tracking import lucuma.core.model.sequence.Atom import lucuma.itc.ItcCcd import lucuma.itc.client.GraphResult @@ -121,7 +121,7 @@ object reusability: given Reusability[ItcInstrumentConfig] = Reusability.byEq given Reusability[ConfigSelection] = Reusability.byEq given Reusability[CentralWavelength] = Reusability.byEq - given Reusability[ObjectTracking] = Reusability.byEq + given Reusability[Tracking] = Reusability.byEq given Reusability[Asterism] = Reusability.byEq[Asterism] given Reusability[TargetWithOptId] = Reusability.byEq given Reusability[GlobalPreferences] = Reusability.byEq diff --git a/explore/model-tests/shared/src/test/scala/explore/model/boopickle/BoopickleSuite.scala b/explore/model-tests/shared/src/test/scala/explore/model/boopickle/BoopickleSuite.scala index 9b5b17e798..230ed59abb 100644 --- a/explore/model-tests/shared/src/test/scala/explore/model/boopickle/BoopickleSuite.scala +++ b/explore/model-tests/shared/src/test/scala/explore/model/boopickle/BoopickleSuite.scala @@ -23,11 +23,11 @@ import lucuma.core.math.arb.ArbRightAscension.given import lucuma.core.math.arb.ArbWavelength.given import lucuma.core.model.ConstraintSet import lucuma.core.model.ElevationRange -import lucuma.core.model.SiderealTracking +import lucuma.core.model.Tracking import lucuma.core.model.UnnormalizedSED import lucuma.core.model.arb.ArbConstraintSet.given import lucuma.core.model.arb.ArbElevationRange.given -import lucuma.core.model.arb.ArbSiderealTracking.given +import lucuma.core.model.arb.ArbTracking.given import lucuma.core.model.arb.ArbUnnormalizedSED.given class BoopickleSuite @@ -46,7 +46,7 @@ class BoopickleSuite checkAll("Pickler[ProperMotion]", PicklerTests[ProperMotion].pickler) checkAll("Pickler[RadialVelocity]", PicklerTests[RadialVelocity].pickler) checkAll("Pickler[Parallax]", PicklerTests[Parallax].pickler) - checkAll("Pickler[SiderealTracking]", PicklerTests[SiderealTracking].pickler) + checkAll("Pickler[Tracking]", PicklerTests[Tracking].pickler) checkAll("Pickler[GuideStarCandidate]", PicklerTests[GuideStarCandidate].pickler) checkAll("Pickler[ElevationRange]", PicklerTests[ElevationRange].pickler) checkAll("Pickler[ConstraintSet]", PicklerTests[ConstraintSet].pickler) diff --git a/explore/model/shared/src/main/scala/explore/events/CatalogMessage.scala b/explore/model/shared/src/main/scala/explore/events/CatalogMessage.scala index e59396f69b..035eda60db 100644 --- a/explore/model/shared/src/main/scala/explore/events/CatalogMessage.scala +++ b/explore/model/shared/src/main/scala/explore/events/CatalogMessage.scala @@ -8,7 +8,7 @@ import boopickle.Pickler import explore.model.boopickle.CatalogPicklers import lucuma.ags.GuideStarCandidate import lucuma.core.enums.ObservingModeType -import lucuma.core.model.ObjectTracking +import lucuma.core.model.Tracking import workers.WorkerRequest import java.time.Duration @@ -21,7 +21,7 @@ object CatalogMessage extends CatalogPicklers { } case class GSRequest( - tracking: ObjectTracking, + tracking: Tracking, vizTime: Instant, obsModeType: ObservingModeType ) extends Request { diff --git a/explore/model/shared/src/main/scala/explore/model/Asterism.scala b/explore/model/shared/src/main/scala/explore/model/Asterism.scala index d6a1170475..567fcbecce 100644 --- a/explore/model/shared/src/main/scala/explore/model/Asterism.scala +++ b/explore/model/shared/src/main/scala/explore/model/Asterism.scala @@ -9,9 +9,9 @@ import cats.derived.* import cats.syntax.all.* import explore.model.extensions.* import lucuma.core.data.Zipper -import lucuma.core.model.ObjectTracking import lucuma.core.model.SiderealTracking import lucuma.core.model.Target +import lucuma.core.model.Tracking import lucuma.schemas.model.* import monocle.* @@ -52,8 +52,8 @@ case class Asterism(private val targets: Zipper[TargetWithId]) derives Eq { def focusOn(tid: Target.Id): Asterism = targets.findFocus(_.id === tid).map(Asterism.apply).getOrElse(this) - def baseTracking: Option[ObjectTracking] = - ObjectTracking.fromAsterism(targets.toNel.map(_.target)) + def baseTracking: Option[Tracking] = + Tracking.fromAsterism(targets.toNel.map(_.target)) def hasId(id: Target.Id): Boolean = targets.exists(_.id === id) } diff --git a/explore/model/shared/src/main/scala/explore/model/Observation.scala b/explore/model/shared/src/main/scala/explore/model/Observation.scala index d6c7b17b59..924a6b1b73 100644 --- a/explore/model/shared/src/main/scala/explore/model/Observation.scala +++ b/explore/model/shared/src/main/scala/explore/model/Observation.scala @@ -31,7 +31,6 @@ import lucuma.core.model.Attachment import lucuma.core.model.Configuration import lucuma.core.model.ConfigurationRequest import lucuma.core.model.ConstraintSet -import lucuma.core.model.ObjectTracking import lucuma.core.model.ObservationReference import lucuma.core.model.ObservationValidation import lucuma.core.model.ObservationWorkflow @@ -39,6 +38,7 @@ import lucuma.core.model.PosAngleConstraint import lucuma.core.model.SourceProfile import lucuma.core.model.Target import lucuma.core.model.TimingWindow +import lucuma.core.model.Tracking import lucuma.core.model.sequence.ExecutionDigest import lucuma.core.model.sequence.gmos.GmosCcdMode import lucuma.core.optics.syntax.lens.* @@ -288,13 +288,13 @@ case class Observation( if (newConfigurationRequestApplies(request.configuration)) updateToPending(request.id) else this - def asterismTracking(allTargets: TargetList): Option[ObjectTracking] = + def asterismTracking(allTargets: TargetList): Option[Tracking] = NonEmptyList .fromList: scienceTargetIds.toList .map(id => allTargets.get(id).map(_.target)) .flattenOption - .flatMap(ObjectTracking.fromAsterism(_)) + .flatMap(Tracking.fromAsterism(_)) def hasTargetOfOpportunity(allTargets: TargetList): Boolean = scienceTargetIds.toList diff --git a/explore/model/shared/src/main/scala/explore/model/boopickle/CatalogPickler.scala b/explore/model/shared/src/main/scala/explore/model/boopickle/CatalogPickler.scala index e56b33aacf..abae9e5932 100644 --- a/explore/model/shared/src/main/scala/explore/model/boopickle/CatalogPickler.scala +++ b/explore/model/shared/src/main/scala/explore/model/boopickle/CatalogPickler.scala @@ -18,9 +18,16 @@ import lucuma.core.math.Coordinates import lucuma.core.math.Epoch import lucuma.core.math.Parallax import lucuma.core.math.ProperMotion -import lucuma.core.model.ObjectTracking +import lucuma.core.model.CompositeTracking +import lucuma.core.model.ConstantTracking +import lucuma.core.model.EphemerisCoordinates +import lucuma.core.model.EphemerisTracking import lucuma.core.model.SiderealTracking +import lucuma.core.model.Tracking import lucuma.core.model.sequence.flamingos2.Flamingos2FpuMask +import lucuma.core.util.Timestamp + +import scala.collection.immutable.TreeMap // Boopicklers for catalog related types trait CatalogPicklers extends CommonPicklers: @@ -58,8 +65,6 @@ trait CatalogPicklers extends CommonPicklers: given Pickler[Parallax] = transformPickler(Parallax.fromMicroarcseconds)(_.μas.value.value) - given Pickler[SiderealTracking] = generatePickler - given Pickler[GuideStarCandidate] = generatePickler given Pickler[AgsPosition] = generatePickler @@ -91,16 +96,30 @@ trait CatalogPicklers extends CommonPicklers: given Pickler[AgsAnalysis.Usable] = generatePickler - given Pickler[ObjectTracking.SiderealObjectTracking] = generatePickler + given Pickler[SiderealTracking] = generatePickler + + given Pickler[CompositeTracking] = generatePickler - given Pickler[ObjectTracking.SiderealAsterismTracking] = generatePickler + given Pickler[ConstantTracking] = generatePickler - given Pickler[ObjectTracking.ConstantTracking] = generatePickler + given Pickler[EphemerisCoordinates] = generatePickler + + given [K: Pickler: Ordering, V: Pickler]: Pickler[TreeMap[K, V]] = + transformPickler((m: Map[K, V]) => TreeMap.empty[K, V] ++ m)(_.toMap) + + import _root_.cats.Order.given + // summon[Ordering[lucuma.core.util.Timestamp]] + + given Pickler[EphemerisTracking] = + transformPickler((m: TreeMap[Timestamp, EphemerisCoordinates]) => EphemerisTracking(m.toSeq*))( + _.toMap + ) - given Pickler[ObjectTracking] = - compositePickler[ObjectTracking] - .addConcreteType[ObjectTracking.SiderealObjectTracking] - .addConcreteType[ObjectTracking.SiderealAsterismTracking] - .addConcreteType[ObjectTracking.ConstantTracking] + given Pickler[Tracking] = + compositePickler[Tracking] + .addConcreteType[SiderealTracking] + .addConcreteType[CompositeTracking] + .addConcreteType[ConstantTracking] + .addConcreteType[EphemerisTracking] object CatalogPicklers extends CatalogPicklers diff --git a/explore/model/shared/src/main/scala/explore/model/boopickle/CommonPicklers.scala b/explore/model/shared/src/main/scala/explore/model/boopickle/CommonPicklers.scala index 021d011f09..010fb5d8dc 100644 --- a/explore/model/shared/src/main/scala/explore/model/boopickle/CommonPicklers.scala +++ b/explore/model/shared/src/main/scala/explore/model/boopickle/CommonPicklers.scala @@ -35,6 +35,7 @@ import lucuma.core.model.Target import lucuma.core.util.Enumerated import lucuma.core.util.NewType import lucuma.core.util.TimeSpan +import lucuma.core.util.Timestamp import lucuma.schemas.model.CentralWavelength import org.http4s.Uri @@ -204,6 +205,8 @@ trait CommonPicklers { SignalToNoise.FromBigDecimalExact.getOption(v).getOrElse(sys.error("Cannot unpickle")) )(_.toBigDecimal) + given Pickler[Timestamp] = + transformPickler((instant: Instant) => Timestamp.fromInstant(instant).get)(_.toInstant) } object CommonPicklers extends CommonPicklers diff --git a/explore/model/shared/src/main/scala/explore/model/boopickle/ItcPickler.scala b/explore/model/shared/src/main/scala/explore/model/boopickle/ItcPickler.scala index ed1aee89a2..5343e41185 100644 --- a/explore/model/shared/src/main/scala/explore/model/boopickle/ItcPickler.scala +++ b/explore/model/shared/src/main/scala/explore/model/boopickle/ItcPickler.scala @@ -41,7 +41,6 @@ import lucuma.core.model.UnnormalizedSED import lucuma.core.model.sequence.gmos.GmosCcdMode import lucuma.core.util.Gid import lucuma.core.util.Of -import lucuma.core.util.Timestamp import lucuma.itc.Error import lucuma.itc.IntegrationTime import lucuma.itc.ItcAxis @@ -113,10 +112,6 @@ trait ItcPicklers extends CommonPicklers { given Pickler[ModeAO] = picklerNewType(ModeAO) - import java.time.Instant - given Pickler[Timestamp] = - transformPickler((instant: Instant) => Timestamp.fromInstant(instant).get)(_.toInstant) - given [A: Gid]: Pickler[A] = transformPickler((str: String) => Gid[A].fromString.getOption(str).get)(_.toString) diff --git a/explore/model/shared/src/main/scala/explore/model/extensions.scala b/explore/model/shared/src/main/scala/explore/model/extensions.scala index 2d8961dbc9..25def7f688 100644 --- a/explore/model/shared/src/main/scala/explore/model/extensions.scala +++ b/explore/model/shared/src/main/scala/explore/model/extensions.scala @@ -13,9 +13,11 @@ import lucuma.core.math.Declination import lucuma.core.math.Epoch import lucuma.core.math.Region import lucuma.core.math.RightAscension -import lucuma.core.model.ObjectTracking +import lucuma.core.model.CompositeTracking +import lucuma.core.model.ConstantTracking import lucuma.core.model.SiderealTracking import lucuma.core.model.Target +import lucuma.core.model.Tracking import lucuma.schemas.model.SiderealTargetWithId import lucuma.schemas.model.TargetWithId @@ -59,8 +61,8 @@ object extensions: TargetWithId.target.replace(targetWithId.target.at(i))(targetWithId) extension (targets: NonEmptyList[TargetWithId]) - def baseTracking: Option[ObjectTracking] = - ObjectTracking.fromAsterism(targets.map(_.target)) + def baseTracking: Option[Tracking] = + Tracking.fromAsterism(targets.map(_.target)) def toSidereal: List[SiderealTargetWithId] = targets.toList.map(_.toSidereal).flattenOption @@ -69,11 +71,11 @@ object extensions: // ToO as a ToO and returns the region of the first ToO it finds. Since we "shouldn't" // have asterisms with multiple ToOs, this is probably fine. def coordsOrRegionAt(vizTime: Option[Instant]): Option[Either[Coordinates, Region]] = - ObjectTracking + Tracking .orRegionFromAsterism(targets.map(_.target)) match - case Left(ot) => - vizTime.fold(ot.baseCoordinates.asLeft.some)(v => ot.at(v).map(_.value.asLeft)) - case Right(region) => region.asRight.some + case Left(tracking) => + vizTime.fold(tracking.baseCoordinates.asLeft.some)(v => tracking.at(v).map(_.asLeft)) + case Right(region) => region.asRight.some def isMixed: Boolean = targets @@ -115,3 +117,10 @@ object extensions: case None => "" case Some(Left(dec)) => f(dec) case Some(Right(arc: Arc[Declination])) => arc.format(f) + + extension (tracking: Tracking) + def baseCoordinates: Coordinates = tracking match + case SiderealTracking(baseCoordinates, _, _, _, _) => baseCoordinates + case ConstantTracking(coordinates) => coordinates + case CompositeTracking(nel) => Coordinates.centerOf(nel.map(_.baseCoordinates)) + case _ => sys.error("Non sidereals are not supported") diff --git a/explore/workers/src/main/scala/workers/AgsServer.scala b/explore/workers/src/main/scala/workers/AgsServer.scala index e168b504ca..e7c320dd32 100644 --- a/explore/workers/src/main/scala/workers/AgsServer.scala +++ b/explore/workers/src/main/scala/workers/AgsServer.scala @@ -23,7 +23,7 @@ object AgsServer extends WorkerServer[IO, AgsMessage.Request] { @JSExport def runWorker(): Unit = run.unsafeRunAndForget() - private val AgsCacheVersion: Int = 18 + private val AgsCacheVersion: Int = 19 private val CacheRetention: Duration = Duration.ofDays(60) diff --git a/explore/workers/src/main/scala/workers/CatalogCache.scala b/explore/workers/src/main/scala/workers/CatalogCache.scala index 06cacb0aac..e60a09f7df 100644 --- a/explore/workers/src/main/scala/workers/CatalogCache.scala +++ b/explore/workers/src/main/scala/workers/CatalogCache.scala @@ -26,7 +26,7 @@ import java.time.temporal.ChronoUnit trait CatalogQuerySettings { private val MaxTargets: Int = 100 - private val CacheVersion: Int = 3 + private val CacheVersion: Int = 4 protected given Hash[Coordinates] = Hash.fromUniversalHashCode protected given ADQLInterpreter = ADQLInterpreter.nTarget(MaxTargets) @@ -66,7 +66,7 @@ trait CatalogCache extends CatalogIDB { // Make a query based on two coordinates of the base of an asterism over a year val query: CoordinatesRangeQueryByADQL = CoordinatesRangeQueryByADQL( - NonEmptyList.of(a.value, b.value), + NonEmptyList.of(a, b), candidatesArea, brightnessConstraints.some ) diff --git a/project/Versions.scala b/project/Versions.scala index 01df72eeb2..1d367b7faa 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -35,7 +35,7 @@ object Versions { val log4s = "1.10.0" val logback = "1.5.20" val lucumaBC = "0.4.0" - val lucumaCore = "0.147.2" + val lucumaCore = "0.149.0" val lucumaPrimeStyles = "0.5.0" val lucumaReact = "0.85.3" val lucumaServers = "0.51.1"