00001 #ifndef OPENTISSUE_DYNAMICS_EDM_EDM_SURFACE_H
00002 #define OPENTISSUE_DYNAMICS_EDM_EDM_SURFACE_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/math/math_functions.h>
00013
00014 #include <cmath>
00015 #include <cassert>
00016 #include <vector>
00017
00018
00019 namespace OpenTissue
00020 {
00021
00022 namespace edm
00023 {
00024
00025 template<typename edm_types>
00026 class Surface
00027 : public edm_types::model_type
00028 {
00029 public:
00030
00031 typedef typename edm_types::model_type base_type;
00032 typedef typename edm_types::value_traits value_traits;
00033 typedef typename edm_types::real_type real_type;
00034 typedef typename edm_types::vector3_type vector3_type;
00035 typedef typename edm_types::tensor2_type tensor2_type;
00036 typedef typename edm_types::Particle particle_type;
00037 typedef typename base_type::EDMMatrix EDMMatrix;
00038 typedef typename base_type::EDMVector EDMVector;
00039
00040 struct SurfaceParticle
00041 : public particle_type
00042 {
00043 SurfaceParticle()
00044 : particle_type()
00045 {}
00046 virtual ~SurfaceParticle(){}
00047
00048
00049 tensor2_type e;
00050 tensor2_type x;
00051 tensor2_type G0;
00052 tensor2_type B0;
00053 };
00054
00055 typedef std::vector<SurfaceParticle> SurfaceParticles;
00056
00057 protected:
00058
00059 size_t m_M, m_N;
00060 bool m_wrap_M, m_wrap_N;
00061
00062 private:
00063
00064 real_type m_h1, m_h2;
00065 SurfaceParticles m_P;
00066
00067 public:
00068
00069 Surface()
00070 : base_type(edm_types::EDM_Surface)
00071 , m_M(0)
00072 , m_N(0)
00073 , m_wrap_M(false)
00074 , m_wrap_N(false)
00075 , m_h1(value_traits::one())
00076 , m_h2(value_traits::one())
00077 {}
00078
00079 virtual ~Surface() {}
00080
00081 public:
00082
00083 bool initialize(size_t M, size_t N)
00084 {
00085 if ( !m_P.empty() || M < 3 || N < 3 )
00086 return false;
00087
00088
00089 m_P.resize( ( m_M = M ) * ( m_N = N ) );
00090 const real_type du = m_h1 = 1. / ( M - 1 ), dv = m_h2 = 1. / ( N - 1 );
00091 real_type v, u;
00092 v = u = value_traits::zero();
00093 for ( size_t n = 0; n < N; n++, v += dv, u = 0 )
00094 for ( size_t m = 0; m < M; m++, u += du )
00095 grid( m, n ).r = position( this->m_rest, u, v );
00096
00097
00098 for ( size_t n = 0; n < N; ++n )
00099 for ( size_t m = 0; m < M; ++m )
00100 {
00101 SurfaceParticle& a = grid( m, n );
00102 a.G0 = metric( m, n );
00103 a.n = normal( m, n );
00104 a.B0 = curvature( m, n );
00105 }
00106
00107 v = u = value_traits::zero();
00108 for ( size_t n = 0; n < N; n++, v += dv, u = 0 )
00109 for ( size_t m = 0; m < M; m++, u += du )
00110 {
00111 SurfaceParticle& a = grid( m, n );
00112 a.r = position( this->m_init, u, v );
00113 a.o = a.r;
00114 a.v *= 0;
00115 a.t.u = math::clamp_zero_one(u);
00116 a.t.v = math::clamp_zero_one(v);
00117 }
00118
00119
00120 compute_surface_normals();
00121
00122 return true;
00123 }
00124
00125 Surface & wrapping(bool M, bool N)
00126 {
00127 m_wrap_M = M;
00128 m_wrap_N = N;
00129 return *this;
00130 }
00131
00132 size_t get_num_M(bool include_wrapping = false) const
00133 {
00134 return size_t(m_M + (!include_wrapping ? 0 : m_wrap_M ? 1 : 0));
00135 }
00136
00137 size_t get_num_N(bool include_wrapping = false) const
00138 {
00139 return size_t(m_N + (!include_wrapping ? 0 : m_wrap_N ? 1 : 0));
00140 }
00141
00142 SurfaceParticle const & particle(size_t m, size_t n) const
00143 {
00144 return grid(m, n);
00145 }
00146
00147
00148 size_t nodes() const
00149 {
00150 return size_t(this->m_max_nodes);
00151 }
00152
00153 size_t index_adjust( long m, long n ) const
00154 {
00155
00156 using std::min;
00157 using std::max;
00158
00159 const size_t m_ = m_wrap_M ? m % ( ( m < 0 ? -1 : 1 ) * static_cast<long>( m_M ) ) + ( m < 0 ? m_M : 0 ) : static_cast<size_t>( max( 0L, min( m, static_cast<long>( m_M - 1 ) ) ) );
00160 const size_t n_ = m_wrap_N ? n % ( ( n < 0 ? -1 : 1 ) * static_cast<long>( m_N ) ) + ( n < 0 ? m_N : 0 ) : static_cast<size_t>( max( 0L, min( n, static_cast<long>( m_N - 1 ) ) ) );
00161 return size_t(n_*m_M + m_);
00162 }
00163
00164 Surface & set_natural_position(size_t idx, vector3_type const & r)
00165 {
00166 assert(idx < this->m_max_nodes || !"set_natural_position: idx out of range.");
00167 this->m_rest[idx] = r;
00168 return set_initial_position(idx, r);
00169 }
00170
00171 Surface & set_initial_position(size_t idx, vector3_type const & r)
00172 {
00173 assert(idx < this->m_max_nodes || !"set_natural_position: idx out of range.");
00174 this->m_init[idx] = r;
00175 return *this;
00176 }
00177
00178
00179 Surface & set_fixed(size_t m, size_t n, bool fixed)
00180 {
00181 assert(m < m_M && n < m_N);
00182 grid(m, n).f = fixed ;
00183 return *this;
00184 }
00185
00186 Surface & set_mass(size_t m, size_t n, real_type const & mass)
00187 {
00188 assert(m < m_M && n < m_N);
00189 grid(m, n).m = mass;
00190 return *this;
00191 }
00192
00193 Surface & set_damping(size_t m, size_t n, real_type const & damping)
00194 {
00195 assert(m < m_M && n < m_N);
00196 grid(m, n).g = damping;
00197 return *this;
00198 }
00199
00200 Surface & set_tension(size_t m, size_t n, tensor2_type const & tension)
00201 {
00202 assert(m < m_M && n < m_N);
00203 grid(m, n).e = tension;
00204 return *this;
00205 }
00206
00207 Surface & set_rigidity(size_t m, size_t n, tensor2_type const & rigidity)
00208 {
00209 assert(m < m_M && n < m_N);
00210 grid(m, n).x = rigidity;
00211 return *this;
00212 }
00213
00214 protected:
00215
00216 bool index_check(long m, long n) const
00217 {
00218 return ( m_wrap_M ? true : 0 <= m && m < static_cast<long>( m_M ) ) && ( m_wrap_N ? true : 0 <= n && n < static_cast<long>( m_N ) );
00219 }
00220
00221 SurfaceParticle const & grid_adjust(long m, long n) const
00222 {
00223 return m_P[index_adjust(m, n)];
00224 }
00225
00226 vector3_type const & r(long m, long n) const
00227 {
00228 return grid_adjust(m, n).r;
00229 }
00230
00231 private:
00232
00233 virtual vector3_type position(vector3_type const * a, real_type const & u, real_type const & v) const = 0;
00234 virtual vector3_type normal(size_t m, size_t n) const = 0;
00235
00236 private:
00237
00238 void compute_stiffness(EDMMatrix & K) const
00239 {
00240 using std::fabs;
00241 typedef std::vector<tensor2_type> Tensors;
00242
00243
00244 Tensors alpha( m_P.size() );
00245 Tensors beta( m_P.size() );
00246 for ( size_t n = 0; n < m_N; ++n )
00247 for ( size_t m = 0; m < m_M; ++m )
00248 {
00249 size_t const i = index_adjust( m, n );
00250 SurfaceParticle const & a = grid( m, n );
00251
00252 tensor2_type& alpha_ = alpha[ i ];
00253 tensor2_type m_ = metric( m, n );
00254 alpha_.t0[ 0 ] = this->m_strength * a.e.t0[ 0 ] * ( m_.t0[ 0 ] - a.G0.t0[ 0 ] );
00255 alpha_.t0[ 1 ] = this->m_strength * a.e.t0[ 1 ] * ( m_.t0[ 1 ] - a.G0.t0[ 1 ] );
00256 alpha_.t1[ 0 ] = this->m_strength * a.e.t1[ 0 ] * ( m_.t1[ 0 ] - a.G0.t1[ 0 ] );
00257 alpha_.t1[ 1 ] = this->m_strength * a.e.t1[ 1 ] * ( m_.t1[ 1 ] - a.G0.t1[ 1 ] );
00258
00259
00260 tensor2_type& beta_ = beta[ i ];
00261 tensor2_type c_ = curvature( m, n );
00262 beta_.t0[ 0 ] = fabs( this->m_strength * a.x.t0[ 0 ] * ( c_.t0[ 0 ] - a.B0.t0[ 0 ] ) );
00263 beta_.t0[ 1 ] = fabs( this->m_strength * a.x.t0[ 1 ] * ( c_.t0[ 1 ] - a.B0.t0[ 1 ] ) );
00264 beta_.t1[ 0 ] = fabs( this->m_strength * a.x.t1[ 0 ] * ( c_.t1[ 0 ] - a.B0.t1[ 0 ] ) );
00265 beta_.t1[ 1 ] = fabs( this->m_strength * a.x.t1[ 1 ] * ( c_.t1[ 1 ] - a.B0.t1[ 1 ] ) );
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 }
00284
00285 real_type const inv_h1h1 = 1. / ( m_h1 * m_h1 );
00286 real_type const inv_h1h2 = 1. / ( m_h1 * m_h2 );
00287 real_type const inv_h2h2 = 1. / ( m_h2 * m_h2 );
00288 real_type const inv_h1h1h1h1 = inv_h1h1 * inv_h1h1;
00289 real_type const inv_h1h1h2h2 = inv_h1h2 * inv_h1h2;
00290 real_type const inv_h2h2h2h2 = inv_h2h2 * inv_h2h2;
00291 size_t const MN = m_M * m_N;
00292
00293 for ( size_t n = 0; n < m_N; ++n )
00294 for ( size_t m = 0; m < m_M; ++m )
00295 {
00296
00297 tensor2_type const & am_n = alpha[index_adjust(m, n)];
00298 tensor2_type const & amM1_n = alpha[index_adjust(m-1, n)];
00299 tensor2_type const & am_nM1 = alpha[index_adjust(m, n-1)];
00300
00301 real_type Am_nM1 = 0;
00302 real_type AmP1_nM1 = 0;
00303 real_type AmM1_n = 0;
00304 real_type Am_n = 0;
00305 real_type AmP1_n = 0;
00306 real_type AmM1_nP1 = 0;
00307 real_type Am_nP1 = 0;
00308
00309
00310 if ( index_check( m + 1, n ) )
00311 {
00312 real_type const tmp = inv_h1h1 * am_n.t0[ 0 ];
00313 AmP1_n += - tmp;
00314 Am_n += + tmp;
00315 }
00316
00317
00318 if ( index_check( m - 1, n ) )
00319 {
00320 real_type const tmp = inv_h1h1 * amM1_n.t0[ 0 ];
00321 Am_n += + tmp;
00322 AmM1_n += - tmp;
00323 }
00324
00325
00326 if ( index_check( m, n + 1 ) )
00327 {
00328 real_type const tmp = inv_h1h2 * am_n.t0[ 1 ];
00329 Am_nP1 += - tmp;
00330 Am_n += + tmp;
00331 }
00332
00333
00334 if ( index_check( m - 1, n + 1 ) )
00335 {
00336 real_type const tmp = inv_h1h2 * amM1_n.t0[ 1 ];
00337 AmM1_nP1 += + tmp;
00338 AmM1_n += - tmp;
00339 }
00340
00341
00342 if ( index_check( m + 1, n ) )
00343 {
00344 real_type const tmp = inv_h1h2 * am_n.t1[ 0 ];
00345 AmP1_n += - tmp;
00346 Am_n += + tmp;
00347 }
00348
00349
00350 if ( index_check( m + 1, n - 1 ) )
00351 {
00352 real_type const tmp = inv_h1h2 * am_nM1.t1[ 0 ];
00353 AmP1_nM1 += + tmp;
00354 Am_nM1 += - tmp;
00355 }
00356
00357
00358 if ( index_check( m, n + 1 ) )
00359 {
00360 real_type const tmp = inv_h2h2 * am_n.t1[ 1 ];
00361 Am_nP1 += - tmp;
00362 Am_n += + tmp;
00363 }
00364
00365
00366 if ( index_check( m, n - 1 ) )
00367 {
00368 real_type const tmp = inv_h2h2 * am_nM1.t1[ 1 ];
00369 Am_n += + tmp;
00370 Am_nM1 += - tmp;
00371 }
00372
00373
00374 tensor2_type const & bm_n = beta[index_adjust(m, n)];
00375 tensor2_type const & bmM1_n = beta[index_adjust(m-1, n)];
00376 tensor2_type const & bmP1_n = beta[index_adjust(m+1, n)];
00377 tensor2_type const & bm_nM1 = beta[index_adjust(m, n-1)];
00378 tensor2_type const & bm_nP1 = beta[index_adjust(m, n+1)];
00379 tensor2_type const & bmM1_nM1 = beta[index_adjust(m-1, n-1)];
00380
00381 real_type Bm_nM2 = 0;
00382 real_type BmM1_nM1 = 0;
00383 real_type Bm_nM1 = 0;
00384 real_type BmP1_nM1 = 0;
00385 real_type BmM2_n = 0;
00386 real_type BmM1_n = 0;
00387 real_type Bm_n = 0;
00388 real_type BmP1_n = 0;
00389 real_type BmP2_n = 0;
00390 real_type BmM1_nP1 = 0;
00391 real_type Bm_nP1 = 0;
00392 real_type BmP1_nP1 = 0;
00393 real_type Bm_nP2 = 0;
00394
00395
00396 if ( index_check( m + 2, n ) )
00397 {
00398 real_type const tmp = inv_h1h1h1h1 * bmP1_n.t0[ 0 ];
00399 BmP2_n += + tmp;
00400 BmP1_n += - 2. * tmp;
00401 Bm_n += + tmp;
00402 }
00403
00404
00405 if ( index_check( m + 1, n ) && index_check( m - 1, n ) )
00406 {
00407 real_type const tmp = inv_h1h1h1h1 * 2. * bm_n.t0[ 0 ];
00408 BmP1_n += - tmp;
00409 Bm_n += + 2. * tmp;
00410 BmM1_n += - tmp;
00411 }
00412
00413
00414 if ( index_check( m - 2, n ) )
00415 {
00416 real_type const tmp = inv_h1h1h1h1 * bmM1_n.t0[ 0 ];
00417 Bm_n += + tmp;
00418 BmM1_n += - 2. * tmp;
00419 BmM2_n += + tmp;
00420 }
00421
00422
00423 if ( index_check( m + 1, n + 1 ) )
00424 {
00425 real_type const tmp = inv_h1h1h2h2 * bm_n.t0[ 1 ];
00426 BmP1_nP1 += + tmp;
00427 BmP1_n += - tmp;
00428 Bm_nP1 += - tmp;
00429 Bm_n += + tmp;
00430 }
00431
00432
00433 if ( index_check( m + 1, n - 1 ) )
00434 {
00435 real_type const tmp = inv_h1h1h2h2 * bm_nM1.t0[ 1 ];
00436 BmP1_n += - tmp;
00437 BmP1_nM1 += + tmp;
00438 Bm_n += + tmp;
00439 Bm_nM1 += - tmp;
00440 }
00441
00442
00443 if ( index_check( m - 1, n + 1 ) )
00444 {
00445 real_type const tmp = inv_h1h1h2h2 * bmM1_n.t0[ 1 ];
00446 Bm_nP1 += - tmp;
00447 Bm_n += + tmp;
00448 BmM1_nP1 += + tmp;
00449 BmM1_n += - tmp;
00450 }
00451
00452
00453 if ( index_check( m - 1, n - 1 ) )
00454 {
00455 real_type const tmp = inv_h1h1h2h2 * bmM1_nM1.t0[ 1 ];
00456 Bm_n += + tmp;
00457 Bm_nM1 += - tmp;
00458 BmM1_n += - tmp;
00459 BmM1_nM1 += + tmp;
00460 }
00461
00462
00463 if ( index_check( m + 1, n + 1 ) )
00464 {
00465 real_type const tmp = inv_h1h1h2h2 * bm_n.t1[ 0 ];
00466 BmP1_nP1 += + tmp;
00467 BmP1_n += - tmp;
00468 Bm_nP1 += - tmp;
00469 Bm_n += + tmp;
00470 }
00471
00472
00473 if ( index_check( m + 1, n - 1 ) )
00474 {
00475 real_type const tmp = inv_h1h1h2h2 * bm_nM1.t1[ 0 ];
00476 BmP1_n += - tmp;
00477 BmP1_nM1 += + tmp;
00478 Bm_n += + tmp;
00479 Bm_nM1 += - tmp;
00480 }
00481
00482
00483 if ( index_check( m - 1, n + 1 ) )
00484 {
00485 real_type const tmp = inv_h1h1h2h2 * bmM1_n.t1[ 0 ];
00486 Bm_nP1 += - tmp;
00487 Bm_n += + tmp;
00488 BmM1_nP1 += + tmp;
00489 BmM1_n += - tmp;
00490 }
00491
00492
00493 if ( index_check( m - 1, n - 1 ) )
00494 {
00495 real_type const tmp = inv_h1h1h2h2 * bmM1_nM1.t1[ 0 ];
00496 Bm_n += + tmp;
00497 Bm_nM1 += - tmp;
00498 BmM1_n += - tmp;
00499 BmM1_nM1 += + tmp;
00500 }
00501
00502
00503 if ( index_check( m, n + 2 ) )
00504 {
00505 real_type const tmp = inv_h2h2h2h2 * bm_nP1.t1[ 1 ];
00506 Bm_nP2 += + tmp;
00507 Bm_nP1 += - 2. * tmp;
00508 Bm_n += + tmp;
00509 }
00510
00511
00512 if ( index_check( m, n + 1 ) && index_check( m, n - 1 ) )
00513 {
00514 real_type const tmp = inv_h2h2h2h2 * 2. * bm_n.t1[ 1 ];
00515 Bm_nP1 += - tmp;
00516 Bm_n += + 2. * tmp;
00517 Bm_nM1 += - tmp;
00518 }
00519
00520
00521 if ( index_check( m, n - 2 ) )
00522 {
00523 real_type const tmp = inv_h2h2h2h2 * bm_nM1.t1[ 1 ];
00524 Bm_n += + tmp;
00525 Bm_nM1 += - 2. * tmp;
00526 Bm_nM2 += + tmp;
00527 }
00528
00529
00530 real_type const Sm_nM2 = 0 + Bm_nM2;
00531 real_type const SmM1_nM1 = 0 + BmM1_nM1;
00532 real_type const Sm_nM1 = Am_nM1 + Bm_nM1;
00533 real_type const SmP1_nM1 = AmP1_nM1 + BmP1_nM1;
00534 real_type const SmM2_n = 0 + BmM2_n;
00535 real_type const SmM1_n = AmM1_n + BmM1_n;
00536 real_type const Sm_n = Am_n + Bm_n;
00537 real_type const SmP1_n = AmP1_n + BmP1_n;
00538 real_type const SmP2_n = 0 + BmP2_n;
00539 real_type const SmM1_nP1 = AmM1_nP1 + BmM1_nP1;
00540 real_type const Sm_nP1 = Am_nP1 + Bm_nP1;
00541 real_type const SmP1_nP1 = 0 + BmP1_nP1;
00542 real_type const Sm_nP2 = 0 + Bm_nP2;
00543
00544 EDMVector row( MN );
00545 row.clear();
00546
00547 row[ index_adjust( m , n - 2 ) ] += zeroize( Sm_nM2 );
00548 row[ index_adjust( m - 1, n - 1 ) ] += zeroize( SmM1_nM1 );
00549 row[ index_adjust( m , n - 1 ) ] += zeroize( Sm_nM1 );
00550 row[ index_adjust( m + 1, n - 1 ) ] += zeroize( SmP1_nM1 );
00551 row[ index_adjust( m - 2, n ) ] += zeroize( SmM2_n );
00552 row[ index_adjust( m - 1, n ) ] += zeroize( SmM1_n );
00553 row[ index_adjust( m , n ) ] += zeroize( Sm_n );
00554 row[ index_adjust( m + 1, n ) ] += zeroize( SmP1_n );
00555 row[ index_adjust( m + 2, n ) ] += zeroize( SmP2_n );
00556 row[ index_adjust( m - 1, n + 1 ) ] += zeroize( SmM1_nP1 );
00557 row[ index_adjust( m , n + 1 ) ] += zeroize( Sm_nP1 );
00558 row[ index_adjust( m + 1, n + 1 ) ] += zeroize( SmP1_nP1 );
00559 row[ index_adjust( m , n + 2 ) ] += zeroize( Sm_nP2 );
00560
00561 ublas::row(K, index_adjust(m, n)) = row;
00562 }
00563 }
00564
00565 SurfaceParticle & grid(size_t m, size_t n)
00566 {
00567 return m_P[ n * m_M + m ];
00568 }
00569
00570 SurfaceParticle const & grid(size_t m, size_t n) const
00571 {
00572 return m_P[n * m_M + m];
00573 }
00574
00575 tensor2_type metric(size_t m, size_t n) const
00576 {
00577 const vector3_type v1 = D1Pb(m, n);
00578 const vector3_type v2 = D2Pb(m, n);
00579
00580 tensor2_type G;
00581 G.t0[ 0 ] = v1 * v1;
00582 G.t0[ 1 ] = G.t1[ 0 ] = v1 * v2;
00583 G.t1[ 1 ] = v2 * v2;
00584 return tensor2_type(G);
00585 }
00586
00587 tensor2_type curvature(size_t m, size_t n) const
00588 {
00589 const vector3_type v11 = D11b(m, n);
00590 const vector3_type v22 = D22b(m, n);
00591 const vector3_type v12 = D12Pb(m, n);
00592
00593
00594 const vector3_type &n_ = particle( m, n ).n;
00595 tensor2_type B;
00596 B.t0[ 0 ] = n_ * v11;
00597 B.t0[ 1 ] = B.t1[ 0 ] = n_ * v12;
00598 B.t1[ 1 ] = n_ * v22;
00599 return tensor2_type(B);
00600 }
00601
00602 void compute_surface_normals()
00603 {
00604 for (size_t n = 0; n < m_N; ++n)
00605 for (size_t m = 0; m < m_M; ++m)
00606 grid(m, n).n = normal(m, n);
00607 }
00608
00609 size_t particle_count() const
00610 {
00611 return size_t(static_cast<size_t>(m_P.size()));
00612 }
00613
00614 particle_type const & get_particle(size_t idx) const
00615 {
00616 return m_P[idx];
00617 }
00618
00619 particle_type & get_particle(size_t idx)
00620 {
00621 return m_P[idx];
00622 }
00623
00624 vector3_type D1(size_t m, size_t n) const
00625 {
00626 return vector3_type((r(m+1,n)-r(m-1,n))/(2.*m_h1));
00627 }
00628 vector3_type D2(size_t m, size_t n) const
00629 {
00630 return vector3_type((r(m,n+1)-r(m,n-1))/(2.*m_h2));
00631 }
00632 vector3_type D1Pb(size_t m, size_t n) const
00633 {
00634 return vector3_type(index_check(m+1,n)?(r(m+1,n)-r(m,n))/m_h1:vector3_type(0));
00635 }
00636 vector3_type D2Pb(size_t m, size_t n) const
00637 {
00638 return vector3_type(index_check(m,n+1)?(r(m,n+1)-r(m,n))/m_h2:vector3_type(0));
00639 }
00640 vector3_type D11b(size_t m, size_t n) const
00641 {
00642 return vector3_type(index_check(m+1,n)&&index_check(m-1,n)?(r(m+1,n)-2.*r(m,n)+r(m-1,n))/(m_h1*m_h1):vector3_type(0));
00643 }
00644 vector3_type D22b(size_t m, size_t n) const
00645 {
00646 return vector3_type(index_check(m,n+1)&&index_check(m,n-1)?(r(m,n+1)-2.*r(m,n)+r(m,n-1))/(m_h2*m_h2):vector3_type(0));
00647 }
00648 vector3_type D12Pb(size_t m, size_t n) const
00649 {
00650 return vector3_type(index_check(m+1,n+1)?(r(m+1,n+1)-r(m,n+1)-r(m+1,n)+r(m,n))/(m_h1*m_h2):vector3_type(0));
00651 }
00652 vector3_type D21Pb(size_t m, size_t n) const
00653 {
00654 return vector3_type(D12Pb(m,n));
00655 }
00656
00657 vector3_type D1P(size_t m, size_t n) const
00658 {
00659 return vector3_type((r(m+1,n)-r(m,n))/m_h1);
00660 }
00661
00662 vector3_type D2P(size_t m, size_t n) const
00663 {
00664 return vector3_type((r(m,n+1)-r(m,n))/m_h2);
00665 }
00666
00667 vector3_type D1M(size_t m, size_t n) const
00668 {
00669 return vector3_type((r(m,n)-r(m-1,n))/m_h1);
00670 }
00671
00672 vector3_type D2M(size_t m, size_t n) const
00673 {
00674 return vector3_type((r(m,n)-r(m,n-1))/m_h2);
00675 }
00676
00677 vector3_type D11(size_t m, size_t n) const
00678 {
00679 return vector3_type((r(m+1,n)-2.*r(m,n)+r(m-1,n))/(m_h1*m_h1));
00680 }
00681
00682 vector3_type D22(size_t m, size_t n) const
00683 {
00684 return vector3_type((r(m,n+1)-2.*r(m,n)+r(m,n-1))/(m_h2*m_h2));
00685 }
00686
00687 vector3_type D12P(size_t m, size_t n) const
00688 {
00689 return vector3_type((r(m+1,n+1)-r(m,n+1)-r(m+1,n)+r(m,n))/(m_h1*m_h2));
00690 }
00691
00692 };
00693
00694 }
00695
00696 }
00697
00698
00699 #endif