1 /* Copyright 2022-2025 Romain Serra
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.propagation.events.functions;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.Field;
21 import org.orekit.propagation.FieldSpacecraftState;
22 import org.orekit.propagation.SpacecraftState;
23 import org.orekit.propagation.events.EventDetector;
24 import org.orekit.propagation.events.FieldEventDetector;
25
26 import java.util.function.Function;
27
28 /**
29 * Interface for functions defining events via their roots a.k.a. zeroes.
30 * It regroups standard (double) and Field methods.
31 * @see EventDetector
32 * @see FieldEventDetector
33 * @since 14.0
34 * @author Romain Serra
35 */
36 @FunctionalInterface
37 public interface EventFunction {
38
39 /**
40 * Evaluate function.
41 * @param state spacecraft state
42 * @return value
43 */
44 double value(SpacecraftState state);
45
46 /**
47 * Evaluate Field function. By default, calls the non-Field version.
48 * This is suitable for detection but not be for applications like automatic differentiation,
49 * where a proper implementation should be used instead.
50 * @param fieldState spacecraft state
51 * @param <T> field type
52 * @return value
53 */
54 default <T extends CalculusFieldElement<T>> T value(final FieldSpacecraftState<T> fieldState) {
55 final Field<T> field = fieldState.getDate().getField();
56 final double gReal = value(fieldState.toSpacecraftState());
57 return field.getZero().newInstance(gReal);
58 }
59
60 /**
61 * Method returning true if and only if the event function does not depend on dependent variables,
62 * just the independent one i.e. time. This information is used for performance in propagation
63 * and derivatives correction with switches in the dynamics.
64 * @return flag
65 */
66 default boolean dependsOnTimeOnly() {
67 return false;
68 }
69
70 /**
71 * Method returning true if and only if the event function does not depend on dependent variables,
72 * other than the Cartesian coordinates (or equivalent), mass and attitude (excepts for its rates).
73 * It should thus return false if the STM is needed to evaluate the event.
74 * This information is used for performance in propagation.
75 * @return flag
76 */
77 default boolean dependsOnMainVariablesOnly() {
78 return true;
79 }
80
81 /**
82 * Builds an instance from a mapping with a single Field. Generalizes naively to all other Field via real part.
83 * Flags are set to default values.
84 * @param field original field
85 * @param fieldStateFunction Field function
86 * @return generic event function working for any field
87 * @param <T> field type
88 */
89 static <T extends CalculusFieldElement<T>> EventFunction of(final Field<T> field,
90 final Function<FieldSpacecraftState<T>, T> fieldStateFunction) {
91 return new EventFunction() {
92
93 @Override
94 public double value(final SpacecraftState state) {
95 return value(new FieldSpacecraftState<>(field, state)).getReal();
96 }
97
98 @Override
99 @SuppressWarnings("unchecked")
100 public <S extends CalculusFieldElement<S>> S value(final FieldSpacecraftState<S> fieldState) {
101 if (fieldState.getMass().getField().equals(field)) {
102 // call input implementation if applicable
103 final FieldSpacecraftState<T> castFieldState = (FieldSpacecraftState<T>) fieldState;
104 return (S) fieldStateFunction.apply(castFieldState);
105 } else {
106 // otherwise, use constant from non-Field version
107 return fieldState.getMass().newInstance(value(fieldState.toSpacecraftState()));
108 }
109 }
110 };
111 }
112 }