1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.migration.ode;
23
24 import java.lang.reflect.Array;
25 import java.lang.reflect.Constructor;
26 import java.lang.reflect.InvocationTargetException;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.List;
30
31 import org.hipparchus.exception.LocalizedCoreFormats;
32 import org.hipparchus.exception.MathIllegalArgumentException;
33 import org.hipparchus.exception.MathIllegalStateException;
34 import org.hipparchus.ode.ExpandableODE;
35 import org.hipparchus.ode.LocalizedODEFormats;
36 import org.hipparchus.ode.NamedParameterJacobianProvider;
37 import org.hipparchus.ode.ODEState;
38 import org.hipparchus.ode.OrdinaryDifferentialEquation;
39 import org.hipparchus.ode.ParameterConfiguration;
40 import org.hipparchus.ode.ParametersController;
41 import org.hipparchus.ode.SecondaryODE;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 @Deprecated
68 public class JacobianMatrices {
69
70
71 private ExpandableODE efode;
72
73
74 private int index;
75
76
77 private MainStateJacobianProvider jode;
78
79
80 private ParametersController parametersController;
81
82
83 private int stateDim;
84
85
86 private MutableParameterConfiguration[] selectedParameters;
87
88
89 private List<NamedParameterJacobianProvider> jacobianProviders;
90
91
92 private int paramDim;
93
94
95 private boolean dirtyParameter;
96
97
98 private double[] matricesData;
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115 public JacobianMatrices(final OrdinaryDifferentialEquation fode, final double[] hY,
116 final String... parameters)
117 throws MathIllegalArgumentException {
118 this(new MainStateJacobianWrapper(fode, hY), parameters);
119 }
120
121
122
123
124
125
126
127
128
129
130
131
132
133 public JacobianMatrices(final MainStateJacobianProvider jode,
134 final String... parameters) {
135
136 this.efode = null;
137 this.index = -1;
138
139 this.jode = jode;
140 this.parametersController = null;
141
142 this.stateDim = jode.getDimension();
143
144 if (parameters == null) {
145 selectedParameters = null;
146 paramDim = 0;
147 } else {
148 this.selectedParameters = new MutableParameterConfiguration[parameters.length];
149 for (int i = 0; i < parameters.length; ++i) {
150 selectedParameters[i] = new MutableParameterConfiguration(parameters[i], Double.NaN);
151 }
152 paramDim = parameters.length;
153 }
154 this.dirtyParameter = false;
155
156 this.jacobianProviders = new ArrayList<>();
157
158
159
160 matricesData = new double[(stateDim + paramDim) * stateDim];
161 for (int i = 0; i < stateDim; ++i) {
162 matricesData[i * (stateDim + 1)] = 1.0;
163 }
164
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179 public void registerVariationalEquations(final ExpandableODE expandable)
180 throws MathIllegalArgumentException, MismatchedEquations {
181
182
183 final OrdinaryDifferentialEquation ode = (jode instanceof MainStateJacobianWrapper) ?
184 ((MainStateJacobianWrapper) jode).ode :
185 jode;
186 if (expandable.getPrimary() != ode) {
187 throw new MismatchedEquations();
188 }
189
190 efode = expandable;
191 index = efode.addSecondaryEquations(new JacobiansSecondaryODE());
192
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213 public ODEState setUpInitialState(final ODEState initialState) {
214
215
216 final double[][] secondary = new double[efode.getMapper().getNumberOfEquations() - 1][];
217 for (int i = 0; i < initialState.getNumberOfSecondaryStates(); ++i) {
218 if (i + 1 != index) {
219 secondary[i] = initialState.getSecondaryState(i + 1);
220 }
221 }
222 secondary[index - 1] = matricesData;
223
224
225 return new ODEState(initialState.getTime(), initialState.getPrimaryState(), secondary);
226
227 }
228
229
230
231
232 public void addParameterJacobianProvider(final NamedParameterJacobianProvider provider) {
233 jacobianProviders.add(provider);
234 }
235
236
237
238
239
240 @Deprecated
241 public void setParameterizedODE(final ParametersController pc) {
242 setParametersController(pc);
243 }
244
245
246
247
248 public void setParametersController(final ParametersController parametersController) {
249 this.parametersController = parametersController;
250 dirtyParameter = true;
251 }
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270 public void setParameterStep(final String parameter, final double hP)
271 throws MathIllegalArgumentException {
272
273 for (MutableParameterConfiguration param: selectedParameters) {
274 if (parameter.equals(param.getParameterName())) {
275 param.setHP(hP);
276 dirtyParameter = true;
277 return;
278 }
279 }
280
281 throw new MathIllegalArgumentException(LocalizedODEFormats.UNKNOWN_PARAMETER, parameter);
282
283 }
284
285
286
287
288
289
290
291
292
293
294
295
296 public void setInitialMainStateJacobian(final double[][] dYdY0)
297 throws MathIllegalArgumentException {
298
299
300 checkDimension(stateDim, dYdY0);
301 checkDimension(stateDim, dYdY0[0]);
302
303
304 int i = 0;
305 for (final double[] row : dYdY0) {
306 System.arraycopy(row, 0, matricesData, i, stateDim);
307 i += stateDim;
308 }
309
310 }
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325 public void setInitialParameterJacobian(final String pName, final double[] dYdP)
326 throws MathIllegalArgumentException {
327
328
329 checkDimension(stateDim, dYdP);
330
331
332 int i = stateDim * stateDim;
333 for (MutableParameterConfiguration param: selectedParameters) {
334 if (pName.equals(param.getParameterName())) {
335 System.arraycopy(dYdP, 0, matricesData, i, stateDim);
336 return;
337 }
338 i += stateDim;
339 }
340
341 throw new MathIllegalArgumentException(LocalizedODEFormats.UNKNOWN_PARAMETER, pName);
342
343 }
344
345
346
347
348
349 public double[][] extractMainSetJacobian(final ODEState state) {
350
351
352 final double[] p = state.getSecondaryState(index);
353
354 final double[][] dYdY0 = new double[stateDim][stateDim];
355 int j = 0;
356 for (int i = 0; i < stateDim; i++) {
357 System.arraycopy(p, j, dYdY0[i], 0, stateDim);
358 j += stateDim;
359 }
360
361 return dYdY0;
362
363 }
364
365
366
367
368
369
370 public double[] extractParameterJacobian(final ODEState state, final String pName) {
371
372
373 final double[] p = state.getSecondaryState(index);
374
375 final double[] dYdP = new double[stateDim];
376 int i = stateDim * stateDim;
377 for (MutableParameterConfiguration param: selectedParameters) {
378 if (param.getParameterName().equals(pName)) {
379 System.arraycopy(p, i, dYdP, 0, stateDim);
380 break;
381 }
382 i += stateDim;
383 }
384
385 return dYdP;
386
387 }
388
389
390
391
392
393
394 private void checkDimension(final int expected, final Object array)
395 throws MathIllegalArgumentException {
396 int arrayDimension = (array == null) ? 0 : Array.getLength(array);
397 if (arrayDimension != expected) {
398 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
399 arrayDimension, expected);
400 }
401 }
402
403
404
405
406
407
408
409 private class JacobiansSecondaryODE implements SecondaryODE {
410
411
412 @Override
413 public int getDimension() {
414 return stateDim * (stateDim + paramDim);
415 }
416
417
418 @Override
419 public double[] computeDerivatives(final double t, final double[] y, final double[] yDot,
420 final double[] z)
421 throws MathIllegalArgumentException, MathIllegalStateException {
422
423 try {
424
425
426 Constructor<ParameterConfiguration> configCtr =
427 ParameterConfiguration.class.getDeclaredConstructor(String.class, Double.TYPE);
428 configCtr.setAccessible(true);
429 @SuppressWarnings("unchecked")
430 Constructor<NamedParameterJacobianProvider> providerCtr =
431 (Constructor<NamedParameterJacobianProvider>)
432 Class.forName("org.hipparchus.ode.ParameterJacobianWrapper").getDeclaredConstructor(OrdinaryDifferentialEquation.class,
433 double[].class,
434 ParametersController.class,
435 ParameterConfiguration[].class);
436 providerCtr.setAccessible(true);
437 if (dirtyParameter && (paramDim != 0)) {
438 ParameterConfiguration [] immutable = new ParameterConfiguration[selectedParameters.length];
439 for (int i = 0; i < selectedParameters.length; ++i) {
440 immutable[i] = configCtr.newInstance(selectedParameters[i].getParameterName(),
441 selectedParameters[i].getHP());
442 }
443 jacobianProviders.add(providerCtr.newInstance(jode, new double[jode.getDimension()],
444 parametersController, immutable));
445 dirtyParameter = false;
446 }
447
448 } catch (InstantiationException | IllegalAccessException | IllegalArgumentException |
449 InvocationTargetException | NoSuchMethodException | SecurityException | ClassNotFoundException e) {
450 throw new MathIllegalStateException(e, LocalizedCoreFormats.SIMPLE_MESSAGE, e.getLocalizedMessage());
451 }
452
453
454
455
456
457 double[][] dFdY = jode.computeMainStateJacobian(t, y, yDot);
458
459
460 final double[] zDot = new double[z.length];
461 for (int i = 0; i < stateDim; ++i) {
462 final double[] dFdYi = dFdY[i];
463 for (int j = 0; j < stateDim; ++j) {
464 double s = 0;
465 final int startIndex = j;
466 int zIndex = startIndex;
467 for (int l = 0; l < stateDim; ++l) {
468 s += dFdYi[l] * z[zIndex];
469 zIndex += stateDim;
470 }
471 zDot[startIndex + i * stateDim] = s;
472 }
473 }
474
475 if (paramDim != 0) {
476
477 int startIndex = stateDim * stateDim;
478 for (MutableParameterConfiguration param: selectedParameters) {
479 boolean found = false;
480 for (int k = 0 ; (!found) && (k < jacobianProviders.size()); ++k) {
481 final NamedParameterJacobianProvider provider = jacobianProviders.get(k);
482 if (provider.isSupported(param.getParameterName())) {
483 final double[] dFdP =
484 provider.computeParameterJacobian(t, y, yDot,
485 param.getParameterName());
486 for (int i = 0; i < stateDim; ++i) {
487 final double[] dFdYi = dFdY[i];
488 int zIndex = startIndex;
489 double s = dFdP[i];
490 for (int l = 0; l < stateDim; ++l) {
491 s += dFdYi[l] * z[zIndex];
492 zIndex++;
493 }
494 zDot[startIndex + i] = s;
495 }
496 found = true;
497 }
498 }
499 if (! found) {
500 Arrays.fill(zDot, startIndex, startIndex + stateDim, 0.0);
501 }
502 startIndex += stateDim;
503 }
504 }
505
506 return zDot;
507
508 }
509 }
510
511
512
513
514 private static class MainStateJacobianWrapper implements MainStateJacobianProvider {
515
516
517 private final OrdinaryDifferentialEquation ode;
518
519
520 private final double[] hY;
521
522
523
524
525
526
527
528 MainStateJacobianWrapper(final OrdinaryDifferentialEquation ode,
529 final double[] hY)
530 throws MathIllegalArgumentException {
531 this.ode = ode;
532 this.hY = hY.clone();
533 if (hY.length != ode.getDimension()) {
534 throw new MathIllegalArgumentException(LocalizedCoreFormats.DIMENSIONS_MISMATCH,
535 ode.getDimension(), hY.length);
536 }
537 }
538
539
540 @Override
541 public int getDimension() {
542 return ode.getDimension();
543 }
544
545
546 @Override
547 public double[] computeDerivatives(double t, double[] y)
548 throws MathIllegalArgumentException, MathIllegalStateException {
549 return ode.computeDerivatives(t, y);
550 }
551
552
553 @Override
554 public double[][] computeMainStateJacobian(double t, double[] y, double[] yDot)
555 throws MathIllegalArgumentException, MathIllegalStateException {
556
557 final int n = ode.getDimension();
558 final double[][] dFdY = new double[n][n];
559 for (int j = 0; j < n; ++j) {
560 final double savedYj = y[j];
561 y[j] += hY[j];
562 final double[] tmpDot = ode.computeDerivatives(t, y);
563 for (int i = 0; i < n; ++i) {
564 dFdY[i][j] = (tmpDot[i] - yDot[i]) / hY[j];
565 }
566 y[j] = savedYj;
567 }
568 return dFdY;
569 }
570
571 }
572
573
574
575
576 public static class MismatchedEquations extends MathIllegalArgumentException {
577
578
579 private static final long serialVersionUID = 20120902L;
580
581
582 public MismatchedEquations() {
583 super(LocalizedODEFormats.UNMATCHED_ODE_IN_EXPANDED_SET);
584 }
585
586 }
587
588
589 private static class MutableParameterConfiguration {
590
591
592 private String parameterName;
593
594
595 private double hP;
596
597
598
599
600
601 MutableParameterConfiguration(final String parameterName, final double hP) {
602 this.parameterName = parameterName;
603 this.hP = hP;
604 }
605
606
607
608
609 public String getParameterName() {
610 return parameterName;
611 }
612
613
614
615
616 public double getHP() {
617 return hP;
618 }
619
620
621
622
623 public void setHP(final double hParam) {
624 this.hP = hParam;
625 }
626
627 }
628
629 }
630