ComplexODEConverter.java

  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. package org.hipparchus.ode;

  18. import org.hipparchus.complex.Complex;

  19. /** This class converts {@link ComplexOrdinaryDifferentialEquation complex Ordinary
  20.  * Differential Equations} into {@link OrdinaryDifferentialEquation real ones}.
  21.  *
  22.  * <p>This class is a wrapper around a {@link ComplexOrdinaryDifferentialEquation} which
  23.  * allow to use a {@link ODEIntegrator} to integrate it.</p>
  24.  *
  25.  * <p>The transformation is done by changing the n dimension state
  26.  * vector to a 2n dimension vector, where the even components are
  27.  * real parts and odd components are imaginary parts.</p>
  28.  *
  29.  * <p>One should be aware that the data is duplicated during the
  30.  * transformation process and that for each call to {@link
  31.  * OrdinaryDifferentialEquation#computeDerivatives(double, double[])
  32.  * computeDerivatives}, this wrapper does copy 4n scalars : 2n before
  33.  * the call to {@link
  34.  * OrdinaryDifferentialEquation#computeDerivatives(double, double[])
  35.  * computeDerivatives} in order to dispatch the y state vector,
  36.  * and 2n after the call to gather zDot. Since the underlying problem
  37.  * by itself perhaps also needs to copy data and dispatch the arrays
  38.  * into domain objects, this has an impact on both memory and CPU usage.
  39.  * The only way to avoid this duplication is to perform the transformation
  40.  * at the problem level, i.e. to implement the problem as a first order one
  41.  * and then avoid using this class.</p>
  42.  *
  43.  * <p>
  44.  * The proper way to use the converter is as follows:
  45.  * </p>
  46.  * <pre>
  47.  *   ODEIntegrator                       integrator       = ...build some integrator...;
  48.  *   ComplexOrdinaryDifferentialEquation complexEquations = ...set up the complex problem...;
  49.  *   ComplexODEState                     initialState     = ...set up initial state...;
  50.  *   ComplexODEConverter                 converter        = new ComplexODEConverter();
  51.  *   ComplexODEStateAndDerivative        finalstate       =
  52.  *      converter.convertStateAndDerivative(integrator.integrate(converter.convertEquations(complexEquations),
  53.  *                                                               converter.convertState(initialState),
  54.  *                                                               t);
  55.  * </pre>
  56.  * <p>
  57.  * If there are {@link ComplexSecondaryODE complex secondary equations}, they must be converted
  58.  * too and both the converted primary equations and converted secondary equations must be
  59.  * combined together using {@link ExpandableODE ExpandableODE} as usual for regular real equations.
  60.  * </p>
  61.  *
  62.  * @see ComplexOrdinaryDifferentialEquation
  63.  * @see OrdinaryDifferentialEquation
  64.  * @since 1.4
  65.  */

  66. public class ComplexODEConverter {

  67.     /** Empty constructor.
  68.      * <p>
  69.      * This constructor is not strictly necessary, but it prevents spurious
  70.      * javadoc warnings with JDK 18 and later.
  71.      * </p>
  72.      * @since 3.0
  73.      */
  74.     public ComplexODEConverter() { // NOPMD - unnecessary constructor added intentionally to make javadoc happy
  75.         // nothing to do
  76.     }

  77.     /** Convert an equations set.
  78.      * @param equations equations to convert
  79.      * @return converted equations
  80.      */
  81.     public OrdinaryDifferentialEquation convertEquations(final ComplexOrdinaryDifferentialEquation equations) {
  82.         return new OrdinaryDifferentialEquation() {

  83.             /** {@inheritDoc}
  84.              * <p>The dimension of the real problem is twice the
  85.              * dimension of the underlying complex problem.</p>
  86.              * @return dimension of the problem
  87.              */
  88.             @Override
  89.             public int getDimension() {
  90.                 return 2 * equations.getDimension();
  91.             }

  92.             /** {@inheritDoc} */
  93.             @Override
  94.             public void init(final double t0, final double[] y0, final double finalTime) {
  95.                 equations.init(t0, convert(y0), finalTime);
  96.             }

  97.             /** {@inheritDoc} */
  98.             @Override
  99.             public double[] computeDerivatives(final double t, final double[] y) {
  100.                 return convert(equations.computeDerivatives(t, convert(y)));
  101.             }

  102.         };
  103.     }

  104.     /** Convert a secondary equations set.
  105.      * @param equations equations to convert
  106.      * @return converted equations
  107.      */
  108.     public SecondaryODE convertSecondaryEquations(final ComplexSecondaryODE equations) {
  109.         return new SecondaryODE() {

  110.             /** {@inheritDoc}
  111.              * <p>The dimension of the real problem is twice the
  112.              * dimension of the underlying complex problem.</p>
  113.              * @return dimension of the problem
  114.              */
  115.             @Override
  116.             public int getDimension() {
  117.                 return 2 * equations.getDimension();
  118.             }

  119.             /** {@inheritDoc} */
  120.             @Override
  121.             public void init(final double t0, final double[] primary0, final double[] secondary0, final double finalTime) {
  122.                 equations.init(t0, convert(primary0), convert(secondary0), finalTime);
  123.             }

  124.             /** {@inheritDoc} */
  125.             @Override
  126.             public double[] computeDerivatives(final double t, final double[] primary, final double[] primaryDot,
  127.                                                final double[] secondary) {
  128.                 return convert(equations.computeDerivatives(t, convert(primary), convert(primaryDot), convert(secondary)));
  129.             }

  130.         };
  131.     }

  132.     /** Convert a complex state (typically the initial state).
  133.      * @param state state to convert
  134.      * @return converted state
  135.      */
  136.     public ODEState convertState(final ComplexODEState state) {
  137.         final double[][] secondary = new double[state.getNumberOfSecondaryStates()][];
  138.         for (int index = 0; index < secondary.length; ++index) {
  139.             secondary[index] = convert(state.getSecondaryState(index + 1));
  140.         }
  141.         return new ODEState(state.getTime(),
  142.                             convert(state.getPrimaryState()),
  143.                             secondary);
  144.     }

  145.     /** Convert a real state and derivatives (typically the final state or some intermediate state for
  146.      * step handling or event handling).
  147.      * @param state state to convert
  148.      * @return converted state
  149.      */
  150.     public ComplexODEStateAndDerivative convertState(final ODEStateAndDerivative state) {
  151.         final Complex[][] secondary           = new Complex[state.getNumberOfSecondaryStates()][];
  152.         final Complex[][] secondaryDerivative = new Complex[state.getNumberOfSecondaryStates()][];
  153.         for (int index = 0; index < secondary.length; ++index) {
  154.             secondary[index]           = convert(state.getSecondaryState(index + 1));
  155.             secondaryDerivative[index] = convert(state.getSecondaryDerivative(index + 1));
  156.         }
  157.         return new ComplexODEStateAndDerivative(state.getTime(),
  158.                                                 convert(state.getPrimaryState()),
  159.                                                 convert(state.getPrimaryDerivative()),
  160.                                                 secondary, secondaryDerivative);
  161.     }

  162.     /** Convert a real array into a complex array.
  163.      * @param a array to convert
  164.      * @return converted array
  165.      */
  166.     private Complex[] convert(final double[] a) {
  167.         final Complex[] converted = new Complex[a.length / 2];
  168.         for (int i = 0; i < converted.length; ++i) {
  169.             converted[i] = new Complex(a[2 * i], a[2 * i + 1]);
  170.         }
  171.         return converted;
  172.     }

  173.     /** Convert a complex array into a real array.
  174.      * @param a array to convert
  175.      * @return converted array
  176.      */
  177.     private double[] convert(final Complex[] a) {
  178.         final double[] converted = new double[a.length * 2];
  179.         for (int i = 0; i < a.length; ++i) {
  180.             converted[2 * i]     = a[i].getReal();
  181.             converted[2 * i + 1] = a[i].getImaginary();
  182.         }
  183.         return converted;
  184.     }

  185. }