1   /* Copyright 2002-2026 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  
18  package org.orekit.files.ccsds.ndm.odm.ocm;
19  
20  import java.util.ArrayList;
21  import java.util.List;
22  import java.util.Optional;
23  
24  import org.hipparchus.linear.DefaultRealMatrixChangingVisitor;
25  import org.hipparchus.linear.MatrixUtils;
26  import org.hipparchus.linear.RealMatrix;
27  import org.orekit.annotation.Nullable;
28  import org.orekit.files.ccsds.definitions.CcsdsFrameMapper;
29  import org.orekit.files.ccsds.ndm.CommonPhysicalProperties;
30  import org.orekit.frames.Frame;
31  import org.orekit.time.AbsoluteDate;
32  import org.orekit.utils.Constants;
33  
34  /** Spacecraft physical properties.
35   * @author Luc Maisonobe
36   * @since 11.0
37   */
38  public class OrbitPhysicalProperties extends CommonPhysicalProperties {
39  
40      /** Satellite manufacturer name. */
41      @Nullable
42      private String manufacturer;
43  
44      /** Bus model name. */
45      @Nullable
46      private String busModel;
47  
48      /** Other space objects this object is docked to. */
49      private List<String> dockedWith;
50  
51      /** Attitude-independent drag cross-sectional area, not already into attitude-dependent area along OEB. */
52      @Nullable
53      private Double dragConstantArea;
54  
55      /** Nominal drag coefficient. */
56      @Nullable
57      private Double dragCoefficient;
58  
59      /** Drag coefficient 1σ uncertainty. */
60      @Nullable
61      private Double dragUncertainty;
62  
63      /** Total mass at beginning of life. */
64      @Nullable
65      private Double initialWetMass;
66  
67      /** Total mass at T₀. */
68      @Nullable
69      private Double wetMass;
70  
71      /** Mass without propellant. */
72      @Nullable
73      private Double dryMass;
74  
75      /** Minimum cross-sectional area for collision probability estimation purposes. */
76      @Nullable
77      private Double minAreaForCollisionProbability;
78  
79      /** Maximum cross-sectional area for collision probability estimation purposes. */
80      @Nullable
81      private Double maxAreaForCollisionProbability;
82  
83      /** Typical (50th percentile) cross-sectional area for collision probability estimation purposes. */
84      @Nullable
85      private Double typAreaForCollisionProbability;
86  
87      /** Attitude-independent SRP area, not already into attitude-dependent area along OEB. */
88      @Nullable
89      private Double srpConstantArea;
90  
91      /** Nominal SRP coefficient. */
92      @Nullable
93      private Double srpCoefficient;
94  
95      /** SRP coefficient 1σ uncertainty. */
96      @Nullable
97      private Double srpUncertainty;
98  
99      /** Attitude control mode. */
100     @Nullable
101     private String attitudeControlMode;
102 
103     /** Type of actuator for attitude control. */
104     @Nullable
105     private String attitudeActuatorType;
106 
107     /** Accuracy of attitude knowledge. */
108     @Nullable
109     private Double attitudeKnowledgeAccuracy;
110 
111     /** Accuracy of attitude control. */
112     @Nullable
113     private Double attitudeControlAccuracy;
114 
115     /** Overall accuracy of spacecraft to maintain attitude. */
116     @Nullable
117     private Double attitudePointingAccuracy;
118 
119     /** Average average frequency of orbit or attitude maneuvers (in SI units, hence per second). */
120     @Nullable
121     private Double maneuversFrequency;
122 
123     /** Maximum composite thrust the spacecraft can accomplish. */
124     @Nullable
125     private Double maxThrust;
126 
127     /** Total ΔV capability at beginning of life. */
128     @Nullable
129     private Double bolDv;
130 
131     /** Total ΔV remaining for spacecraft. */
132     @Nullable
133     private Double remainingDv;
134 
135     /** Inertia matrix. */
136     @Nullable
137     private RealMatrix inertiaMatrix;
138 
139     /**
140      * Simple constructor.
141      *
142      * @param epochT0     T0 epoch from file metadata
143      * @param frameMapper for creating a {@link Frame}.
144      * @since 13.1.5
145      */
146     public OrbitPhysicalProperties(final AbsoluteDate epochT0,
147                                    final CcsdsFrameMapper frameMapper) {
148 
149         // Call to CommonPhysicalProperties constructor
150         super(epochT0, frameMapper);
151         // we don't call the setXxx() methods in order to avoid
152         // calling refuseFurtherComments as a side effect
153         dockedWith = new ArrayList<>();
154     }
155 
156     /** Get manufacturer name.
157      * @return manufacturer name
158      */
159     public Optional<String> getManufacturer() {
160         return Optional.ofNullable(manufacturer);
161     }
162 
163     /** Set manufacturer name.
164      * @param manufacturer manufacturer name
165      */
166     public void setManufacturer(final String manufacturer) {
167         refuseFurtherComments();
168         this.manufacturer = manufacturer;
169     }
170 
171     /** Get the bus model name.
172      * @return bus model name
173      */
174     public Optional<String> getBusModel() {
175         return Optional.ofNullable(busModel);
176     }
177 
178     /** Set the bus model name.
179      * @param busModel bus model name
180      */
181     public void setBusModel(final String busModel) {
182         refuseFurtherComments();
183         this.busModel = busModel;
184     }
185 
186     /** Get the other space objects this object is docked to.
187      * @return the oother space objects this object is docked to
188      */
189     public List<String> getDockedWith() {
190         return dockedWith;
191     }
192 
193     /** Set the other space objects this object is docked to.
194      * @param dockedWith the other space objects this object is docked to
195      */
196     public void setDockedWith(final List<String> dockedWith) {
197         refuseFurtherComments();
198         this.dockedWith = dockedWith;
199     }
200 
201     /** Get the attitude-independent drag cross-sectional area, not already into attitude-dependent area along OEB.
202      * @return attitude-independent drag cross-sectional area, not already into attitude-dependent area along OEB
203      */
204     public Optional<Double> getDragConstantArea() {
205         return Optional.ofNullable(dragConstantArea);
206     }
207 
208     /** Set the attitude-independent drag cross-sectional area, not already into attitude-dependent area along OEB.
209      * @param dragConstantArea attitude-independent drag cross-sectional area, not already into attitude-dependent area along OEB
210      */
211     public void setDragConstantArea(final double dragConstantArea) {
212         refuseFurtherComments();
213         this.dragConstantArea = dragConstantArea;
214     }
215 
216     /** Get the nominal drag coefficient.
217      * @return the nominal drag coefficient
218      */
219     public Optional<Double> getDragCoefficient() {
220         return Optional.ofNullable(dragCoefficient);
221     }
222 
223     /** Set the the nominal drag coefficient.
224      * @param dragCoefficient the nominal drag coefficient
225      */
226     public void setDragCoefficient(final double dragCoefficient) {
227         refuseFurtherComments();
228         this.dragCoefficient = dragCoefficient;
229     }
230 
231     /** Get the drag coefficient 1σ uncertainty.
232      * @return drag coefficient 1σ uncertainty (in %)
233      */
234     public Optional<Double> getDragUncertainty() {
235         return Optional.ofNullable(dragUncertainty);
236     }
237 
238     /** Set the drag coefficient 1σ uncertainty.
239      * @param dragUncertainty drag coefficient 1σ uncertainty (in %)
240      */
241     public void setDragUncertainty(final double dragUncertainty) {
242         refuseFurtherComments();
243         this.dragUncertainty = dragUncertainty;
244     }
245 
246     /** Get the total mass at beginning of life.
247      * @return total mass at beginning of life
248      */
249     public Optional<Double> getInitialWetMass() {
250         return Optional.ofNullable(initialWetMass);
251     }
252 
253     /** Set the total mass at beginning of life.
254      * @param initialWetMass total mass at beginning of life
255      */
256     public void setInitialWetMass(final double initialWetMass) {
257         refuseFurtherComments();
258         this.initialWetMass = initialWetMass;
259     }
260 
261     /** Get the total mass at T₀.
262      * @return total mass at T₀
263      */
264     public Optional<Double> getWetMass() {
265         return Optional.ofNullable(wetMass);
266     }
267 
268     /** Set the total mass at T₀.
269      * @param wetMass total mass at T₀
270      */
271     public void setWetMass(final double wetMass) {
272         refuseFurtherComments();
273         this.wetMass = wetMass;
274     }
275 
276     /** Get the mass without propellant.
277      * @return mass without propellant
278      */
279     public Optional<Double> getDryMass() {
280         return Optional.ofNullable(dryMass);
281     }
282 
283     /** Set the mass without propellant.
284      * @param dryMass mass without propellant
285      */
286     public void setDryMass(final double dryMass) {
287         refuseFurtherComments();
288         this.dryMass = dryMass;
289     }
290 
291     /** Get the minimum cross-sectional area for collision probability estimation purposes.
292      * @return minimum cross-sectional area for collision probability estimation purposes
293      */
294     public Optional<Double> getMinAreaForCollisionProbability() {
295         return Optional.ofNullable(minAreaForCollisionProbability);
296     }
297 
298     /** Set the minimum cross-sectional area for collision probability estimation purposes.
299      * @param minAreaForCollisionProbability minimum cross-sectional area for collision probability estimation purposes
300      */
301     public void setMinAreaForCollisionProbability(final double minAreaForCollisionProbability) {
302         refuseFurtherComments();
303         this.minAreaForCollisionProbability = minAreaForCollisionProbability;
304     }
305 
306     /** Get the maximum cross-sectional area for collision probability estimation purposes.
307      * @return maximum cross-sectional area for collision probability estimation purposes
308      */
309     public Optional<Double> getMaxAreaForCollisionProbability() {
310         return Optional.ofNullable(maxAreaForCollisionProbability);
311     }
312 
313     /** Set the maximum cross-sectional area for collision probability estimation purposes.
314      * @param maxAreaForCollisionProbability maximum cross-sectional area for collision probability estimation purposes
315      */
316     public void setMaxAreaForCollisionProbability(final double maxAreaForCollisionProbability) {
317         refuseFurtherComments();
318         this.maxAreaForCollisionProbability = maxAreaForCollisionProbability;
319     }
320 
321     /** Get the typical (50th percentile) cross-sectional area for collision probability estimation purposes.
322      * @return typical (50th percentile) cross-sectional area for collision probability estimation purposes
323      */
324     public Optional<Double> getTypAreaForCollisionProbability() {
325         return Optional.ofNullable(typAreaForCollisionProbability);
326     }
327 
328     /** Get the typical (50th percentile) cross-sectional area for collision probability estimation purposes.
329      * @param typAreaForCollisionProbability typical (50th percentile) cross-sectional area for collision probability estimation purposes
330      */
331     public void setTypAreaForCollisionProbability(final double typAreaForCollisionProbability) {
332         refuseFurtherComments();
333         this.typAreaForCollisionProbability = typAreaForCollisionProbability;
334     }
335 
336     /** Get the attitude-independent SRP area, not already into attitude-dependent area along OEB.
337      * @return attitude-independent SRP area, not already into attitude-dependent area along OEB
338      */
339     public Optional<Double> getSrpConstantArea() {
340         return Optional.ofNullable(srpConstantArea);
341     }
342 
343     /** Set the attitude-independent SRP area, not already into attitude-dependent area along OEB.
344      * @param srpConstantArea attitude-independent SRP area, not already into attitude-dependent area along OEB
345      */
346     public void setSrpConstantArea(final double srpConstantArea) {
347         refuseFurtherComments();
348         this.srpConstantArea = srpConstantArea;
349     }
350 
351     /** Get the nominal SRP coefficient.
352      * @return nominal SRP coefficient
353      */
354     public Optional<Double> getSrpCoefficient() {
355         return Optional.ofNullable(srpCoefficient);
356     }
357 
358     /** Set the nominal SRP coefficient.
359      * @param srpCoefficient nominal SRP coefficient
360      */
361     public void setSrpCoefficient(final double srpCoefficient) {
362         refuseFurtherComments();
363         this.srpCoefficient = srpCoefficient;
364     }
365 
366     /** Get the SRP coefficient 1σ uncertainty.
367      * @return SRP coefficient 1σ uncertainty
368      */
369     public Optional<Double> getSrpUncertainty() {
370         return Optional.ofNullable(srpUncertainty);
371     }
372 
373     /** Set the SRP coefficient 1σ uncertainty.
374      * @param srpUncertainty SRP coefficient 1σ uncertainty.
375      */
376     public void setSrpUncertainty(final double srpUncertainty) {
377         refuseFurtherComments();
378         this.srpUncertainty = srpUncertainty;
379     }
380 
381     /** Get the attitude control mode.
382      * @return attitude control mode
383      */
384     public Optional<String> getAttitudeControlMode() {
385         return Optional.ofNullable(attitudeControlMode);
386     }
387 
388     /** Set the attitude control mode.
389      * @param attitudeControlMode attitude control mode
390      */
391     public void setAttitudeControlMode(final String attitudeControlMode) {
392         refuseFurtherComments();
393         this.attitudeControlMode = attitudeControlMode;
394     }
395 
396     /** Get the type of actuator for attitude control.
397      * @return type of actuator for attitude control
398      */
399     public Optional<String> getAttitudeActuatorType() {
400         return Optional.ofNullable(attitudeActuatorType);
401     }
402 
403     /** Set the type of actuator for attitude control.
404      * @param attitudeActuatorType type of actuator for attitude control
405      */
406     public void setAttitudeActuatorType(final String attitudeActuatorType) {
407         refuseFurtherComments();
408         this.attitudeActuatorType = attitudeActuatorType;
409     }
410 
411     /** Get the accuracy of attitude knowledge.
412      * @return accuracy of attitude knowledge
413      */
414     public Optional<Double> getAttitudeKnowledgeAccuracy() {
415         return Optional.ofNullable(attitudeKnowledgeAccuracy);
416     }
417 
418     /** Set the accuracy of attitude knowledge.
419      * @param attitudeKnowledgeAccuracy accuracy of attitude knowledge
420      */
421     public void setAttitudeKnowledgeAccuracy(final double attitudeKnowledgeAccuracy) {
422         refuseFurtherComments();
423         this.attitudeKnowledgeAccuracy = attitudeKnowledgeAccuracy;
424     }
425 
426     /** Get the accuracy of attitude control.
427      * @return accuracy of attitude control
428      */
429     public Optional<Double> getAttitudeControlAccuracy() {
430         return Optional.ofNullable(attitudeControlAccuracy);
431     }
432 
433     /** Set the accuracy of attitude control.
434      * @param attitudeControlAccuracy accuracy of attitude control
435      */
436     public void setAttitudeControlAccuracy(final double attitudeControlAccuracy) {
437         refuseFurtherComments();
438         this.attitudeControlAccuracy = attitudeControlAccuracy;
439     }
440 
441     /** Get the overall accuracy of spacecraft to maintain attitude.
442      * @return overall accuracy of spacecraft to maintain attitude
443      */
444     public Optional<Double> getAttitudePointingAccuracy() {
445         return Optional.ofNullable(attitudePointingAccuracy);
446     }
447 
448     /** Set the overall accuracy of spacecraft to maintain attitude.
449      * @param attitudePointingAccuracy overall accuracy of spacecraft to maintain attitude
450      */
451     public void setAttitudePointingAccuracy(final double attitudePointingAccuracy) {
452         refuseFurtherComments();
453         this.attitudePointingAccuracy = attitudePointingAccuracy;
454     }
455 
456     /** Get the average number of orbit or attitude maneuvers per year.
457      * @return average number of orbit or attitude maneuvers per year.
458      */
459     public Optional<Double> getManeuversPerYear() {
460         return maneuversFrequency != null ? Optional.of(maneuversFrequency * Constants.JULIAN_YEAR) : Optional.empty();
461     }
462 
463     /** Get the average frequency of orbit or attitude maneuvers (in SI units, hence per second).
464      * @return average frequency of orbit or attitude maneuvers (in SI units, hence per second).
465      */
466     public Optional<Double> getManeuversFrequency() {
467         return Optional.ofNullable(maneuversFrequency);
468     }
469 
470     /** Set the average frequency of orbit or attitude maneuvers (in SI units, hence per second).
471      * @param maneuversFrequency average frequency of orbit or attitude (in SI units, hence per second).
472      */
473     public void setManeuversFrequency(final double maneuversFrequency) {
474         refuseFurtherComments();
475         this.maneuversFrequency = maneuversFrequency;
476     }
477 
478     /** Get the maximum composite thrust the spacecraft can accomplish.
479      * @return maximum composite thrust the spacecraft can accomplish
480      */
481     public Optional<Double> getMaxThrust() {
482         return Optional.ofNullable(maxThrust);
483     }
484 
485     /** Set the maximum composite thrust the spacecraft can accomplish.
486      * @param maxThrust maximum composite thrust the spacecraft can accomplish
487      */
488     public void setMaxThrust(final double maxThrust) {
489         refuseFurtherComments();
490         this.maxThrust = maxThrust;
491     }
492 
493     /** Get the total ΔV capability at beginning of life.
494      * @return total ΔV capability at beginning of life
495      */
496     public Optional<Double> getBolDv() {
497         return Optional.ofNullable(bolDv);
498     }
499 
500     /** Set the total ΔV capability at beginning of life.
501      * @param bolDv total ΔV capability at beginning of life
502      */
503     public void setBolDv(final double bolDv) {
504         refuseFurtherComments();
505         this.bolDv = bolDv;
506     }
507 
508     /** Get the total ΔV remaining for spacecraft.
509      * @return total ΔV remaining for spacecraft
510      */
511     public Optional<Double> getRemainingDv() {
512         return Optional.ofNullable(remainingDv);
513     }
514 
515     /** Set the total ΔV remaining for spacecraft.
516      * @param remainingDv total ΔV remaining for spacecraft
517      */
518     public void setRemainingDv(final double remainingDv) {
519         refuseFurtherComments();
520         this.remainingDv = remainingDv;
521     }
522 
523     /** Get the inertia matrix.
524      * @return the inertia matrix
525      */
526     public Optional<RealMatrix> getInertiaMatrix() {
527         return Optional.ofNullable(inertiaMatrix);
528     }
529 
530     /** Set an entry in the inertia matrix.
531      * <p>
532      * Both I(j, k) and I(k, j) are set.
533      * </p>
534      * @param j row index (must be between 0 and 3 (inclusive)
535      * @param k column index (must be between 0 and 3 (inclusive)
536      * @param entry value of the matrix entry
537      */
538     public void setInertiaMatrixEntry(final int j, final int k, final double entry) {
539         refuseFurtherComments();
540         if (inertiaMatrix == null) {
541             inertiaMatrix = MatrixUtils.createRealMatrix(3, 3);
542             // set all values to NaN
543             inertiaMatrix.walkInOptimizedOrder(new DefaultRealMatrixChangingVisitor() {
544                 @Override
545                 public double visit(final int i, final int j, final double v) {
546                     return Double.NaN;
547                 }
548             });
549         }
550         inertiaMatrix.setEntry(j, k, entry);
551         inertiaMatrix.setEntry(k, j, entry);
552     }
553 
554 }