ComplexODEConverter.java
- /*
- * Licensed to the Hipparchus project under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The Hipparchus project licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.hipparchus.ode;
- import org.hipparchus.complex.Complex;
- /** This class converts {@link ComplexOrdinaryDifferentialEquation complex Ordinary
- * Differential Equations} into {@link OrdinaryDifferentialEquation real ones}.
- *
- * <p>This class is a wrapper around a {@link ComplexOrdinaryDifferentialEquation} which
- * allow to use a {@link ODEIntegrator} to integrate it.</p>
- *
- * <p>The transformation is done by changing the n dimension state
- * vector to a 2n dimension vector, where the even components are
- * real parts and odd components are imaginary parts.</p>
- *
- * <p>One should be aware that the data is duplicated during the
- * transformation process and that for each call to {@link
- * OrdinaryDifferentialEquation#computeDerivatives(double, double[])
- * computeDerivatives}, this wrapper does copy 4n scalars : 2n before
- * the call to {@link
- * OrdinaryDifferentialEquation#computeDerivatives(double, double[])
- * computeDerivatives} in order to dispatch the y state vector,
- * and 2n after the call to gather zDot. Since the underlying problem
- * by itself perhaps also needs to copy data and dispatch the arrays
- * into domain objects, this has an impact on both memory and CPU usage.
- * The only way to avoid this duplication is to perform the transformation
- * at the problem level, i.e. to implement the problem as a first order one
- * and then avoid using this class.</p>
- *
- * <p>
- * The proper way to use the converter is as follows:
- * </p>
- * <pre>
- * ODEIntegrator integrator = ...build some integrator...;
- * ComplexOrdinaryDifferentialEquation complexEquations = ...set up the complex problem...;
- * ComplexODEState initialState = ...set up initial state...;
- * ComplexODEConverter converter = new ComplexODEConverter();
- * ComplexODEStateAndDerivative finalstate =
- * converter.convertStateAndDerivative(integrator.integrate(converter.convertEquations(complexEquations),
- * converter.convertState(initialState),
- * t);
- * </pre>
- * <p>
- * If there are {@link ComplexSecondaryODE complex secondary equations}, they must be converted
- * too and both the converted primary equations and converted secondary equations must be
- * combined together using {@link ExpandableODE ExpandableODE} as usual for regular real equations.
- * </p>
- *
- * @see ComplexOrdinaryDifferentialEquation
- * @see OrdinaryDifferentialEquation
- * @since 1.4
- */
- public class ComplexODEConverter {
- /** Empty constructor.
- * <p>
- * This constructor is not strictly necessary, but it prevents spurious
- * javadoc warnings with JDK 18 and later.
- * </p>
- * @since 3.0
- */
- public ComplexODEConverter() { // NOPMD - unnecessary constructor added intentionally to make javadoc happy
- // nothing to do
- }
- /** Convert an equations set.
- * @param equations equations to convert
- * @return converted equations
- */
- public OrdinaryDifferentialEquation convertEquations(final ComplexOrdinaryDifferentialEquation equations) {
- return new OrdinaryDifferentialEquation() {
- /** {@inheritDoc}
- * <p>The dimension of the real problem is twice the
- * dimension of the underlying complex problem.</p>
- * @return dimension of the problem
- */
- @Override
- public int getDimension() {
- return 2 * equations.getDimension();
- }
- /** {@inheritDoc} */
- @Override
- public void init(final double t0, final double[] y0, final double finalTime) {
- equations.init(t0, convert(y0), finalTime);
- }
- /** {@inheritDoc} */
- @Override
- public double[] computeDerivatives(final double t, final double[] y) {
- return convert(equations.computeDerivatives(t, convert(y)));
- }
- };
- }
- /** Convert a secondary equations set.
- * @param equations equations to convert
- * @return converted equations
- */
- public SecondaryODE convertSecondaryEquations(final ComplexSecondaryODE equations) {
- return new SecondaryODE() {
- /** {@inheritDoc}
- * <p>The dimension of the real problem is twice the
- * dimension of the underlying complex problem.</p>
- * @return dimension of the problem
- */
- @Override
- public int getDimension() {
- return 2 * equations.getDimension();
- }
- /** {@inheritDoc} */
- @Override
- public void init(final double t0, final double[] primary0, final double[] secondary0, final double finalTime) {
- equations.init(t0, convert(primary0), convert(secondary0), finalTime);
- }
- /** {@inheritDoc} */
- @Override
- public double[] computeDerivatives(final double t, final double[] primary, final double[] primaryDot,
- final double[] secondary) {
- return convert(equations.computeDerivatives(t, convert(primary), convert(primaryDot), convert(secondary)));
- }
- };
- }
- /** Convert a complex state (typically the initial state).
- * @param state state to convert
- * @return converted state
- */
- public ODEState convertState(final ComplexODEState state) {
- final double[][] secondary = new double[state.getNumberOfSecondaryStates()][];
- for (int index = 0; index < secondary.length; ++index) {
- secondary[index] = convert(state.getSecondaryState(index + 1));
- }
- return new ODEState(state.getTime(),
- convert(state.getPrimaryState()),
- secondary);
- }
- /** Convert a real state and derivatives (typically the final state or some intermediate state for
- * step handling or event handling).
- * @param state state to convert
- * @return converted state
- */
- public ComplexODEStateAndDerivative convertState(final ODEStateAndDerivative state) {
- final Complex[][] secondary = new Complex[state.getNumberOfSecondaryStates()][];
- final Complex[][] secondaryDerivative = new Complex[state.getNumberOfSecondaryStates()][];
- for (int index = 0; index < secondary.length; ++index) {
- secondary[index] = convert(state.getSecondaryState(index + 1));
- secondaryDerivative[index] = convert(state.getSecondaryDerivative(index + 1));
- }
- return new ComplexODEStateAndDerivative(state.getTime(),
- convert(state.getPrimaryState()),
- convert(state.getPrimaryDerivative()),
- secondary, secondaryDerivative);
- }
- /** Convert a real array into a complex array.
- * @param a array to convert
- * @return converted array
- */
- private Complex[] convert(final double[] a) {
- final Complex[] converted = new Complex[a.length / 2];
- for (int i = 0; i < converted.length; ++i) {
- converted[i] = new Complex(a[2 * i], a[2 * i + 1]);
- }
- return converted;
- }
- /** Convert a complex array into a real array.
- * @param a array to convert
- * @return converted array
- */
- private double[] convert(final Complex[] a) {
- final double[] converted = new double[a.length * 2];
- for (int i = 0; i < a.length; ++i) {
- converted[2 * i] = a[i].getReal();
- converted[2 * i + 1] = a[i].getImaginary();
- }
- return converted;
- }
- }