1   /* Copyright 2013-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.rugged.adjustment;
18  
19  import java.lang.reflect.Field;
20  
21  import java.util.ArrayList;
22  import java.util.Iterator;
23  import java.util.List;
24  
25  import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer.Optimum;
26  
27  import org.junit.jupiter.api.AfterEach;
28  import org.junit.jupiter.api.Assertions;
29  import org.junit.jupiter.api.BeforeEach;
30  import org.junit.jupiter.api.Test;
31  import org.orekit.rugged.adjustment.measurements.Observables;
32  import org.orekit.rugged.adjustment.measurements.SensorMapping;
33  import org.orekit.rugged.adjustment.util.InitInterRefiningTest;
34  import org.orekit.rugged.api.Rugged;
35  import org.orekit.rugged.errors.RuggedException;
36  import org.orekit.rugged.errors.RuggedMessages;
37  import org.orekit.rugged.linesensor.SensorPixel;
38  
39  public class AdjustmentContextTest {
40      
41      @BeforeEach
42      public void setUp() {
43          
44          try {
45              // One must set a context for the adjustment ... Here we choose an inter sensors optimization problem
46              InitInterRefiningTest refiningTest = new InitInterRefiningTest();
47              refiningTest.initRefiningTest();
48  
49              ruggedList = refiningTest.getRuggedList();
50  
51              int lineSampling = 1000;
52              int pixelSampling = 1000;
53              
54              double earthConstraintWeight = 0.1;
55  
56              measurements = refiningTest.generateNoisyPoints(lineSampling, pixelSampling, earthConstraintWeight, false);
57              
58          }  catch (RuggedException re) {
59              Assertions.fail(re.getLocalizedMessage());
60          }
61      }
62  
63      @Test
64      public void testAdjustmentContext() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
65          
66          AdjustmentContext adjustmentContext = new AdjustmentContext(ruggedList, measurements);
67          
68          // Check if the default OptimizerId is the expected one (use reflectivity)
69          Field optimizerId = adjustmentContext.getClass().getDeclaredField("optimizerID");
70          optimizerId.setAccessible(true);
71          OptimizerId defaultOptimizerId = (OptimizerId) optimizerId.get(adjustmentContext);
72          Assertions.assertTrue((defaultOptimizerId == OptimizerId.GAUSS_NEWTON_QR));
73          
74          // Check if the change of the default OptimizerId is correct
75          adjustmentContext.setOptimizer(OptimizerId.GAUSS_NEWTON_LU);
76          OptimizerId modifiedOptimizerId = (OptimizerId) optimizerId.get(adjustmentContext);
77          Assertions.assertTrue((modifiedOptimizerId == OptimizerId.GAUSS_NEWTON_LU));
78          
79          // Check if the change of the default OptimizerId is correct
80          adjustmentContext.setOptimizer(OptimizerId.LEVENBERG_MARQUADT);
81          modifiedOptimizerId = (OptimizerId) optimizerId.get(adjustmentContext);
82          Assertions.assertTrue((modifiedOptimizerId == OptimizerId.LEVENBERG_MARQUADT));
83  
84   
85      }
86  
87      @Test
88      public void testEstimateFreeParameters() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
89          
90          AdjustmentContext adjustmentContext = new AdjustmentContext(ruggedList, measurements);
91          
92          for (OptimizerId optimizer : OptimizerId.values()) {
93              
94              // Set the optimizer
95              adjustmentContext.setOptimizer(optimizer);
96  
97              List<String> ruggedNameList = new ArrayList<String>();
98              for(Rugged rugged : ruggedList) {
99                  ruggedNameList.add(rugged.getName());
100             }
101             final int maxIterations = 120;
102             final double convergenceThreshold = 1.e-7;
103 
104             Optimum optimum = adjustmentContext.estimateFreeParameters(ruggedNameList, maxIterations, convergenceThreshold);
105             
106             Field optimizerId = adjustmentContext.getClass().getDeclaredField("optimizerID");
107             optimizerId.setAccessible(true);
108             OptimizerId usedOptimizerId = (OptimizerId) optimizerId.get(adjustmentContext);
109 
110             if (usedOptimizerId == OptimizerId.GAUSS_NEWTON_QR || usedOptimizerId == OptimizerId.GAUSS_NEWTON_LU) {
111                 // For Gauss Newton, the number of evaluations is equal to the number of iterations
112                 Assertions.assertTrue(optimum.getEvaluations() == optimum.getIterations());
113             } else if (usedOptimizerId == OptimizerId.LEVENBERG_MARQUADT) {
114                 // For Levenberg Marquadt, the number of evaluations is slightly greater than the number of iterations
115                 Assertions.assertTrue(optimum.getEvaluations() >= optimum.getIterations());
116             }
117 
118         } // loop on OptimizerId
119     }
120 
121     @Test
122     public void testInvalidRuggedName() {
123         try {
124 
125             AdjustmentContext adjustmentContext = new AdjustmentContext(ruggedList, measurements);
126 
127             List<String> ruggedNameList = new ArrayList<String>();
128             // the list must not have a null value
129             Iterator<Rugged> it = ruggedList.iterator();
130             while (it.hasNext()) {
131                 ruggedNameList.add(null);
132                 it.next();
133             }
134             final int maxIterations = 1;
135             final double convergenceThreshold = 1.e-7;
136 
137             adjustmentContext.estimateFreeParameters(ruggedNameList, maxIterations, convergenceThreshold);
138             Assertions.fail("An exception should have been thrown");
139 
140         } catch (RuggedException re) {
141             Assertions.assertEquals(RuggedMessages.INVALID_RUGGED_NAME,re.getSpecifier());
142         }
143     }
144 
145     @Test
146     public void testUnsupportedRefiningContext() {
147         try {
148             
149             AdjustmentContext adjustmentContext = new AdjustmentContext(ruggedList, measurements);
150             
151             List<String> ruggedNameList = new ArrayList<String>();
152             // Add too many rugged name: the list must have 1 or 2 items 
153             for(Rugged rugged : ruggedList) {
154                 ruggedNameList.add(rugged.getName());
155                 ruggedNameList.add(rugged.getName());
156                 ruggedNameList.add(rugged.getName());
157             }
158             final int maxIterations = 1;
159             final double convergenceThreshold = 1.e-7;
160 
161             adjustmentContext.estimateFreeParameters(ruggedNameList, maxIterations, convergenceThreshold);
162             Assertions.fail("An exception should have been thrown");
163             
164         } catch (RuggedException re) {
165             Assertions.assertEquals(RuggedMessages.UNSUPPORTED_REFINING_CONTEXT,re.getSpecifier());
166         }
167     }
168     
169     @Test
170     public void testSensorMapping() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
171  
172         String sensorGiven = "lineSensor";
173         String ruggedGiven = "Rugged";
174         SensorMapping<SensorPixel> simpleMapping = new SensorMapping<SensorPixel>(sensorGiven) ;
175         
176         Field ruggedField = simpleMapping.getClass().getDeclaredField("ruggedName");
177         ruggedField.setAccessible(true);
178         String ruggedRead = (String) ruggedField.get(simpleMapping);
179         
180         Field sensorField = simpleMapping.getClass().getDeclaredField("sensorName");
181         sensorField.setAccessible(true);
182         String sensorRead = (String) sensorField.get(simpleMapping);
183 
184         Assertions.assertTrue(ruggedGiven.equals(ruggedRead));
185         Assertions.assertTrue(sensorGiven.equals(sensorRead));
186     }
187     
188     @AfterEach
189     public void tearDown() {
190         measurements = null;
191         ruggedList = null;
192     }
193     
194     private Observables measurements;
195     private List<Rugged> ruggedList;
196 
197 }