25 #ifndef MIRTK_FreeFormTransformationRungeKutta_H 26 #define MIRTK_FreeFormTransformationRungeKutta_H 28 #include "mirtk/Math.h" 29 #include "mirtk/Matrix.h" 30 #include "mirtk/Vector3D.h" 31 #include "mirtk/TransformationJacobian.h" 53 dk(0, 0) = (Dv(0, 0) * dx(0, 0) + Dv(0, 1) * dx(1, 0) + Dv(0, 2) * dx(2, 0)) * h;
54 dk(0, 1) = (Dv(0, 0) * dx(0, 1) + Dv(0, 1) * dx(1, 1) + Dv(0, 2) * dx(2, 1)) * h;
55 dk(0, 2) = (Dv(0, 0) * dx(0, 2) + Dv(0, 1) * dx(1, 2) + Dv(0, 2) * dx(2, 2)) * h;
56 dk(1, 0) = (Dv(1, 0) * dx(0, 0) + Dv(1, 1) * dx(1, 0) + Dv(1, 2) * dx(2, 0)) * h;
57 dk(1, 1) = (Dv(1, 0) * dx(0, 1) + Dv(1, 1) * dx(1, 1) + Dv(1, 2) * dx(2, 1)) * h;
58 dk(1, 2) = (Dv(1, 0) * dx(0, 2) + Dv(1, 1) * dx(1, 2) + Dv(1, 2) * dx(2, 2)) * h;
59 dk(2, 0) = (Dv(2, 0) * dx(0, 0) + Dv(2, 1) * dx(1, 0) + Dv(2, 2) * dx(2, 0)) * h;
60 dk(2, 1) = (Dv(2, 0) * dx(0, 1) + Dv(2, 1) * dx(1, 1) + Dv(2, 2) * dx(2, 1)) * h;
61 dk(2, 2) = (Dv(2, 0) * dx(0, 2) + Dv(2, 1) * dx(1, 2) + Dv(2, 2) * dx(2, 2)) * h;
68 dk(0, 0) = (Dv(0, 0) * dx(0, 0) + Dv(0, 1) * dx(1, 0) + Dv(0, 2) * dx(2, 0) + dv[0]) * h;
69 dk(0, 1) = (Dv(0, 0) * dx(0, 1) + Dv(0, 1) * dx(1, 1) + Dv(0, 2) * dx(2, 1) ) * h;
70 dk(0, 2) = (Dv(0, 0) * dx(0, 2) + Dv(0, 1) * dx(1, 2) + Dv(0, 2) * dx(2, 2) ) * h;
71 dk(1, 0) = (Dv(1, 0) * dx(0, 0) + Dv(1, 1) * dx(1, 0) + Dv(1, 2) * dx(2, 0) ) * h;
72 dk(1, 1) = (Dv(1, 0) * dx(0, 1) + Dv(1, 1) * dx(1, 1) + Dv(1, 2) * dx(2, 1) + dv[1]) * h;
73 dk(1, 2) = (Dv(1, 0) * dx(0, 2) + Dv(1, 1) * dx(1, 2) + Dv(1, 2) * dx(2, 2) ) * h;
74 dk(2, 0) = (Dv(2, 0) * dx(0, 0) + Dv(2, 1) * dx(1, 0) + Dv(2, 2) * dx(2, 0) ) * h;
75 dk(2, 1) = (Dv(2, 0) * dx(0, 1) + Dv(2, 1) * dx(1, 1) + Dv(2, 2) * dx(2, 1) ) * h;
76 dk(2, 2) = (Dv(2, 0) * dx(0, 2) + Dv(2, 1) * dx(1, 2) + Dv(2, 2) * dx(2, 2) + dv[2]) * h;
101 template <
class TFreeFormTransformation,
class TButcherTableau>
108 typedef TButcherTableau
BT;
111 static void Transform(
const TFreeFormTransformation *v,
112 double &x,
double &y,
double &z,
113 double t1,
double t2,
double dt)
115 if (t1 == t2)
return;
118 const double d = copysign(1.0, t2 - t1);
119 double h = d * abs(dt);
125 while (d * t < d * t2) {
127 if (d * (t + h) > d * t2) h = t2 - t;
129 if (BT::fsal && t != t1) k[0] = k[BT::s - 1], i = 1;
131 for (; i < BT::s; i++) {
133 k[i].
_x = x, k[i].
_y = y, k[i].
_z = z;
134 for (j = 0; j < i; j++) k[i] += k[j] * BT::a[i][j];
135 v->WorldToLattice(k[i]._x, k[i]._y, k[i]._z);
136 l = v->TimeToLattice(t + BT::c[i] * h);
138 v->Evaluate(k[i]._x, k[i]._y, k[i]._z, l);
142 for (i = 0; i < BT::s; i++) {
143 x += k[i].
_x * BT::b[i];
144 y += k[i].
_y * BT::b[i];
145 z += k[i].
_z * BT::b[i];
152 static void Jacobian(
const TFreeFormTransformation *v,
154 double &x,
double &y,
double &z,
155 double t1,
double t2,
double dt)
157 if (t1 == t2)
return;
163 const double d = copysign(1.0, t2 - t1);
164 double h = d * abs(dt);
168 for (i = 0; i < BT::s; ++i) dk[i].Initialize(3, 3);
172 while (d * t < d * t2) {
174 if (d * (t + h) > d * t2) h = t2 - t;
176 if (BT::fsal && t != t1) {
183 for (; i < BT::s; i++) {
185 k[i].
_x = x, k[i].
_y = y, k[i].
_z = z;
186 for (j = 0; j < i; j++) k[i] += k[j] * BT::a[i][j];
187 v->WorldToLattice(k[i]._x, k[i]._y, k[i]._z);
188 l = v->TimeToLattice(t + BT::c[i] * h);
190 v->EvaluateJacobianWorld(Dv, k[i]._x, k[i]._y, k[i]._z, l);
192 v->Evaluate(k[i]._x, k[i]._y, k[i]._z, l);
196 for (j = 0; j < i; j++) dx += dk[j] * BT::a[i][j];
197 dkdx(dk[i], Dv, dx, h);
201 for (i = 0; i < BT::s; i++) {
202 x += k[i].
_x * BT::b[i];
203 y += k[i].
_y * BT::b[i];
204 z += k[i].
_z * BT::b[i];
205 dx += dk[i] * BT::b[i];
213 static void JacobianDOFs(
const TFreeFormTransformation *v,
214 Matrix &jac,
int ci,
int cj,
int ck,
int cl,
215 double &x,
double &y,
double &z,
216 double t1,
double t2,
double dt)
218 if (t1 == t2)
return;
225 const double d = copysign(1.0, t2 - t1);
226 double h = d * abs(dt);
230 for (i = 0; i < BT::s; i++) dk[i].Initialize(3, 3);
234 while (d * t < d * t2) {
236 if (d * (t + h) > d * t2) h = t2 - t;
238 if (BT::fsal && t != t1) {
245 for (; i < BT::s; i++) {
247 k[i].
_x = x, k[i].
_y = y, k[i].
_z = z;
248 for (j = 0; j < i; j++) k[i] += k[j] * BT::a[i][j];
249 v->WorldToLattice(k[i]._x, k[i]._y, k[i]._z);
250 l = v->TimeToLattice(t + BT::c[i] * h);
252 v->EvaluateJacobianWorld(Dv, k[i]._x, k[i]._y, k[i]._z, l);
253 v->EvaluateJacobianDOFs (dv, ci, cj, ck, cl, k[i]._x, k[i]._y, k[i]._z, l);
255 v->Evaluate(k[i]._x, k[i]._y, k[i]._z, l);
259 for (j = 0; j < i; j++) dx += dk[j] * BT::a[i][j];
261 dkdp(dk[i], Dv, dx, dv, h);
264 for (i = 0; i < BT::s; i++) {
265 x += k[i].
_x * BT::b[i];
266 y += k[i].
_y * BT::b[i];
267 z += k[i].
_z * BT::b[i];
268 jac += dk[i] * BT::b[i];
275 static void JacobianDOFs(
const TFreeFormTransformation *v,
277 double &x,
double &y,
double &z,
278 double t1,
double t2,
double dt)
280 if (t1 == t2)
return;
288 const double d = copysign(1.0, t2 - t1);
289 double h = d * abs(dt);
295 while (d * t < d * t2) {
297 if (d * (t + h) > d * t2) h = t2 - t;
299 if (BT::fsal && t != t1) {
300 k [0] = k [BT::s - 1];
301 dk[0] = dk[BT::s - 1];
306 for (; i < BT::s; i++) {
308 k[i].
_x = x, k[i].
_y = y, k[i].
_z = z;
309 for (j = 0; j < i; j++) k[i] += k[j] * BT::a[i][j];
310 v->WorldToLattice(k[i]._x, k[i]._y, k[i]._z);
311 l = v->TimeToLattice(t + BT::c[i] * h);
313 v->EvaluateJacobianWorld(Dv, k[i]._x, k[i]._y, k[i]._z, l);
314 v->EvaluateJacobianDOFs (dk[i], k[i]._x, k[i]._y, k[i]._z, l);
316 v->Evaluate(k[i]._x, k[i]._y, k[i]._z, l);
320 for (j = 0; j < i; j++) dx.
add(dk[j], BT::a[i][j]);
327 for (i = 0; i < BT::s; i++) {
328 x += k[i].
_x * BT::b[i];
329 y += k[i].
_y * BT::b[i];
330 z += k[i].
_z * BT::b[i];
331 jac.
add(dk[i], BT::b[i]);
359 template <
class TFreeFormTransformation,
class TButcherTableau>
366 typedef TButcherTableau
BT;
369 static void Transform(
const TFreeFormTransformation *v,
370 double &x,
double &y,
double &z,
371 double t1,
double t2,
double mindt,
double maxdt,
double tol)
373 if (t1 == t2)
return;
381 const double d = copysign(1.0, h);
382 const double e = 1.0 /
static_cast<double>(BT::p);
387 if (abs(h) > maxdt) h = copysign(maxdt, d);
391 while (d * t < d * t2) {
393 if (d * (t + h) > d * t2) h = t2 - t;
395 if (BT::fsal && t != t1) k[0] = k[BT::s - 1], i = 1;
397 for (; i < BT::s; i++) {
398 k[i].
_x = x, k[i].
_y = y, k[i].
_z = z;
399 for (j = 0; j < i; j++) k[i] += k[j] * BT::a[i][j];
400 v->WorldToLattice(k[i]._x, k[i]._y, k[i]._z);
401 l = v->TimeToLattice(t + BT::c[i] * h);
402 v->Evaluate(k[i]._x, k[i]._y, k[i]._z, l);
406 next.
_x = x, next.
_y = y, next.
_z = z;
407 for (i = 0; i < BT::s; i++) next += k[i] * BT::b[1][i];
411 tmp.
_x = x, tmp.
_y = y, tmp.
_z = z;
412 for (i = 0; i < BT::s; i++) tmp += k[i] * BT::b[0][i];
414 error = max(max(abs(next.
_x - tmp.
_x),
415 abs(next.
_y - tmp.
_y)),
416 abs(next.
_z - tmp.
_z));
418 if (abs(h) > mindt && error > tol) {
420 h *= 0.8 * pow(tol / error, e);
421 if (abs(h) < mindt) h = copysign(mindt, d);
426 hnext = 0.8 * pow(tol / error, e) * h;
427 if (abs(hnext) < mindt) hnext = copysign(mindt, d);
428 else if (abs(hnext) > maxdt) hnext = copysign(maxdt, d);
444 static void Jacobian(
const TFreeFormTransformation *v,
445 Matrix &jac,
double &x,
double &y,
double &z,
446 double t1,
double t2,
double mindt,
double maxdt,
double tol)
448 if (t1 == t2)
return;
456 const double d = copysign(1.0, h);
460 const double e = 1.0 /
static_cast<double>(BT::p);
464 for (i = 0; i < BT::s; i++) dk[i].Initialize(3, 3);
467 if (abs(h) > maxdt) h = copysign(maxdt, d);
471 while (d * t < d * t2) {
473 if (d * (t + h) > d * t2) h = t2 - t;
475 if (BT::fsal && t != t1) {
482 for (; i < BT::s; i++) {
484 k[i].
_x = x, k[i].
_y = y, k[i].
_z = z;
485 for (j = 0; j < i; j++) k[i] += k[j] * BT::a[i][j];
486 v->WorldToLattice(k[i]._x, k[i]._y, k[i]._z);
487 l = v->TimeToLattice(t + BT::c[i] * h);
489 v->EvaluateJacobianWorld(Dv, k[i]._x, k[i]._y, k[i]._z, l);
491 v->Evaluate(k[i]._x, k[i]._y, k[i]._z, l);
495 for (j = 0; j < i; j++) dx += dk[j] * BT::a[i][j];
497 dkdx(dk[i], Dv, dx, h);
500 next.
_x = x, next.
_y = y, next.
_z = z;
501 for (i = 0; i < BT::s; i++) next += k[i] * BT::b[1][i];
505 tmp.
_x = x, tmp.
_y = y, tmp.
_z = z;
506 for (i = 0; i < BT::s; i++) tmp += k[i] * BT::b[0][i];
508 error = max(max(abs(next.
_x - tmp.
_x),
509 abs(next.
_y - tmp.
_y)),
510 abs(next.
_z - tmp.
_z));
512 if (abs(h) > mindt && error > tol) {
514 h *= 0.8 * pow(tol / error, e);
515 if (abs(h) < mindt) h = copysign(mindt, d);
520 hnext = 0.8 * pow(tol / error, e) * h;
521 if (abs(hnext) < mindt) hnext = copysign(mindt, d);
522 else if (abs(hnext) > maxdt) hnext = copysign(maxdt, d);
529 for (i = 0; i < BT::s; i++) dx += dk[i] * BT::b[1][i];
542 static void JacobianDOFs(
const TFreeFormTransformation *v,
543 Matrix &jac,
int ci,
int cj,
int ck,
int cl,
544 double &x,
double &y,
double &z,
double t1,
double t2,
545 double mindt,
double maxdt,
double tol)
547 if (t1 == t2)
return;
556 const double d = copysign(1.0, h);
560 const double e = 1.0 /
static_cast<double>(BT::p);
564 for (i = 0; i < BT::s; i++) dk[i].Initialize(3, 3);
567 if (abs(h) > maxdt) h = copysign(maxdt, d);
571 while (d * t < d * t2) {
573 if (d * (t + h) > d * t2) h = t2 - t;
575 if (BT::fsal && t != t1) {
582 for (; i < BT::s; i++) {
584 k[i].
_x = x, k[i].
_y = y, k[i].
_z = z;
585 for (j = 0; j < i; j++) k[i] += k[j] * BT::a[i][j];
586 v->WorldToLattice(k[i]._x, k[i]._y, k[i]._z);
587 l = v->TimeToLattice(t + BT::c[i] * h);
589 v->EvaluateJacobianWorld(Dv, k[i]._x, k[i]._y, k[i]._z, l);
590 v->EvaluateJacobianDOFs (dv, ci, cj, ck, cl, k[i]._x, k[i]._y, k[i]._z, l);
592 v->Evaluate(k[i]._x, k[i]._y, k[i]._z, l);
596 for (j = 0; j < i; j++) dx += dk[j] * BT::a[i][j];
598 dkdp(dk[i], Dv, dx, dv, h);
601 next.
_x = x, next.
_y = y, next.
_z = z;
602 for (i = 0; i < BT::s; i++) next += k[i] * BT::b[1][i];
606 tmp.
_x = x, tmp.
_y = y, tmp.
_z = z;
607 for (i = 0; i < BT::s; i++) tmp += k[i] * BT::b[0][i];
609 error = max(max(abs(next.
_x - tmp.
_x),
610 abs(next.
_y - tmp.
_y)),
611 abs(next.
_z - tmp.
_z));
613 if (abs(h) > mindt && error > tol) {
615 h *= 0.8 * pow(tol / error, e);
616 if (abs(h) < mindt) h = copysign(mindt, d);
621 hnext = 0.8 * pow(tol / error, e) * h;
622 if (abs(hnext) < mindt) hnext = copysign(mindt, d);
623 else if (abs(hnext) > maxdt) hnext = copysign(maxdt, d);
629 for (i = 0; i < BT::s; i++) jac += dk[i] * BT::b[1][i];
641 static void JacobianDOFs(
const TFreeFormTransformation *v,
643 double &x,
double &y,
double &z,
644 double t1,
double t2,
double mindt,
double maxdt,
double tol)
646 if (t1 == t2)
return;
655 const double d = copysign(1.0, h);
660 const double e = 1.0 / double(BT::p);
665 if (abs(h) > maxdt) h = copysign(maxdt, d);
669 while (d * t < d * t2) {
671 if (d * (t + h) > d * t2) h = t2 - t;
673 if (BT::fsal && t != t1) {
680 for (; i < BT::s; i++) {
682 k[i].
_x = x, k[i].
_y = y, k[i].
_z = z;
683 for (j = 0; j < i; j++) k[i] += k[j] * BT::a[i][j];
684 v->WorldToLattice(k[i]._x, k[i]._y, k[i]._z);
685 l = v->TimeToLattice(t + BT::c[i] * h);
687 v->EvaluateJacobianWorld(Dv, k[i]._x, k[i]._y, k[i]._z, l);
688 v->EvaluateJacobianDOFs (dk[i], k[i]._x, k[i]._y, k[i]._z, l);
690 v->Evaluate(k[i]._x, k[i]._y, k[i]._z, l);
694 for (j = 0; j < i; j++) dx.
add(dk[j], BT::a[i][j]);
701 next.
_x = x, next.
_y = y, next.
_z = z;
702 for (i = 0; i < BT::s; i++) next += k[i] * BT::b[1][i];
706 tmp.
_x = x, tmp.
_y = y, tmp.
_z = z;
707 for (i = 0; i < BT::s; i++) tmp += k[i] * BT::b[0][i];
709 error = max(max(abs(next.
_x - tmp.
_x),
710 abs(next.
_y - tmp.
_y)),
711 abs(next.
_z - tmp.
_z));
713 if (abs(h) > mindt && error > tol) {
715 h *= 0.8 * pow(tol / error, e);
716 if (abs(h) < mindt) h = copysign(mindt, d);
721 hnext = 0.8 * pow(tol / error, e) * h;
722 if (abs(hnext) < mindt) hnext = copysign(mindt, d);
723 else if (abs(hnext) > maxdt) hnext = copysign(maxdt, d);
729 for (i = 0; i < BT::s; i++) jac.
add(dk[i], BT::b[1][i]);
748 #define MIRTK_DECLARE_FFDRK_EXPLICIT(NAME, S) \ 749 struct FreeFormTransformationButcherTableau##NAME \ 751 static const int s = S; \ 752 static const int p; \ 753 static const bool fsal; \ 754 static const double a[S][S]; \ 755 static const double b[S]; \ 756 static const double c[S]; \ 759 template <class TFreeFormTransformation> \ 760 class FreeFormTransformationIntegration##NAME \ 761 : public mirtk::FreeFormTransformationExplicitRungeKutta \ 762 <TFreeFormTransformation, FreeFormTransformationButcherTableau##NAME> \ 767 #define MIRTK_DECLARE_FFDRK_EMBEDDED(NAME, S) \ 768 struct FreeFormTransformationButcherTableau##NAME \ 770 static const int s = S; \ 771 static const int p; \ 772 static const bool fsal; \ 773 static const double a[S][S]; \ 774 static const double b[2][S]; \ 775 static const double c[S]; \ 778 template <class TFreeFormTransformation> \ 779 class FreeFormTransformationIntegration##NAME \ 780 : public mirtk::FreeFormTransformationEmbeddedRungeKutta \ 781 <TFreeFormTransformation, FreeFormTransformationButcherTableau##NAME> \ 786 #define MIRTK_DEFINE_FFDRK_EXPLICIT(NAME, S, P, FSAL, C, A, B) \ 788 const int FreeFormTransformationButcherTableau##NAME::p = P; \ 789 const bool FreeFormTransformationButcherTableau##NAME::fsal = FSAL; \ 790 const double FreeFormTransformationButcherTableau##NAME::a[S][S] = A; \ 791 const double FreeFormTransformationButcherTableau##NAME::b[S] = B; \ 792 const double FreeFormTransformationButcherTableau##NAME::c[S] = C 796 #define MIRTK_DEFINE_FFDRK_EMBEDDED(NAME, S, P, FSAL, C, A, BY, BZ) \ 798 const int FreeFormTransformationButcherTableau##NAME::p = P; \ 799 const bool FreeFormTransformationButcherTableau##NAME::fsal = FSAL; \ 800 const double FreeFormTransformationButcherTableau##NAME::a[S][S] = A; \ 801 const double FreeFormTransformationButcherTableau##NAME::b[2][S] = {BY, BZ}; \ 802 const double FreeFormTransformationButcherTableau##NAME::c[S] = C 810 MIRTK_DECLARE_FFDRK_EXPLICIT(RKE1, 1);
811 MIRTK_DECLARE_FFDRK_EMBEDDED(RKEH12, 2);
812 MIRTK_DECLARE_FFDRK_EXPLICIT(RKE2, 2);
813 MIRTK_DECLARE_FFDRK_EXPLICIT(RKH2, 2);
814 MIRTK_DECLARE_FFDRK_EMBEDDED(RKBS23, 4);
815 MIRTK_DECLARE_FFDRK_EXPLICIT(RK4, 4);
816 MIRTK_DECLARE_FFDRK_EMBEDDED(RKF45, 6);
817 MIRTK_DECLARE_FFDRK_EMBEDDED(RKCK45, 6);
818 MIRTK_DECLARE_FFDRK_EMBEDDED(RKDP45, 7);
823 #endif // MIRTK_FreeFormTransformationRungeKutta_H
Matrix & Ident()
Set to identity matrix.
void Transform(Array< T > &values, UnaryOperation op)
Apply unary operation for each array element in-place.