View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF 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.apache.commons.math4.legacy.ode;
19  
20  import java.io.Serializable;
21  
22  import org.apache.commons.math4.legacy.core.RealFieldElement;
23  import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
24  import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
25  import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
26  import org.apache.commons.math4.legacy.core.MathArrays;
27  
28  /**
29   * Class mapping the part of a complete state or derivative that pertains
30   * to a set of differential equations.
31   * <p>
32   * Instances of this class are guaranteed to be immutable.
33   * </p>
34   * @see FieldExpandableODE
35   * @param <T> the type of the field elements
36   * @since 3.6
37   */
38  public class FieldEquationsMapper<T extends RealFieldElement<T>> implements Serializable {
39  
40      /** Serializable UID. */
41      private static final long serialVersionUID = 20151114L;
42  
43      /** Start indices of the components. */
44      private final int[] start;
45  
46      /** Create a mapper by adding a new equation to another mapper.
47       * <p>
48       * The new equation will have index {@code mapper.}{@link #getNumberOfEquations()},
49       * or 0 if {@code mapper} is null.
50       * </p>
51       * @param mapper former mapper, with one equation less (null for first equation)
52       * @param dimension dimension of the equation state vector
53       */
54      FieldEquationsMapper(final FieldEquationsMapper<T> mapper, final int dimension) {
55          final int index = (mapper == null) ? 0 : mapper.getNumberOfEquations();
56          this.start = new int[index + 2];
57          if (mapper == null) {
58              start[0] = 0;
59          } else {
60              System.arraycopy(mapper.start, 0, start, 0, index + 1);
61          }
62          start[index + 1] = start[index] + dimension;
63      }
64  
65      /** Get the number of equations mapped.
66       * @return number of equations mapped
67       */
68      public int getNumberOfEquations() {
69          return start.length - 1;
70      }
71  
72      /** Return the dimension of the complete set of equations.
73       * <p>
74       * The complete set of equations correspond to the primary set plus all secondary sets.
75       * </p>
76       * @return dimension of the complete set of equations
77       */
78      public int getTotalDimension() {
79          return start[start.length - 1];
80      }
81  
82      /** Map a state to a complete flat array.
83       * @param state state to map
84       * @return flat array containing the mapped state, including primary and secondary components
85       */
86      public T[] mapState(final FieldODEState<T> state) {
87          final T[] y = MathArrays.buildArray(state.getTime().getField(), getTotalDimension());
88          int index = 0;
89          insertEquationData(index, state.getState(), y);
90          while (++index < getNumberOfEquations()) {
91              insertEquationData(index, state.getSecondaryState(index), y);
92          }
93          return y;
94      }
95  
96      /** Map a state derivative to a complete flat array.
97       * @param state state to map
98       * @return flat array containing the mapped state derivative, including primary and secondary components
99       */
100     public T[] mapDerivative(final FieldODEStateAndDerivative<T> state) {
101         final T[] yDot = MathArrays.buildArray(state.getTime().getField(), getTotalDimension());
102         int index = 0;
103         insertEquationData(index, state.getDerivative(), yDot);
104         while (++index < getNumberOfEquations()) {
105             insertEquationData(index, state.getSecondaryDerivative(index), yDot);
106         }
107         return yDot;
108     }
109 
110     /** Map flat arrays to a state and derivative.
111      * @param t time
112      * @param y state array to map, including primary and secondary components
113      * @param yDot state derivative array to map, including primary and secondary components
114      * @return mapped state
115      * @exception DimensionMismatchException if an array does not match total dimension
116      */
117     public FieldODEStateAndDerivative<T> mapStateAndDerivative(final T t, final T[] y, final T[] yDot)
118         throws DimensionMismatchException {
119 
120         if (y.length != getTotalDimension()) {
121             throw new DimensionMismatchException(y.length, getTotalDimension());
122         }
123 
124         if (yDot.length != getTotalDimension()) {
125             throw new DimensionMismatchException(yDot.length, getTotalDimension());
126         }
127 
128         final int n = getNumberOfEquations();
129         int index = 0;
130         final T[] state      = extractEquationData(index, y);
131         final T[] derivative = extractEquationData(index, yDot);
132         if (n < 2) {
133             return new FieldODEStateAndDerivative<>(t, state, derivative);
134         } else {
135             final T[][] secondaryState      = MathArrays.buildArray(t.getField(), n - 1, -1);
136             final T[][] secondaryDerivative = MathArrays.buildArray(t.getField(), n - 1, -1);
137             while (++index < getNumberOfEquations()) {
138                 secondaryState[index - 1]      = extractEquationData(index, y);
139                 secondaryDerivative[index - 1] = extractEquationData(index, yDot);
140             }
141             return new FieldODEStateAndDerivative<>(t, state, derivative, secondaryState, secondaryDerivative);
142         }
143     }
144 
145     /** Extract equation data from a complete state or derivative array.
146      * @param index index of the equation, must be between 0 included and
147      * {@link #getNumberOfEquations()} (excluded)
148      * @param complete complete state or derivative array from which
149      * equation data should be retrieved
150      * @return equation data
151      * @exception MathIllegalArgumentException if index is out of range
152      * @exception DimensionMismatchException if complete state has not enough elements
153      */
154     public T[] extractEquationData(final int index, final T[] complete)
155         throws MathIllegalArgumentException, DimensionMismatchException {
156         checkIndex(index);
157         final int begin     = start[index];
158         final int end       = start[index + 1];
159         if (complete.length < end) {
160             throw new DimensionMismatchException(complete.length, end);
161         }
162         final int dimension = end - begin;
163         final T[] equationData = MathArrays.buildArray(complete[0].getField(), dimension);
164         System.arraycopy(complete, begin, equationData, 0, dimension);
165         return equationData;
166     }
167 
168     /** Insert equation data into a complete state or derivative array.
169      * @param index index of the equation, must be between 0 included and
170      * {@link #getNumberOfEquations()} (excluded)
171      * @param equationData equation data to be inserted into the complete array
172      * @param complete placeholder where to put equation data (only the
173      * part corresponding to the equation will be overwritten)
174      * @exception DimensionMismatchException if either array has not enough elements
175      */
176     public void insertEquationData(final int index, T[] equationData, T[] complete)
177         throws DimensionMismatchException {
178         checkIndex(index);
179         final int begin     = start[index];
180         final int end       = start[index + 1];
181         final int dimension = end - begin;
182         if (complete.length < end) {
183             throw new DimensionMismatchException(complete.length, end);
184         }
185         if (equationData.length != dimension) {
186             throw new DimensionMismatchException(equationData.length, dimension);
187         }
188         System.arraycopy(equationData, 0, complete, begin, dimension);
189     }
190 
191     /** Check equation index.
192      * @param index index of the equation, must be between 0 included and
193      * {@link #getNumberOfEquations()} (excluded)
194      * @exception MathIllegalArgumentException if index is out of range
195      */
196     private void checkIndex(final int index) throws MathIllegalArgumentException {
197         if (index < 0 || index > start.length - 2) {
198             throw new MathIllegalArgumentException(LocalizedFormats.ARGUMENT_OUTSIDE_DOMAIN,
199                                                    index, 0, start.length - 2);
200         }
201     }
202 }