View Javadoc
1   /*
2    * Licensed to the Hipparchus project 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 Hipparchus project 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    *      https://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.hipparchus.ode;
19  
20  import org.hipparchus.complex.Complex;
21  
22  /** This class converts {@link ComplexOrdinaryDifferentialEquation complex Ordinary
23   * Differential Equations} into {@link OrdinaryDifferentialEquation real ones}.
24   *
25   * <p>This class is a wrapper around a {@link ComplexOrdinaryDifferentialEquation} which
26   * allow to use a {@link ODEIntegrator} to integrate it.</p>
27   *
28   * <p>The transformation is done by changing the n dimension state
29   * vector to a 2n dimension vector, where the even components are
30   * real parts and odd components are imaginary parts.</p>
31   *
32   * <p>One should be aware that the data is duplicated during the
33   * transformation process and that for each call to {@link
34   * OrdinaryDifferentialEquation#computeDerivatives(double, double[])
35   * computeDerivatives}, this wrapper does copy 4n scalars : 2n before
36   * the call to {@link
37   * OrdinaryDifferentialEquation#computeDerivatives(double, double[])
38   * computeDerivatives} in order to dispatch the y state vector,
39   * and 2n after the call to gather zDot. Since the underlying problem
40   * by itself perhaps also needs to copy data and dispatch the arrays
41   * into domain objects, this has an impact on both memory and CPU usage.
42   * The only way to avoid this duplication is to perform the transformation
43   * at the problem level, i.e. to implement the problem as a first order one
44   * and then avoid using this class.</p>
45   *
46   * <p>
47   * The proper way to use the converter is as follows:
48   * </p>
49   * <pre>
50   *   ODEIntegrator                       integrator       = ...build some integrator...;
51   *   ComplexOrdinaryDifferentialEquation complexEquations = ...set up the complex problem...;
52   *   ComplexODEState                     initialState     = ...set up initial state...;
53   *   ComplexODEConverter                 converter        = new ComplexODEConverter();
54   *   ComplexODEStateAndDerivative        finalstate       =
55   *      converter.convertStateAndDerivative(integrator.integrate(converter.convertEquations(complexEquations),
56   *                                                               converter.convertState(initialState),
57   *                                                               t);
58   * </pre>
59   * <p>
60   * If there are {@link ComplexSecondaryODE complex secondary equations}, they must be converted
61   * too and both the converted primary equations and converted secondary equations must be
62   * combined together using {@link ExpandableODE ExpandableODE} as usual for regular real equations.
63   * </p>
64   *
65   * @see ComplexOrdinaryDifferentialEquation
66   * @see OrdinaryDifferentialEquation
67   * @since 1.4
68   */
69  
70  public class ComplexODEConverter {
71  
72      /** Empty constructor.
73       * <p>
74       * This constructor is not strictly necessary, but it prevents spurious
75       * javadoc warnings with JDK 18 and later.
76       * </p>
77       * @since 3.0
78       */
79      public ComplexODEConverter() { // NOPMD - unnecessary constructor added intentionally to make javadoc happy
80          // nothing to do
81      }
82  
83      /** Convert an equations set.
84       * @param equations equations to convert
85       * @return converted equations
86       */
87      public OrdinaryDifferentialEquation convertEquations(final ComplexOrdinaryDifferentialEquation equations) {
88          return new OrdinaryDifferentialEquation() {
89  
90              /** {@inheritDoc}
91               * <p>The dimension of the real problem is twice the
92               * dimension of the underlying complex problem.</p>
93               * @return dimension of the problem
94               */
95              @Override
96              public int getDimension() {
97                  return 2 * equations.getDimension();
98              }
99  
100             /** {@inheritDoc} */
101             @Override
102             public void init(final double t0, final double[] y0, final double finalTime) {
103                 equations.init(t0, convert(y0), finalTime);
104             }
105 
106             /** {@inheritDoc} */
107             @Override
108             public double[] computeDerivatives(final double t, final double[] y) {
109                 return convert(equations.computeDerivatives(t, convert(y)));
110             }
111 
112         };
113     }
114 
115     /** Convert a secondary equations set.
116      * @param equations equations to convert
117      * @return converted equations
118      */
119     public SecondaryODE convertSecondaryEquations(final ComplexSecondaryODE equations) {
120         return new SecondaryODE() {
121 
122             /** {@inheritDoc}
123              * <p>The dimension of the real problem is twice the
124              * dimension of the underlying complex problem.</p>
125              * @return dimension of the problem
126              */
127             @Override
128             public int getDimension() {
129                 return 2 * equations.getDimension();
130             }
131 
132             /** {@inheritDoc} */
133             @Override
134             public void init(final double t0, final double[] primary0, final double[] secondary0, final double finalTime) {
135                 equations.init(t0, convert(primary0), convert(secondary0), finalTime);
136             }
137 
138             /** {@inheritDoc} */
139             @Override
140             public double[] computeDerivatives(final double t, final double[] primary, final double[] primaryDot,
141                                                final double[] secondary) {
142                 return convert(equations.computeDerivatives(t, convert(primary), convert(primaryDot), convert(secondary)));
143             }
144 
145         };
146     }
147 
148     /** Convert a complex state (typically the initial state).
149      * @param state state to convert
150      * @return converted state
151      */
152     public ODEState convertState(final ComplexODEState state) {
153         final double[][] secondary = new double[state.getNumberOfSecondaryStates()][];
154         for (int index = 0; index < secondary.length; ++index) {
155             secondary[index] = convert(state.getSecondaryState(index + 1));
156         }
157         return new ODEState(state.getTime(),
158                             convert(state.getPrimaryState()),
159                             secondary);
160     }
161 
162     /** Convert a real state and derivatives (typically the final state or some intermediate state for
163      * step handling or event handling).
164      * @param state state to convert
165      * @return converted state
166      */
167     public ComplexODEStateAndDerivative convertState(final ODEStateAndDerivative state) {
168         final Complex[][] secondary           = new Complex[state.getNumberOfSecondaryStates()][];
169         final Complex[][] secondaryDerivative = new Complex[state.getNumberOfSecondaryStates()][];
170         for (int index = 0; index < secondary.length; ++index) {
171             secondary[index]           = convert(state.getSecondaryState(index + 1));
172             secondaryDerivative[index] = convert(state.getSecondaryDerivative(index + 1));
173         }
174         return new ComplexODEStateAndDerivative(state.getTime(),
175                                                 convert(state.getPrimaryState()),
176                                                 convert(state.getPrimaryDerivative()),
177                                                 secondary, secondaryDerivative);
178     }
179 
180     /** Convert a real array into a complex array.
181      * @param a array to convert
182      * @return converted array
183      */
184     private Complex[] convert(final double[] a) {
185         final Complex[] converted = new Complex[a.length / 2];
186         for (int i = 0; i < converted.length; ++i) {
187             converted[i] = new Complex(a[2 * i], a[2 * i + 1]);
188         }
189         return converted;
190     }
191 
192     /** Convert a complex array into a real array.
193      * @param a array to convert
194      * @return converted array
195      */
196     private double[] convert(final Complex[] a) {
197         final double[] converted = new double[a.length * 2];
198         for (int i = 0; i < a.length; ++i) {
199             converted[2 * i]     = a[i].getReal();
200             converted[2 * i + 1] = a[i].getImaginary();
201         }
202         return converted;
203     }
204 
205 }