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    *      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  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  package org.hipparchus.ode;
23  
24  import java.util.Arrays;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  import org.hipparchus.exception.MathIllegalArgumentException;
30  import org.hipparchus.exception.MathIllegalStateException;
31  
32  /** Wrapper class to compute Jacobian matrices by finite differences for ODE
33   *  which do not compute them by themselves.
34   *
35   */
36  class ParameterJacobianWrapper implements ODEJacobiansProvider {
37  
38      /** ode base ordinary differential equation for which Jacobians
39       * matrices are requested. */
40      private final OrdinaryDifferentialEquation ode;
41  
42      /** Steps for finite difference computation of the jacobian df/dy w.r.t. state. */
43      private final double[] hY;
44  
45      /** Controller to change parameters. */
46      private final ParametersController controller;
47  
48      /** Steps for finite difference computation of the Jacobian df/dp w.r.t. parameters. */
49      private final Map<String, Double> hParam;
50  
51      /** Wrap a {@link ParametersController} into a {@link NamedParameterJacobianProvider}.
52       * @param ode ode base ordinary differential equation for which Jacobians
53       * matrices are requested
54       * @param hY step used for finite difference computation with respect to state vector
55       * @param controller controller to change parameters
56       * @param paramsAndSteps parameters and steps to compute the Jacobians df/dp
57       */
58      ParameterJacobianWrapper(final OrdinaryDifferentialEquation ode, final double[] hY,
59                               final ParametersController controller,
60                               final ParameterConfiguration[] paramsAndSteps) {
61          this.ode        = ode;
62          this.hY         = hY.clone();
63          this.controller = controller;
64          this.hParam     = new HashMap<>();
65  
66          // set up parameters for jacobian computation
67          for (final ParameterConfiguration param : paramsAndSteps) {
68              final String name = param.getParameterName();
69              if (controller.isSupported(name)) {
70                  hParam.put(name, param.getHP());
71              }
72          }
73      }
74  
75      /** Get the underlying ode.
76       * @return underlying ode
77       */
78      public OrdinaryDifferentialEquation getODE() {
79          return ode;
80      }
81  
82      /** {@inheritDoc} */
83      @Override
84      public int getDimension() {
85          return ode.getDimension();
86      }
87  
88      /** {@inheritDoc} */
89      @Override
90      public double[] computeDerivatives(double t, double[] y)
91          throws MathIllegalArgumentException, MathIllegalStateException {
92          return ode.computeDerivatives(t, y);
93      }
94  
95      /** {@inheritDoc} */
96      @Override
97      public double[][] computeMainStateJacobian(double t, double[] y, double[] yDot)
98          throws MathIllegalArgumentException, MathIllegalStateException {
99  
100         final int n = ode.getDimension();
101         final double[][] dFdY = new double[n][n];
102         for (int j = 0; j < n; ++j) {
103             final double savedYj = y[j];
104             y[j] += hY[j];
105             final double[] tmpDot = ode.computeDerivatives(t, y);
106             for (int i = 0; i < n; ++i) {
107                 dFdY[i][j] = (tmpDot[i] - yDot[i]) / hY[j];
108             }
109             y[j] = savedYj;
110         }
111         return dFdY;
112     }
113 
114     /** {@inheritDoc} */
115     @Override
116     public List<String> getParametersNames() {
117         return controller.getParametersNames();
118     }
119 
120     /** {@inheritDoc} */
121     @Override
122     public boolean isSupported(String name) {
123         return controller.isSupported(name);
124     }
125 
126     /** {@inheritDoc} */
127     @Override
128     public double[] computeParameterJacobian(final double t, final double[] y,
129                                              final double[] yDot, final String paramName)
130         throws MathIllegalArgumentException, MathIllegalStateException {
131 
132         final int n = ode.getDimension();
133         final double[] dFdP = new double[n];
134         if (controller.isSupported(paramName)) {
135 
136             // compute the jacobian df/dp w.r.t. parameter
137             final double p  = controller.getParameter(paramName);
138             final double hP = hParam.get(paramName);
139             controller.setParameter(paramName, p + hP);
140             final double[] tmpDot = ode.computeDerivatives(t, y);
141             for (int i = 0; i < n; ++i) {
142                 dFdP[i] = (tmpDot[i] - yDot[i]) / hP;
143             }
144             controller.setParameter(paramName, p);
145         } else {
146             Arrays.fill(dFdP, 0, n, 0.0);
147         }
148 
149         return dFdP;
150 
151     }
152 
153 }