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 }