1   /* Copyright 2002-2025 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.files.ccsds.ndm.odm.ocm;
18  
19  import org.orekit.files.ccsds.definitions.Units;
20  import org.orekit.files.ccsds.utils.ContextBinding;
21  import org.orekit.files.ccsds.utils.lexical.ParseToken;
22  import org.orekit.files.ccsds.utils.lexical.TokenType;
23  import org.orekit.utils.units.Unit;
24  
25  
26  /** Keys for {@link OrbitPhysicalProperties physical properties data} entries.
27   * @author Luc Maisonobe
28   * @since 11.0
29   */
30  public enum OrbitPhysicalPropertiesKey {
31  
32      /** Comment entry. */
33      COMMENT((token, context, container) ->
34              token.getType() == TokenType.ENTRY ? container.addComment(token.getContentAsNormalizedString()) : true),
35  
36      /** Satellite manufacturer name. */
37      MANUFACTURER((token, context, container) -> token.processAsFreeTextString(container::setManufacturer)),
38  
39      /** Bus model name. */
40      BUS_MODEL((token, context, container) -> token.processAsFreeTextString(container::setBusModel)),
41  
42      /** Other space objects this object is docked to. */
43      DOCKED_WITH((token, context, container) -> token.processAsFreeTextList(container::setDockedWith)),
44  
45      /** Attitude-independent drag cross-sectional area, not already into attitude-dependent area along OEB. */
46      DRAG_CONST_AREA((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
47                                                                           container::setDragConstantArea)),
48  
49      /** Nominal drag coefficient. */
50      DRAG_COEFF_NOM((token, context, container) -> token.processAsDouble(Unit.ONE, context.getParsedUnitsBehavior(),
51                                                                          container::setDragCoefficient)),
52  
53      /** Drag coefficient 1σ uncertainty. */
54      DRAG_UNCERTAINTY((token, context, container) -> token.processAsDouble(Unit.PERCENT, context.getParsedUnitsBehavior(),
55                                                                            container::setDragUncertainty)),
56  
57      /** Total mass at beginning of life. */
58      INITIAL_WET_MASS((token, context, container) -> token.processAsDouble(Unit.KILOGRAM, context.getParsedUnitsBehavior(),
59                                                                            container::setInitialWetMass)),
60  
61      /** Total mass at T₀. */
62      WET_MASS((token, context, container) -> token.processAsDouble(Unit.KILOGRAM, context.getParsedUnitsBehavior(),
63                                                                    container::setWetMass)),
64  
65      /** Mass without propellant. */
66      DRY_MASS((token, context, container) -> token.processAsDouble(Unit.KILOGRAM, context.getParsedUnitsBehavior(),
67                                                                    container::setDryMass)),
68  
69      /** Optimally Enclosing Box parent reference frame. */
70      OEB_PARENT_FRAME((token, context, container) -> token.processAsFrame(container::setOebParentFrame, context, true, true, false)),
71  
72      /** Optimally Enclosing Box parent reference frame epoch. */
73      OEB_PARENT_FRAME_EPOCH((token, context, container) -> token.processAsDate(container::setOebParentFrameEpoch, context)),
74  
75      /** Quaternion defining Optimally Enclosing Box (first vectorial component). */
76      OEB_Q1((token, context, container) -> token.processAsIndexedDouble(1, Unit.ONE, context.getParsedUnitsBehavior(),
77                                                                         container::setOebQ)),
78  
79      /** Quaternion defining Optimally Enclosing Box (second vectorial component). */
80      OEB_Q2((token, context, container) -> token.processAsIndexedDouble(2, Unit.ONE, context.getParsedUnitsBehavior(),
81                                                                         container::setOebQ)),
82  
83      /** Quaternion defining Optimally Enclosing Box (third vectorial component). */
84      OEB_Q3((token, context, container) -> token.processAsIndexedDouble(3, Unit.ONE, context.getParsedUnitsBehavior(),
85                                                                         container::setOebQ)),
86  
87      /** Quaternion defining Optimally Enclosing Box (scalar component). */
88      OEB_QC((token, context, container) -> token.processAsIndexedDouble(0, Unit.ONE, context.getParsedUnitsBehavior(),
89                                                                         container::setOebQ)),
90  
91      /** Dimensions of Optimally Enclosing Box along X-OEB (i.e max). */
92      OEB_MAX((token, context, container) -> token.processAsDouble(Unit.METRE, context.getParsedUnitsBehavior(),
93                                                                   container::setOebMax)),
94  
95      /** Dimensions of Optimally Enclosing Box along Y-OEB (i.e intermediate). */
96      OEB_INT((token, context, container) -> token.processAsDouble(Unit.METRE, context.getParsedUnitsBehavior(),
97                                                                   container::setOebIntermediate)),
98  
99      /** Dimensions of Optimally Enclosing Box along Z-OEB (i.e min). */
100     OEB_MIN((token, context, container) -> token.processAsDouble(Unit.METRE, context.getParsedUnitsBehavior(),
101                                                                  container::setOebMin)),
102 
103     /** Cross-sectional area of Optimally Enclosing Box along X-OEB. */
104     AREA_ALONG_OEB_MAX((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
105                                                                             container::setOebAreaAlongMax)),
106 
107     /** Cross-sectional area of Optimally Enclosing Box along Y-OEB. */
108     AREA_ALONG_OEB_INT((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
109                                                                             container::setOebAreaAlongIntermediate)),
110 
111     /** Cross-sectional area of Optimally Enclosing Box along Z-OEB. */
112     AREA_ALONG_OEB_MIN((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
113                                                                             container::setOebAreaAlongMin)),
114 
115     /** Minimum cross-sectional area for collision probability estimation purposes. */
116     AREA_MIN_FOR_PC((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
117                                                                          container::setMinAreaForCollisionProbability)),
118 
119     /** Maximum cross-sectional area for collision probability estimation purposes. */
120     AREA_MAX_FOR_PC((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
121                                                                          container::setMaxAreaForCollisionProbability)),
122 
123     /** Typical (50th percentile) cross-sectional area for collision probability estimation purposes. */
124     AREA_TYP_FOR_PC((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
125                                                                          container::setTypAreaForCollisionProbability)),
126 
127     /** Typical (50th percentile) radar cross-section. */
128     RCS((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
129                                                              container::setRcs)),
130 
131     /** Minimum radar cross-section. */
132     RCS_MIN((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
133                                                                  container::setMinRcs)),
134 
135     /** Maximum radar cross-section. */
136     RCS_MAX((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
137                                                                  container::setMaxRcs)),
138 
139     /** Attitude-independent SRP area, not already into attitude-dependent area along OEB. */
140     SRP_CONST_AREA((token, context, container) -> token.processAsDouble(Units.M2, context.getParsedUnitsBehavior(),
141                                                                         container::setSrpConstantArea)),
142 
143     /** Nominal SRP coefficient. */
144     SOLAR_RAD_COEFF((token, context, container) -> token.processAsDouble(Unit.ONE, context.getParsedUnitsBehavior(),
145                                                                          container::setSrpCoefficient)),
146 
147     /** SRP coefficient 1σ uncertainty. */
148     SOLAR_RAD_UNCERTAINTY((token, context, container) -> token.processAsDouble(Unit.PERCENT, context.getParsedUnitsBehavior(),
149                                                                                container::setSrpUncertainty)),
150 
151     /** Typical (50th percentile) visual magnitude. */
152     VM_ABSOLUTE((token, context, container) -> token.processAsDouble(Unit.ONE, context.getParsedUnitsBehavior(),
153                                                                      container::setVmAbsolute)),
154 
155     /** Minimum apparent visual magnitude. */
156     VM_APPARENT_MIN((token, context, container) -> token.processAsDouble(Unit.ONE, context.getParsedUnitsBehavior(),
157                                                                          container::setVmApparentMin)),
158 
159     /** Typical (50th percentile) apparent visual magnitude. */
160     VM_APPARENT((token, context, container) -> token.processAsDouble(Unit.ONE, context.getParsedUnitsBehavior(),
161                                                                      container::setVmApparent)),
162 
163     /** Maximum apparent visual magnitude. */
164     VM_APPARENT_MAX((token, context, container) -> token.processAsDouble(Unit.ONE, context.getParsedUnitsBehavior(),
165                                                                          container::setVmApparentMax)),
166 
167     /** Typical (50th percentile) coefficient of reflectance. */
168     REFLECTANCE((token, context, container) -> token.processAsDouble(Unit.ONE, context.getParsedUnitsBehavior(),
169                                                                      container::setReflectance)),
170 
171     /** Attitude control mode. */
172     ATT_CONTROL_MODE((token, context, container) -> token.processAsFreeTextString(container::setAttitudeControlMode)),
173 
174     /** Type of actuator for attitude control. */
175     ATT_ACTUATOR_TYPE((token, context, container) -> token.processAsFreeTextString(container::setAttitudeActuatorType)),
176 
177     /** Accuracy of attitude knowledge. */
178     ATT_KNOWLEDGE((token, context, container) -> token.processAsDouble(Unit.DEGREE, context.getParsedUnitsBehavior(), container::setAttitudeKnowledgeAccuracy)),
179 
180     /** Accuracy of attitude control. */
181     ATT_CONTROL((token, context, container) -> token.processAsDouble(Unit.DEGREE, context.getParsedUnitsBehavior(), container::setAttitudeControlAccuracy)),
182 
183     /** Overall accuracy of spacecraft to maintain attitude. */
184     ATT_POINTING((token, context, container) -> token.processAsDouble(Unit.DEGREE, context.getParsedUnitsBehavior(), container::setAttitudePointingAccuracy)),
185 
186     /** Average number of orbit or attitude maneuvers per year. */
187     AVG_MANEUVER_FREQ((token, context, container) -> token.processAsDouble(Units.NB_PER_Y, context.getParsedUnitsBehavior(),
188                                                                            container::setManeuversFrequency)),
189 
190     /** Maximum composite thrust the spacecraft can accomplish. */
191     MAX_THRUST((token, context, container) -> token.processAsDouble(Unit.NEWTON, context.getParsedUnitsBehavior(),
192                                                                     container::setMaxThrust)),
193 
194     /** Total ΔV capability at beginning of life. */
195     DV_BOL((token, context, container) -> token.processAsDouble(Units.KM_PER_S, context.getParsedUnitsBehavior(),
196                                                                 container::setBolDv)),
197 
198     /** Total ΔV remaining for spacecraft. */
199     DV_REMAINING((token, context, container) -> token.processAsDouble(Units.KM_PER_S, context.getParsedUnitsBehavior(),
200                                                                       container::setRemainingDv)),
201 
202     /** Moment of inertia about X-axis. */
203     IXX((token, context, container) -> token.processAsDoublyIndexedDouble(0, 0, Units.KG_M2, context.getParsedUnitsBehavior(),
204                                                                           container::setInertiaMatrixEntry)),
205 
206     /** Moment of inertia about Y-axis. */
207     IYY((token, context, container) -> token.processAsDoublyIndexedDouble(1, 1, Units.KG_M2, context.getParsedUnitsBehavior(),
208                                                                           container::setInertiaMatrixEntry)),
209 
210     /** Moment of inertia about Z-axis. */
211     IZZ((token, context, container) -> token.processAsDoublyIndexedDouble(2, 2, Units.KG_M2, context.getParsedUnitsBehavior(),
212                                                                           container::setInertiaMatrixEntry)),
213 
214     /** Inertia cross product of the X and Y axes. */
215     IXY((token, context, container) -> token.processAsDoublyIndexedDouble(0, 1, Units.KG_M2, context.getParsedUnitsBehavior(),
216                                                                           container::setInertiaMatrixEntry)),
217 
218     /** Inertia cross product of the X and Z axes. */
219     IXZ((token, context, container) -> token.processAsDoublyIndexedDouble(0, 2, Units.KG_M2, context.getParsedUnitsBehavior(),
220                                                                           container::setInertiaMatrixEntry)),
221 
222     /** Inertia cross product of the Y and Z axes. */
223     IYZ((token, context, container) -> token.processAsDoublyIndexedDouble(1, 2, Units.KG_M2, context.getParsedUnitsBehavior(),
224                                                                           container::setInertiaMatrixEntry));
225 
226     /** Processing method. */
227     private final transient TokenProcessor processor;
228 
229     /** Simple constructor.
230      * @param processor processing method
231      */
232     OrbitPhysicalPropertiesKey(final TokenProcessor processor) {
233         this.processor = processor;
234     }
235 
236     /** Process an token.
237      * @param token token to process
238      * @param context context binding
239      * @param data data to fill
240      * @return true of token was accepted
241      */
242     public boolean process(final ParseToken token, final ContextBinding context, final OrbitPhysicalProperties data) {
243         return processor.process(token, context, data);
244     }
245 
246     /** Interface for processing one token. */
247     interface TokenProcessor {
248         /** Process one token.
249          * @param token token to process
250          * @param context context binding
251          * @param data data to fill
252          * @return true of token was accepted
253          */
254         boolean process(ParseToken token, ContextBinding context, OrbitPhysicalProperties data);
255     }
256 
257 }