00001 /* 00002 Copyright (C) 2010 - 2014 Christoph Haenisch 00003 00004 Chair of Medical Engineering (mediTEC) 00005 RWTH Aachen University 00006 Pauwelsstr. 20 00007 52074 Aachen 00008 Germany 00009 00010 See license.txt for more information. 00011 00012 Version 0.1.1 (2011-11-29) 00013 */ 00014 00021 #ifndef DIFFUSION_HPP_6431082743 00022 #define DIFFUSION_HPP_6431082743 00023 00024 00025 #include <assert.h> 00026 #include <cmath> 00027 #include <iostream> 00028 #include <vector> 00029 00030 #include <Eigen/Core> 00031 00032 #include "ErrorObj.hpp" 00033 #include "Tools.hpp" 00034 00035 00036 namespace TRTK 00037 { 00038 00039 00040 namespace Diffusion 00041 { 00042 00043 00044 template<class T> 00045 void print(const std::vector<T> & data) 00046 { 00047 for (unsigned i = 0; i < data.size(); ++i) 00048 { 00049 std::cout.precision(4); 00050 std::cout.width(8); 00051 std::cout << std::fixed << data[i]; 00052 } 00053 std::cout << std::endl; 00054 } 00055 00056 00059 enum BorderInterpolation 00060 { 00061 CONTINUED, 00062 CIRCULAR, 00063 INTERPOLATED, 00064 REFLECTED, 00065 ZERO 00066 }; 00067 00068 00071 enum Error 00072 { 00073 INVALID_ARGUMENT, 00074 UNKNOWN_ERROR 00075 }; 00076 00177 template <class T> 00178 const std::vector<T> firstDerivative(const std::vector<T> & signal, const BorderInterpolation interpolation = CONTINUED) 00179 { 00180 const unsigned size = signal.size(); 00181 const unsigned n = signal.size() - 1; 00182 00183 std::vector<T> derivative(size); 00184 00185 if (size == 0) 00186 { 00187 return derivative; 00188 } 00189 else if (size == 1) 00190 { 00191 derivative.push_back(T(0)); 00192 return derivative; 00193 } 00194 else 00195 { 00196 // compute boundaries 00197 00198 // left boundary 00199 // derivative[0] = 0.5 * (signal[1] - signal[-1]) 00200 00201 switch(interpolation) 00202 { 00203 case CONTINUED: 00204 // signal[-1] := signal[0] 00205 derivative[0] = 0.5 * (signal[1] - signal[0]); 00206 break; 00207 00208 case CIRCULAR: 00209 // signal[-1] := signal[n] 00210 derivative[0] = 0.5 * (signal[1] - signal[n]); 00211 break; 00212 00213 case INTERPOLATED: 00214 // signal[-1] := signal[0] + (signal[0] - signal[1]) = 2 * signal[0] - signal[1] 00215 derivative[0] = signal[1] - signal[0]; 00216 break; 00217 00218 case REFLECTED: 00219 // signal[-1] := signal[0] 00220 derivative[0] = 0.5 * (signal[1] - signal[0]); 00221 break; 00222 00223 case ZERO: 00224 // signal[-1] := 0 00225 derivative[0] = signal[1] / 2.0; 00226 break; 00227 00228 default: 00229 ErrorObj error("Unknown interpolation method."); 00230 error.setFunctionName("Differentiate"); 00231 error.setErrorCode(INVALID_ARGUMENT); 00232 throw error; 00233 } 00234 00235 // right boundary 00236 // derivative[n] = 0.5 * (signal[n+1] - signal[n-1]) 00237 00238 switch(interpolation) 00239 { 00240 case CONTINUED: 00241 // signal[n+1] := signal[n] 00242 derivative[n] = 0.5 * (signal[n] - signal[n-1]); 00243 break; 00244 00245 case CIRCULAR: 00246 // signal[n+1] := signal[0] 00247 derivative[n] = 0.5 * (signal[0] - signal[n-1]); 00248 break; 00249 00250 case INTERPOLATED: 00251 // signal[n+1] := signal[n] + (signal[n] - signal[n-1]) = 2 * signal[n] - signal[n-1] 00252 derivative[n] = signal[n] - signal[n-1]; 00253 break; 00254 00255 case REFLECTED: 00256 // signal[n+1] := signal[n] 00257 derivative[n] = 0.5 * (signal[n] - signal[n-1]); 00258 break; 00259 00260 case ZERO: 00261 // signal[n+1] := 0 00262 derivative[n] = -signal[n-1] / 2.0; 00263 break; 00264 00265 default: 00266 ErrorObj error("Unknown interpolation method."); 00267 error.setFunctionName("Differentiate"); 00268 error.setErrorCode(INVALID_ARGUMENT); 00269 throw error; 00270 } 00271 00272 // compute inner part 00273 00274 for (unsigned i = 1; i < n; ++i) 00275 { 00276 derivative[i] = 0.5 * (signal[i+1] - signal[i-1]); 00277 } 00278 00279 return derivative; 00280 } 00281 } 00282 00283 00359 template <class T> 00360 const std::vector<T> secondDerivative(const std::vector<T> & signal, const BorderInterpolation interpolation = CONTINUED) 00361 { 00362 const unsigned size = signal.size(); 00363 const unsigned n = signal.size() - 1; 00364 00365 std::vector<T> derivative(size); 00366 00367 if (size == 0) 00368 { 00369 return derivative; 00370 } 00371 else if (size == 1) 00372 { 00373 derivative.push_back(T(0)); 00374 return derivative; 00375 } 00376 else 00377 { 00378 // compute boundaries 00379 00380 // left boundary 00381 // derivative[0] = signal[-1] - 2 * signal[0] + signal[1] 00382 00383 switch(interpolation) 00384 { 00385 case CONTINUED: 00386 // signal[-1] := signal[0] 00387 derivative[0] = -signal[0] + signal[1]; 00388 break; 00389 00390 case CIRCULAR: 00391 // signal[-1] := signal[n] 00392 derivative[0] = signal[n] - 2 * signal[0] + signal[1]; 00393 break; 00394 00395 case INTERPOLATED: 00396 // signal[-1] := signal[0] + (signal[0] - signal[1]) = 2 * signal[0] - signal[1] 00397 derivative[0] = 0; 00398 break; 00399 00400 case REFLECTED: 00401 // signal[-1] := signal[0] 00402 derivative[0] = -signal[0] + signal[1]; 00403 break; 00404 00405 case ZERO: 00406 // signal[-1] := 0 00407 derivative[0] = -2 * signal[0] + signal[1]; 00408 break; 00409 00410 default: 00411 ErrorObj error("Unknown interpolation method."); 00412 error.setFunctionName("Differentiate"); 00413 error.setErrorCode(INVALID_ARGUMENT); 00414 throw error; 00415 } 00416 00417 // right boundary 00418 // derivative[n] = signal[n-1] - 2 * signal[n] + signal[n+1] 00419 00420 switch(interpolation) 00421 { 00422 case CONTINUED: 00423 // signal[n+1] := signal[n] 00424 derivative[n] = signal[n-1] -signal[n]; 00425 break; 00426 00427 case CIRCULAR: 00428 // signal[n+1] := signal[0] 00429 derivative[n] = signal[n-1] - 2 * signal[n] + signal[0]; 00430 break; 00431 00432 case INTERPOLATED: 00433 // signal[n+1] := signal[n] + (signal[n] - signal[n-1]) = 2 * signal[n] - signal[n-1] 00434 derivative[n] = 0; 00435 break; 00436 00437 case REFLECTED: 00438 // signal[n+1] := signal[n] 00439 derivative[n] = signal[n-1] -signal[n]; 00440 break; 00441 00442 case ZERO: 00443 // signal[n+1] := 0 00444 derivative[n] = signal[n-1] - 2 * signal[n]; 00445 break; 00446 00447 default: 00448 ErrorObj error("Unknown interpolation method."); 00449 error.setFunctionName("Differentiate"); 00450 error.setErrorCode(INVALID_ARGUMENT); 00451 throw error; 00452 } 00453 00454 // compute inner part 00455 00456 for (unsigned i = 1; i < n; ++i) 00457 { 00458 derivative[i] = signal[i-1] - 2 * signal[i] + signal[i+1]; 00459 } 00460 00461 return derivative; 00462 } 00463 } 00464 00465 00575 template <class T> 00576 const std::vector<T> linearDiffusion(const std::vector<T> & signal, 00577 T time, 00578 T step_size = 0.25, 00579 BorderInterpolation interpolation_method = CONTINUED) 00580 { 00581 /* The general formulation of a nonlinear diffusion is 00582 * 00583 * d/dt f(x, t) = div grad f(x, t) = laplace f(x, t) 00584 * 00585 * In the 1-dimensional case, the divergence and the gradient simplify to 00586 * an ordinary differentiation. Thus we get 00587 * 00588 * d/dt f(x, t) = d^2/dx^2 f(x, t) 00589 * 00590 * The diffusion equation can be easily solved by using the following 00591 * approximation 00592 * 00593 * d/dt f(x, t) = [f(x, t+h) - f(x, t) ] / h 00594 * 00595 * where h is the step size. With this, we get 00596 * 00597 * d/dt f(x, t+h) = f(x, t) + h * d^2/dx^2 f(x, t) 00598 * 00599 * Iterating until t + n * h = time, yields the solution. 00600 */ 00601 00602 00603 // If time == 0 return the unchanged signal. 00604 00605 if (Tools::isZero(time)) 00606 { 00607 return signal; 00608 } 00609 00610 // Modify step_size such, that after n iterations, time is really reached. 00611 00612 step_size = time / std::ceil(time / step_size); 00613 00614 // Compute the diffusion. 00615 00616 const unsigned N = signal.size(); 00617 std::vector<T> B(N); 00618 00619 std::vector<T> diffused_signal = signal; 00620 00621 for (T t = step_size; t <= time; t += step_size) 00622 { 00623 const std::vector<T> & derivative = secondDerivative(diffused_signal, interpolation_method); 00624 00625 for (unsigned i = 0; i < signal.size(); ++i) 00626 { 00627 diffused_signal[i] = diffused_signal[i] + step_size * derivative[i]; 00628 } 00629 } 00630 00631 return diffused_signal; 00632 } 00633 00634 00748 template <class T> 00749 const std::vector<T> nonlinearIsotropicDiffusion(const std::vector<T> & signal, 00750 T time, 00751 T step_size = 0.25, 00752 T alpha = 0.0, 00753 BorderInterpolation interpolation_method = CONTINUED) 00754 { 00755 /* The general formulation of a nonlinear diffusion is 00756 * 00757 * d/dt f(x, t) = div [ D(grad f(x, t)) * grad f(x, t) ] 00758 * 00759 * where D is the so-called diffusivity which we define to be 00760 * 00761 * D(x) = 1 / abs(x)^alpha 00762 * 00763 * In the 1-dimensional case, the divergence and the gradient simplify to 00764 * an ordinary differentiation. Thus we get 00765 * 00766 * d/dt f(x, t) = d/dx [ D(d/dx f(x, t)) * d/dx f(x, t) ] 00767 * 00768 * The diffusion equation can be easily solved by using the following 00769 * approximation 00770 * 00771 * d/dt f(x, t) = [f(x, t+h) - f(x, t) ] / h 00772 * 00773 * where h is the step size. With this, we get (A, B, and C are used within 00774 * the implementation) 00775 * 00776 * d/dt f(x, t+h) = f(x, t) + h * { d/dx [ D(d/dx f(x, t)) * d/dx f(x, t) ] } 00777 * = f(x, t) + h * { d/dx [ D(A) * A ] } 00778 * = f(x, t) + h * { d/dx [ B ] } 00779 * = f(x, t) + h * { C } 00780 * 00781 * Iterating until t + n * h = time, yields the solution. 00782 */ 00783 00784 00785 // If time == 0 return the unchanged signal. 00786 00787 if (Tools::isZero(time)) 00788 { 00789 return signal; 00790 } 00791 00792 // Modify step_size such, that after n iterations, time is really reached. 00793 00794 step_size = time / std::ceil(time / step_size); 00795 00796 // Compute the diffusion. 00797 00798 const unsigned N = signal.size(); 00799 std::vector<T> B(N); 00800 00801 std::vector<T> diffused_signal = signal; 00802 00803 for (T t = step_size; t <= time; t += step_size) 00804 { 00805 const std::vector<T> & A = firstDerivative(diffused_signal, interpolation_method); 00806 00807 for (unsigned i = 0; i < N; ++i) 00808 { 00809 const double epsilon = 1e-14; 00810 B[i] = 1 / std::pow(std::abs(A[i] + epsilon), alpha) * A[i]; 00811 } 00812 00813 const std::vector<T> & C = firstDerivative(B, interpolation_method); 00814 00815 for (unsigned i = 0; i < signal.size(); ++i) 00816 { 00817 diffused_signal[i] = diffused_signal[i] + step_size * C[i]; 00818 } 00819 } 00820 00821 return diffused_signal; 00822 } 00823 00824 00923 template <class T> 00924 const std::vector<T> nonlinearIsotropicDiffusion(const std::vector<T> & signal, 00925 T (* diffusivity)(T), 00926 T time, 00927 T step_size = 0.25, 00928 BorderInterpolation interpolation_method = CONTINUED) 00929 { 00930 /* The general formulation of a nonlinear diffusion is 00931 * 00932 * d/dt f(x, t) = div [ D(grad f(x, t)) * grad f(x, t) ] 00933 * 00934 * where D is the so-called diffusivity. In the 1-dimensional case, the 00935 * divergence and the gradient simplify to an ordinary differentiation. 00936 * Thus we get 00937 * 00938 * d/dt f(x, t) = d/dx [ D(d/dx f(x, t)) * d/dx f(x, t) ] 00939 * 00940 * The diffusion equation can be easily solved by using the following 00941 * approximation 00942 * 00943 * d/dt f(x, t) = [f(x, t+h) - f(x, t) ] / h 00944 * 00945 * where h is the step size. With this, we get (A, B, and C are used within 00946 * the implementation) 00947 * 00948 * d/dt f(x, t+h) = f(x, t) + h * { d/dx [ D(d/dx f(x, t)) * d/dx f(x, t) ] } 00949 * = f(x, t) + h * { d/dx [ D(A) * A ] } 00950 * = f(x, t) + h * { d/dx [ B ] } 00951 * = f(x, t) + h * { C } 00952 * 00953 * Iterating until t + n * h = time, yields the solution. 00954 */ 00955 00956 00957 // If time == 0 return the unchanged signal. 00958 00959 if (Tools::isZero(time)) 00960 { 00961 return signal; 00962 } 00963 00964 // Modify step_size such, that after n iterations, time is really reached. 00965 00966 step_size = time / std::ceil(time / step_size); 00967 00968 // Compute the diffusion. 00969 00970 const unsigned N = signal.size(); 00971 std::vector<T> B(N); 00972 00973 std::vector<T> diffused_signal = signal; 00974 00975 for (T t = step_size; t <= time; t += step_size) 00976 { 00977 const std::vector<T> & A = firstDerivative(diffused_signal, interpolation_method); 00978 00979 for (unsigned i = 0; i < N; ++i) 00980 { 00981 B[i] = diffusivity(A[i]) * A[i]; 00982 } 00983 00984 const std::vector<T> & C = firstDerivative(B, interpolation_method); 00985 00986 for (unsigned i = 0; i < signal.size(); ++i) 00987 { 00988 diffused_signal[i] = diffused_signal[i] + step_size * C[i]; 00989 } 00990 } 00991 00992 return diffused_signal; 00993 } 00994 00995 00996 } // namespace Diffusion 00997 00998 00999 } // namespace TRTK 01000 01001 01002 #endif // DIFFUSION_HPP_6431082743
Documentation generated by Doxygen