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.propagation.events;
18  
19  import java.util.Collections;
20  import java.util.NoSuchElementException;
21  
22  import org.hipparchus.util.Binary64;
23  import org.hipparchus.util.Binary64Field;
24  import org.junit.jupiter.api.Assertions;
25  import org.junit.jupiter.api.BeforeEach;
26  import org.junit.jupiter.api.Test;
27  import org.mockito.Mockito;
28  import org.orekit.propagation.FieldSpacecraftState;
29  import org.orekit.propagation.SpacecraftState;
30  import org.orekit.propagation.events.handlers.FieldEventHandler;
31  import org.orekit.propagation.events.intervals.FieldAdaptableInterval;
32  import org.orekit.time.FieldAbsoluteDate;
33  
34  /**
35   * Unit tests for {@link FieldBooleanDetector#orCombine(FieldEventDetector...)}.
36   *
37   * @author Evan Ward
38   */
39  public class FieldOrDetectorTest {
40  
41      /** first operand. */
42      private MockDetector a;
43      /** second operand. */
44      private MockDetector b;
45      /** null (except for date) */
46      private FieldSpacecraftState<Binary64> s;
47      /** subject under test */
48      private FieldBooleanDetector<Binary64> or;
49  
50      /** create subject under test and dependencies. */
51      @SuppressWarnings("unchecked")
52      @BeforeEach
53      public void setUp() {
54          a = new MockDetector();
55          b = new MockDetector();
56          s = Mockito.mock(FieldSpacecraftState.class);
57          Mockito.when(s.getDate()).thenReturn(FieldAbsoluteDate.getArbitraryEpoch(Binary64Field.getInstance()));
58          or = FieldBooleanDetector.orCombine(a, b);
59      }
60  
61      /**
62       * check {@link BooleanDetector#g(SpacecraftState)}.
63       */
64      @Test
65      public void testG() {
66          // test zero cases
67          a.g = b.g = new Binary64(0.0);
68          Assertions.assertEquals(0.0, or.g(s).getReal(), 0);
69          a.g = new Binary64(-1);
70          b.g = new Binary64(0);
71          Assertions.assertEquals(0.0, or.g(s).getReal(), 0);
72          a.g = new Binary64(0);
73          b.g = new Binary64(-1);
74          Assertions.assertEquals(0.0, or.g(s).getReal(), 0);
75  
76          // test negative cases
77          a.g = new Binary64(-1);
78          b.g = new Binary64(-1);
79          Assertions.assertTrue(or.g(s).getReal() < 0, "negative");
80  
81          // test positive cases
82          a.g = new Binary64(0);
83          b.g = new Binary64(1);
84          Assertions.assertTrue(or.g(s).getReal() > 0, "positive");
85          a.g = new Binary64(1);
86          b.g = new Binary64(-1);
87          Assertions.assertTrue(or.g(s).getReal() > 0, "positive");
88          a.g = new Binary64(1);
89          b.g = new Binary64(0);
90          Assertions.assertTrue(or.g(s).getReal() > 0, "positive");
91          a.g = new Binary64(-1);
92          b.g = new Binary64(1);
93          Assertions.assertTrue(or.g(s).getReal() > 0, "positive");
94          a.g = new Binary64(1);
95          b.g = new Binary64(1);
96          Assertions.assertTrue(or.g(s).getReal() > 0, "positive");
97  
98      }
99  
100     /**
101      * check when there is numeric cancellation between the two g values.
102      */
103     @Test
104     public void testCancellation() {
105         a.g = new Binary64(-1e-10);
106         b.g = new Binary64(-1e10);
107         Assertions.assertTrue(or.g(s).getReal() < 0, "negative");
108         a.g = new Binary64(-1e10);
109         b.g = new Binary64(-1e-10);
110         Assertions.assertTrue(or.g(s).getReal() < 0, "negative");
111         a.g = new Binary64(-1e10);
112         b.g = new Binary64(1e-10);
113         Assertions.assertTrue(or.g(s).getReal() > 0, "positive");
114         a.g = new Binary64(1e-10);
115         b.g = new Binary64(-1e10);
116         Assertions.assertTrue(or.g(s).getReal() > 0, "positive");
117         a.g = new Binary64(1e10);
118         b.g = new Binary64(-1e-10);
119         Assertions.assertTrue(or.g(s).getReal() > 0, "positive");
120         a.g = new Binary64(-1e-10);
121         b.g = new Binary64(1e10);
122         Assertions.assertTrue(or.g(s).getReal() > 0, "positive");
123     }
124 
125     /**
126      * Check wrapped detectors are initialized.
127      */
128     @SuppressWarnings("unchecked")
129     @Test
130     public void testInit() {
131         // setup
132         FieldEventDetector<Binary64> a = Mockito.mock(FieldEventDetector.class);
133         Mockito.when(a.getMaxCheckInterval()).thenReturn(FieldAdaptableInterval.of(AbstractDetector.DEFAULT_MAX_CHECK));
134         Mockito.when(a.getThreshold()).thenReturn(new Binary64(AbstractDetector.DEFAULT_THRESHOLD));
135         FieldEventDetector<Binary64> b = Mockito.mock(FieldEventDetector.class);
136         Mockito.when(b.getMaxCheckInterval()).thenReturn(FieldAdaptableInterval.of(AbstractDetector.DEFAULT_MAX_CHECK));
137         Mockito.when(b.getThreshold()).thenReturn(new Binary64(AbstractDetector.DEFAULT_THRESHOLD));
138         FieldEventHandler<Binary64> c = Mockito.mock(FieldEventHandler.class);
139         FieldBooleanDetector<Binary64> or = FieldBooleanDetector.orCombine(a, b).withHandler(c);
140         FieldAbsoluteDate<Binary64> t = FieldAbsoluteDate.getCCSDSEpoch(Binary64Field.getInstance());
141         s = Mockito.mock(FieldSpacecraftState.class);
142         Mockito.when(s.getDate()).thenReturn(t.shiftedBy(60.0));
143 
144         // action
145         or.init(s, t);
146 
147         // verify
148         Assertions.assertEquals(2, or.getDetectors().size());
149         Mockito.verify(a).init(s, t);
150         Mockito.verify(b).init(s, t);
151         Mockito.verify(c).init(s, t, or);
152     }
153 
154     /** check when no operands are passed to the constructor. */
155     @Test
156     public void testZeroDetectors() {
157         // action
158         try {
159             BooleanDetector.orCombine(Collections.emptyList());
160             Assertions.fail("Expected Exception");
161         } catch (NoSuchElementException e) {
162             // expected
163         }
164     }
165 
166     /** Mock detector to set the g function to arbitrary values. */
167     private static class MockDetector implements FieldEventDetector<Binary64> {
168 
169         /** value to return from {@link #g(SpacecraftState)}. */
170         public Binary64 g = new Binary64(0);
171 
172         @Override
173         public Binary64 g(FieldSpacecraftState<Binary64> s) {
174             return this.g;
175         }
176 
177         @Override
178         public FieldEventDetectionSettings<Binary64> getDetectionSettings() {
179             return new FieldEventDetectionSettings<>(Binary64Field.getInstance(), EventDetectionSettings.getDefaultEventDetectionSettings());
180         }
181 
182         @Override
183         public FieldEventHandler<Binary64> getHandler() {
184             return (state, detector, increasing) -> null;
185         }
186     }
187 }