00001 #ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_REDISTANCE_H
00002 #define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_REDISTANCE_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <cmath>
00013
00014 #include <OpenTissue/core/math/math_is_finite.h>
00015 #include <OpenTissue/core/math/math_vector3.h>
00016 #include <OpenTissue/core/containers/grid/util/grid_compute_sign_function.h>
00017
00018 namespace OpenTissue
00019 {
00020 namespace grid
00021 {
00022
00023 namespace detail
00024 {
00025 class FullRedistance
00026 {
00027 protected:
00028
00029 template < typename grid_type >
00030 typename grid_type::value_type compute_speed(
00031 grid_type const & phi
00032 , grid_type const & S0
00033 , grid_type & speed
00034 )
00035 {
00036 using std::min;
00037 using std::max;
00038 using std::sqrt;
00039 using std::fabs;
00040
00041 typedef typename grid_type::const_index_iterator const_index_iterator;
00042 typedef typename grid_type::const_iterator const_iterator;
00043 typedef typename grid_type::iterator iterator;
00044 typedef typename grid_type::math_types math_types;
00045 typedef typename math_types::value_type real_type;
00046
00047 assert(phi.I()==S0.I() || !"compute_speed(): incompatible grid dimensions");
00048 assert(phi.J()==S0.J() || !"compute_speed(): incompatible grid dimensions");
00049 assert(phi.K()==S0.K() || !"compute_speed(): incompatible grid dimensions");
00050 assert(phi.min_coord()==S0.min_coord() || !"compute_speed(): incompatible grid side lengths");
00051 assert(phi.max_coord()==S0.max_coord() || !"compute_speed(): incompatible grid side lengths");
00052
00053 speed.create(phi.min_coord(),phi.max_coord(),phi.I(),phi.J(),phi.K());
00054
00055 real_type inv_dx = static_cast<real_type> ( 1.0 / phi.dx());
00056 real_type inv_dy = static_cast<real_type> ( 1.0 / phi.dy());
00057 real_type inv_dz = static_cast<real_type> ( 1.0 / phi.dz());
00058
00059 real_type inv_dx2 = inv_dx*inv_dx;
00060 real_type inv_dy2 = inv_dx*inv_dy;
00061 real_type inv_dz2 = inv_dx*inv_dz;
00062
00063 real_type cfl_condition = real_type(0.0);
00064 real_type zero = static_cast<real_type>(0.0);
00065
00066 iterator f = speed.begin();
00067 const_index_iterator p = phi.begin();
00068 const_index_iterator end = phi.end();
00069 const_iterator s0 = S0.begin();
00070
00071 size_t I = phi.I();
00072 size_t J = phi.J();
00073 size_t K = phi.K();
00074
00075 for ( ; p != end; ++p, ++f,++s0)
00076 {
00077 size_t i = p.i();
00078 size_t j = p.j();
00079 size_t k = p.k();
00080 size_t im1 = ( i ) ? i - 1 : 0;
00081 size_t jm1 = ( j ) ? j - 1 : 0;
00082 size_t km1 = ( k ) ? k - 1 : 0;
00083 size_t ip1 = min( i + 1, I - 1 );
00084 size_t jp1 = min( j + 1, J - 1 );
00085 size_t kp1 = min( k + 1, K - 1 );
00086 size_t idx_000 = ( k * J + j ) * I + i;
00087 size_t idx_m00 = ( k * J + j ) * I + im1;
00088 size_t idx_p00 = ( k * J + j ) * I + ip1;
00089 size_t idx_0m0 = ( k * J + jm1 ) * I + i;
00090 size_t idx_0p0 = ( k * J + jp1 ) * I + i;
00091 size_t idx_00m = ( km1 * J + j ) * I + i;
00092 size_t idx_00p = ( kp1 * J + j ) * I + i;
00093 real_type d000 = phi( idx_000 );
00094 real_type dp00 = phi( idx_p00 );
00095 real_type dm00 = phi( idx_m00 );
00096 real_type d0p0 = phi( idx_0p0 );
00097 real_type d0m0 = phi( idx_0m0 );
00098 real_type d00p = phi( idx_00p );
00099 real_type d00m = phi( idx_00m );
00100 assert( is_finite( d000 ) || !"compute_speed(): NaN encountered");
00101 assert( is_finite( dp00 ) || !"compute_speed(): NaN encountered");
00102 assert( is_finite( dm00 ) || !"compute_speed(): NaN encountered");
00103 assert( is_finite( d0p0 ) || !"compute_speed(): NaN encountered");
00104 assert( is_finite( d0m0 ) || !"compute_speed(): NaN encountered");
00105 assert( is_finite( d00p ) || !"compute_speed(): NaN encountered");
00106 assert( is_finite( d00m ) || !"compute_speed(): NaN encountered");
00107 real_type dxp = (dp00 - d000)*inv_dx;
00108 real_type dxm = (d000 - dm00)*inv_dx;
00109 real_type dyp = (d0p0 - d000)*inv_dy;
00110 real_type dym = (d000 - d0m0)*inv_dy;
00111 real_type dzp = (d00p - d000)*inv_dz;
00112 real_type dzm = (d000 - d00m)*inv_dz;
00113 assert( is_finite( dxp ) || !"compute_speed(): NaN encountered");
00114 assert( is_finite( dxm ) || !"compute_speed(): NaN encountered");
00115 assert( is_finite( dyp ) || !"compute_speed(): NaN encountered");
00116 assert( is_finite( dym ) || !"compute_speed(): NaN encountered");
00117 assert( is_finite( dzp ) || !"compute_speed(): NaN encountered");
00118 assert( is_finite( dzm ) || !"compute_speed(): NaN encountered");
00119 real_type dxp_max = max( dxp, zero );
00120 real_type dxm_max = max( dxm, zero );
00121 real_type dyp_max = max( dyp, zero );
00122 real_type dym_max = max( dym, zero );
00123 real_type dzp_max = max( dzp, zero );
00124 real_type dzm_max = max( dzm, zero );
00125 real_type dxp_min = min( dxp, zero );
00126 real_type dxm_min = min( dxm, zero );
00127 real_type dyp_min = min( dyp, zero );
00128 real_type dym_min = min( dym, zero );
00129 real_type dzp_min = min( dzp, zero );
00130 real_type dzm_min = min( dzm, zero );
00131 real_type dxp_max_2 = dxp_max * dxp_max;
00132 real_type dxm_max_2 = dxm_max * dxm_max;
00133 real_type dyp_max_2 = dyp_max * dyp_max;
00134 real_type dym_max_2 = dym_max * dym_max;
00135 real_type dzp_max_2 = dzp_max * dzp_max;
00136 real_type dzm_max_2 = dzm_max * dzm_max;
00137 real_type dxp_min_2 = dxp_min * dxp_min;
00138 real_type dxm_min_2 = dxm_min * dxm_min;
00139 real_type dyp_min_2 = dyp_min * dyp_min;
00140 real_type dym_min_2 = dym_min * dym_min;
00141 real_type dzp_min_2 = dzp_min * dzp_min;
00142 real_type dzm_min_2 = dzm_min * dzm_min;
00143
00144 real_type phi_x_2_p = max( dxm_max_2, dxp_min_2 );
00145 real_type phi_x_2_m = max( dxm_min_2, dxp_max_2 );
00146 real_type phi_y_2_p = max( dym_max_2, dyp_min_2 );
00147 real_type phi_y_2_m = max( dym_min_2, dyp_max_2 );
00148 real_type phi_z_2_p = max( dzm_max_2, dzp_min_2 );
00149 real_type phi_z_2_m = max( dzm_min_2, dzp_max_2 );
00150
00151 real_type norm_grad_phi_p = sqrt( phi_x_2_p + phi_y_2_p + phi_z_2_p );
00152 real_type norm_grad_phi_m = sqrt( phi_x_2_m + phi_y_2_m + phi_z_2_m );
00153
00154 if ( (*s0) > 0 )
00155 {
00156 (*f) = (*s0) * ( norm_grad_phi_p - 1.0 );
00157 }
00158 else if ( (*s0) < 0 )
00159 {
00160 (*f) = (*s0) * ( norm_grad_phi_m - 1.0 );
00161 }
00162 else
00163 {
00164 (*f) = 0;
00165 }
00166 real_type phi_x = fabs((dp00 - dm00)*inv_dx*.5);
00167 real_type phi_y = fabs((d0p0 - d0m0)*inv_dy*.5);
00168 real_type phi_z = fabs((d00p - d00m)*inv_dz*.5);
00169 real_type norm_grad_phi = sqrt(phi_x*phi_x + phi_y*phi_y + phi_z*phi_z);
00170
00171 real_type tmp = fabs( (*s0)*phi_x*inv_dx2/norm_grad_phi + (*s0)*phi_y*inv_dy2/norm_grad_phi + (*s0)*phi_z*inv_dz2/norm_grad_phi );
00172 cfl_condition = max( cfl_condition, tmp );
00173 }
00174 return 1.0/cfl_condition;
00175 }
00176
00177 template < typename grid_type , typename real_type >
00178 real_type update(
00179 grid_type const & phi
00180 , grid_type const & speed
00181 , real_type const & time_step
00182 , grid_type & psi
00183 , real_type const & gamma = 10e30
00184 )
00185 {
00186 typedef typename grid_type::const_index_iterator const_iterator;
00187 typedef typename grid_type::iterator iterator;
00188
00189 assert(phi.I()==psi.I() || !"update(): incompatible grid dimensions");
00190 assert(phi.J()==psi.J() || !"update(): incompatible grid dimensions");
00191 assert(phi.K()==psi.K() || !"update(): incompatible grid dimensions");
00192 assert(phi.min_coord()==psi.min_coord() || !"update(): incompatible grid side lengths");
00193 assert(phi.max_coord()==psi.max_coord() || !"update(): incompatible grid side lengths");
00194 assert(time_step>0 || !"update(): time-step must be positive");
00195
00196 real_type steady = real_type(0.0);
00197 const_iterator i = phi.begin();
00198 const_iterator f = speed.begin();
00199 iterator o = psi.begin();
00200 const_iterator end = phi.end();
00201 for ( ; i!=end;++i, ++o, ++f)
00202 {
00203 real_type diff = time_step * (*f);
00204 (*o) = (*i) - diff;
00205 diff = std::fabs(diff);
00206 if ( (*o) < gamma && steady < diff )
00207 steady = diff;
00208 }
00209 return steady;
00210 }
00211
00212 public:
00213
00232 template < typename grid_type >
00233 void operator()(
00234 grid_type const & phi
00235 , grid_type & psi
00236 , size_t max_iterations = 10
00237 , double steady_threshold = 0.05
00238 )
00239 {
00240 using std::min;
00241 using std::max;
00242
00243 typedef typename grid_type::value_type real_type;
00244
00245 assert(phi.I()==psi.I() || !"operator(): incompatible grid dimensions");
00246 assert(phi.J()==psi.J() || !"operator(): incompatible grid dimensions");
00247 assert(phi.K()==psi.K() || !"operator(): incompatible grid dimensions");
00248 assert(phi.min_coord()==psi.min_coord() || !"operator(): incompatible grid side lengths");
00249 assert(phi.max_coord()==psi.max_coord() || !"operator(): incompatible grid side lengths");
00250
00251 static grid_type S0;
00252 static grid_type speed;
00253
00254 compute_sign_function(phi,S0);
00255
00256 real_type alpha = static_cast<real_type> ( 0.9 );
00257
00258 real_type max_delta = static_cast<real_type> ( (max( phi.dx(), max( phi.dy(), phi.dz() ) ) ) );
00259
00260 grid_type * phi_in = const_cast<grid_type*>(&phi);
00261 grid_type * phi_out = ψ
00262
00263 real_type gamma = static_cast<real_type>( max_delta * max_iterations );
00264 real_type steady = static_cast<real_type>(0.0);
00265
00266 for(size_t iterations=0;iterations<max_iterations;++iterations)
00267 {
00268 for ( size_t flipflop = 2; flipflop; --flipflop )
00269 {
00270 std::swap( phi_in, phi_out );
00271 real_type cfl_condition = compute_speed( (*phi_in) ,S0,speed);
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 real_type time_step = alpha*cfl_condition;
00321 std::cout << "\ttime step = " << time_step << std::endl;
00322
00323 steady = update( (*phi_in), speed, time_step, (*phi_out), gamma);
00324 }
00325 std::cout << "\tredistance(): iteration = " << iterations << " steady = " << steady <<std::endl;
00326 if(steady < steady_threshold)
00327 break;
00328 }
00329 }
00330 };
00331
00332 }
00333
00352 template < typename grid_type >
00353 inline void redistance(
00354 grid_type const & phi
00355 , grid_type & psi
00356 , size_t max_iterations = 10
00357 , double steady_threshold = 0.05
00358 )
00359 {
00360 static detail::FullRedistance redistance_class;
00361 redistance_class(phi,psi,max_iterations,steady_threshold);
00362 }
00363
00364 }
00365 }
00366
00367
00368 #endif