Skip to content
Snippets Groups Projects
tnlGrid.h 82 KiB
Newer Older
  • Learn to ignore specific revisions
  • /***************************************************************************
                              tnlGrid.h  -  description
                                 -------------------
        begin                : Dec 12, 2010
        copyright            : (C) 2010 by Tomas Oberhuber
        email                : tomas.oberhuber@fjfi.cvut.cz
     ***************************************************************************/
    
    /***************************************************************************
     *                                                                         *
     *   This program is free software; you can redistribute it and/or modify  *
     *   it under the terms of the GNU General Public License as published by  *
     *   the Free Software Foundation; either version 2 of the License, or     *
     *   (at your option) any later version.                                   *
     *                                                                         *
     ***************************************************************************/
    
    #ifndef TNLGRID_H_
    #define TNLGRID_H_
    
    #include <iomanip>
    #include <fstream>
    #include <core/tnlAssert.h>
    #include <core/tnlArray.h>
    
    #include <core/tnlVector.h>
    
    
    using namespace std;
    
    template< int Dimensions, typename Real = double, tnlDevice Device = tnlHost, typename Index = int >
    class tnlGrid : public tnlArray< Dimensions, Real, Device, Index >
    {
       //! We do not allow constructor without parameters.
       tnlGrid();
    
       //! We do not allow copy constructor without object name.
       tnlGrid( const tnlGrid< Dimensions, Real, Device, Index >& a );
    
       public:
    
       tnlGrid( const tnlString& name );
    
       tnlGrid( const tnlString& name,
                const tnlGrid< Dimensions, Real, tnlHost, Index >& grid );
    
       tnlGrid( const tnlString& name,
                const tnlGrid< Dimensions, Real, tnlCuda, Index >& grid );
    
    
       const tnlTuple< Dimensions, Index >& getDimensions() const;
    
    
       //! Sets the dimensions
       /***
        * This method also must recompute space steps. It is save to call setDimensions and
        * setDomain in any order. Both recompute the space steps.
        */
    
       bool setDimensions( const tnlTuple< Dimensions, Index >& dimensions );
    
    
       //! Sets the computation domain in form of "rectangle".
       /***
        * This method also must recompute space steps. It is save to call setDimensions and
        * setDomain in any order. Both recompute the space steps.
        */
    
    
       bool setDomain( const tnlTuple< Dimensions, Real >& lowerCorner,
                       const tnlTuple< Dimensions, Real >& upperCorner );
    
    
       //! Set dimensions and domain of the grid using another grid as a template
       bool setLike( const tnlGrid< Dimensions, Real, tnlHost, Index >& v );
    
       //! Set dimensions and domain of the grid using another grid as a template
       bool setLike( const tnlGrid< Dimensions, Real, tnlCuda, Index >& v );
    
    
       const tnlTuple< Dimensions, Real >& getDomainLowerCorner() const;
    
       const tnlTuple< Dimensions, Real >& getDomainUpperCorner() const;
    
       const tnlTuple< Dimensions, Real >& getSpaceSteps() const;
    
    
       tnlString getType() const;
    
       bool operator == ( const tnlGrid< Dimensions, Real, Device, Index >& array ) const;
    
       bool operator != ( const tnlGrid< Dimensions, Real, Device, Index >& array ) const;
    
       template< typename Real2, tnlDevice Device2, typename Index2 >
       tnlGrid< Dimensions, Real, Device, Index >& operator = ( const tnlGrid< Dimensions, Real2, Device2, Index2 >& array );
    
       //! This method interpolates value at given point.
    
       Real getValue( const tnlTuple< Dimensions, Real >& point ) const;
    
    
       //! Interpolation for 1D grid.
       Real getValue( const Real& x ) const;
    
       //! Interpolation for 2D grid.
       Real getValue( const Real& x,
                      const Real& y ) const;
    
       //! Interpolation for 3D grid.
       Real getValue( const Real& x,
                      const Real& y,
                      const Real& z ) const;
    
       //! Forward difference w.r.t x
       Real Partial_x_f( const Index i1 ) const;
    
       //! Forward difference w.r.t x in two dimensions
       Real Partial_x_f( const Index i1,
                         const Index i2 ) const;
    
       //! Forward difference w.r.t x in three dimensions
       Real Partial_x_f( const Index i1,
                         const Index i2,
                         const Index i3 ) const;
    
       //! Backward difference w.r.t x
       Real Partial_x_b( const Index i1 ) const;
    
       //! Backward difference w.r.t x in two dimensions
       Real Partial_x_b( const Index i1,
                         const Index i2 ) const;
    
       //! Backward difference w.r.t x in three dimensions
       Real Partial_x_b( const Index i1,
                         const Index i2,
                         const Index i3 ) const;
    
       //! Central difference w.r.t. x
       Real Partial_x( const Index i1 ) const;
    
       //! Central difference w.r.t. x in two dimensions
       Real Partial_x( const Index i1,
                       const Index i2 ) const;
    
       //! Central difference w.r.t. x
       Real Partial_x( const Index i1,
                       const Index i2,
                       const Index i3 ) const;
    
       //! Second order difference w.r.t. x
       Real Partial_xx( const Index i1 ) const;
    
       //! Second order difference w.r.t. x in two dimensions
       Real Partial_xx( const Index i1,
                        const Index i2 ) const;
    
       //! Second order difference w.r.t. x
       Real Partial_xx( const Index i1,
                        const Index i2,
                        const Index i3 ) const;
    
       //! Forward difference w.r.t y
       Real Partial_y_f( const Index i1,
                         const Index i2 ) const;
    
       //! Forward difference w.r.t y in three dimensions
       Real Partial_y_f( const Index i1,
                         const Index i2,
                         const Index i3 ) const;
    
       //! Backward difference w.r.t y
       Real Partial_y_b( const Index i1,
                         const Index i2 ) const;
    
       //! Backward difference w.r.t y in three dimensions
       Real Partial_y_b( const Index i1,
                         const Index i2,
                         const Index i3 ) const;
    
       //! Central difference w.r.t y
       Real Partial_y( const Index i1,
                       const Index i2 ) const;
    
       //! Central difference w.r.t y
       Real Partial_y( const Index i1,
                       const Index i2,
                       const Index i3 ) const;
    
       //! Second order difference w.r.t. y
       Real Partial_yy( const Index i1,
                        const Index i2 ) const;
    
       //! Second order difference w.r.t. y in three dimensions
       Real Partial_yy( const Index i1,
                        const Index i2,
                        const Index i3 ) const;
    
       //! Forward difference w.r.t z
       Real Partial_z_f( const Index i1,
                         const Index i2,
                         const Index i3 ) const;
    
       //! Backward difference w.r.t z
       Real Partial_z_b( const Index i1,
                         const Index i2,
                         const Index i3 ) const;
    
       //! Central difference w.r.t z
       Real Partial_z( const Index i1,
                       const Index i2,
                       const Index i3 ) const;
    
       //! Second order difference w.r.t. z
       Real Partial_zz( const Index i1,
                        const Index i2,
                        const Index i3 ) const;
    
       //! Set space dependent Dirichlet boundary conditions
       void setDirichletBC( const tnlGrid< Dimensions, Real, Device, Index >&bc,
    
                            const tnlTuple< Dimensions, bool >& lowerBC,
                            const tnlTuple< Dimensions, bool >& upperBC );
    
    
       //! Set constant Dirichlet boundary conditions
       void setDirichletBC( const Real& bc,
    
                            const tnlTuple< Dimensions, bool >& lowerBC,
                            const tnlTuple< Dimensions, bool >& upperBC );
    
    
       //! Set space dependent Neumann boundary conditions
       void setNeumannBC( const tnlGrid< Dimensions, Real, Device, Index >&bc,
    
                          const tnlTuple< Dimensions, bool >& lowerBC,
                          const tnlTuple< Dimensions, bool >& upperBC );
    
    
       //! Set constant Neumann boundary conditions
       void setNeumannBC( const Real& bc,
    
                          const tnlTuple< Dimensions, bool >& lowerBC,
                          const tnlTuple< Dimensions, bool >& upperBC );
    
    
       Real getMax() const;
    
       Real getMin() const;
    
       Real getAbsMax() const;
    
       Real getAbsMin() const;
    
       Real getLpNorm() const;
    
       Real getSum() const;
    
    
       Real getDifferenceMax( const tnlVector< Real, tnlHost, Index >& v ) const;
    
       Real getDifferenceMin( const tnlVector< Real, tnlHost, Index >& v ) const;
    
       Real getDifferenceAbsMax( const tnlVector< Real, tnlHost, Index >& v ) const;
    
       Real getDifferenceAbsMin( const tnlVector< Real, tnlHost, Index >& v ) const;
    
       Real getDifferenceLpNorm( const tnlVector< Real, tnlHost, Index >& v, const Real& p ) const;
    
       Real getDifferenceSum( const tnlVector< Real, tnlHost, Index >& v ) const;
    
    
       //! Method for saving the object to a file as a binary data
       bool save( tnlFile& file ) const;
    
       //! Method for restoring the object from a file
       bool load( tnlFile& file );
    
       bool save( const tnlString& fileName ) const;
    
       bool load( const tnlString& fileName );
    
       //! This method writes the grid in some format suitable for some other preprocessing.
       /*! Possible formats are:
        *  1) Gnuplot format (gnuplot)
        *  2) VTI format (vti)
        *  3) Povray format (povray) - only for 3D.
        */
       bool draw( const tnlString& fileName,
                  const tnlString& format,
    
                  const tnlTuple< Dimensions, Index > steps = ( tnlTuple< Dimensions, Index > ) 1 ) const;
    
       tnlTuple< Dimensions, Real > domainLowerCorner, domainUpperCorner, spaceSteps;
    
    };
    
    #ifdef HAVE_CUDA
    template< int Dimensions, typename Real, typename Index >
    __global__ void setConstantDirichletBC( const Index xSize,
                                            const Index ySize,
                                            const Real bc,
                                            Real* u );
    
    template< int Dimensions, typename Real, typename Index >
    __global__ void setDirichletBC( const Index xSize,
                                    const Index ySize,
                                    const Real* bc,
                                    Real* u );
    
    template< int Dimensions, typename Real, typename Index >
    __global__ void setConstantNeumannBC( const Index xSize,
                                          const Index ySize,
                                          const Real hx,
                                          const Real hy,
                                          const Real bc,
                                          Real* u );
    
    template< int Dimensions, typename Real, typename Index >
    __global__ void setNeumannBC( const Index xSize,
                                  const Index ySize,
                                  const Real hx,
                                  const Real hy,
                                  const Real* bc,
                                  Real* u );
    #endif
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    tnlGrid< Dimensions, Real, Device, Index > :: tnlGrid( const tnlString& name )
    : tnlArray< Dimensions, Real, Device, Index >( name )
      {
      }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    tnlGrid< Dimensions, Real, Device, Index > :: tnlGrid( const tnlString& name,
                                                           const tnlGrid< Dimensions, Real, tnlHost, Index >& grid )
    : tnlArray< Dimensions, Real, Device, Index >( name, grid )
    {
       this -> setDomain( grid. getDomainLowerCorner(),
                          grid. getDomainUpperCorner() );
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    tnlGrid< Dimensions, Real, Device, Index > :: tnlGrid( const tnlString& name,
                                                           const tnlGrid< Dimensions, Real, tnlCuda, Index >& grid )
    : tnlArray< Dimensions, Real, Device, Index >( name, grid )
    {
       this -> setDomain( grid. getDomainLowerCorner(),
                          grid. getDomainUpperCorner() );
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    
    const tnlTuple< Dimensions, Index >& tnlGrid< Dimensions, Real, Device, Index > :: getDimensions() const
    
    {
       return tnlArray< Dimensions, Real, Device, Index > :: getDimensions();
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    
    bool tnlGrid< Dimensions, Real, Device, Index > :: setDimensions( const tnlTuple< Dimensions, Index >& dimensions )
    
    {
       if( ! tnlArray< Dimensions, Real, Device, Index > :: setDimensions( dimensions ) )
          return false;
       for( int i = 0; i < Dimensions; i ++ )
          spaceSteps[ i ] = ( domainUpperCorner[ i ] - domainLowerCorner[ i ] ) / ( Real ) ( this -> getDimensions()[ i ] - 1 );
       return true;
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    
    bool tnlGrid< Dimensions, Real, Device, Index > :: setDomain( const tnlTuple< Dimensions, Real >& lowerCorner,
                                                                  const tnlTuple< Dimensions, Real >& upperCorner )
    
    {
       if( lowerCorner >= upperCorner )
       {
          cerr << "Wrong parameters for the grid domain of " << this -> getName() << ". The low corner must by smaller than the high corner." << endl
                   << "lowerCorner = " << lowerCorner << endl << "upperCorner = " << upperCorner << endl;
          return false;
       }
       domainLowerCorner = lowerCorner;
       domainUpperCorner = upperCorner;
       for( int i = 0; i < Dimensions; i ++ )
          spaceSteps[ i ] = ( domainUpperCorner[ i ] - domainLowerCorner[ i ] ) / ( Real ) ( this -> getDimensions()[ i ] - 1 );
       return true;
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    bool tnlGrid< Dimensions, Real, Device, Index > :: setLike( const tnlGrid< Dimensions, Real, tnlHost, Index >& v )
    {
       return tnlArray< Dimensions, Real, Device, Index > :: setLike( v ) &&
              this -> setDomain( v. getDomainLowerCorner(), v. getDomainUpperCorner() );
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    bool tnlGrid< Dimensions, Real, Device, Index > :: setLike( const tnlGrid< Dimensions, Real, tnlCuda, Index >& v )
    {
       return tnlArray< Dimensions, Real, Device, Index > :: setLike( v ) &&
              this -> setDomain( v. getDomainLowerCorner(), v. getDomainUpperCorner() );
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    
    const tnlTuple< Dimensions, Real >& tnlGrid< Dimensions, Real, Device, Index > :: getDomainLowerCorner() const
    
    {
       return this -> domainLowerCorner;
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    
    const tnlTuple< Dimensions, Real >& tnlGrid< Dimensions, Real, Device, Index > :: getDomainUpperCorner() const
    
    {
       return this -> domainUpperCorner;
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    
    const tnlTuple< Dimensions, Real >& tnlGrid< Dimensions, Real, Device, Index > :: getSpaceSteps() const
    
    {
       return spaceSteps;
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    tnlString tnlGrid< Dimensions, Real, Device, Index > :: getType() const
    {
       return tnlString( "tnlGrid< ") +
              tnlString( Dimensions ) +
              tnlString( ", " ) +
    
              tnlString( getParameterType< Real >() ) +
    
              tnlString( ", " ) +
              getDeviceType( Device ) +
              tnlString( ", " ) +
    
              tnlString( getParameterType< Index >() ) +
    
              tnlString( " >" );
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    bool tnlGrid< Dimensions, Real, Device, Index > :: operator == ( const tnlGrid< Dimensions, Real, Device, Index >& grid ) const
    {
       tnlAssert( this -> getDomainLowerCorner() == grid. getDomainLowerCorner() &&
                  this -> getDomainUpperCorner() == grid. getDomainUpperCorner(),
                  cerr << "You are attempting to compare two grids with different domains." << endl
                       << "First grid name is " << this -> getName()
                       << " domain is ( " << this -> getDomainLowerCorner() << " )- ("
                                          << this -> getDomainUpperCorner() << ")" << endl
                       << "Second grid is " << grid. getName()
                       << " domain is ( " << grid. getDomainLowerCorner() << " )- ("
                                          << grid. getDomainUpperCorner() << ")" << endl; );
       return tnlArray< Dimensions, Real, Device, Index > :: operator == ( grid );
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    bool tnlGrid< Dimensions, Real, Device, Index > :: operator != ( const tnlGrid< Dimensions, Real, Device, Index >& grid ) const
    {
       return ! ( (* this ) == grid );
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
      template< typename Real2, tnlDevice Device2, typename Index2 >
    tnlGrid< Dimensions, Real, Device, Index >&
    tnlGrid< Dimensions, Real, Device, Index >
    :: operator = ( const tnlGrid< Dimensions, Real2, Device2, Index2 >& grid )
    {
       tnlAssert( this -> getDimensions() == grid. getDimensions(),
                  cerr << "You are attempting to assign two arrays with different dimensions." << endl
                       << "First array name is " << this -> getName()
                       << " dimensions are ( " << this -> getDimensions() << " )" << endl
                       << "Second array is " << grid. getName()
                       << " dimensions are ( " << grid. getDimensions() << " )" << endl; );
    
       tnlVector< Real, Device, Index > :: operator = ( grid );
    
       return ( *this );
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    
    Real tnlGrid< Dimensions, Real, Device, Index > :: getValue( const tnlTuple< Dimensions, Real >& point ) const
    
    {
       if( Dimensions == 1)
       {
          tnlAssert( 0, cerr << "Interpolation is not implemented yet.");
       }
       if( Dimensions == 2 )
       {
          Real x = ( point[ 0 ] - domainLowerCorner[ 0 ] ) / spaceSteps[ 0 ];
          Real y = ( point[ 1 ] - domainLowerCorner[ 1 ] ) / spaceSteps[ 1 ];
          Index ix = ( Index ) ( x );
          Index iy = ( Index ) ( y );
          Real dx = x - ( Real ) ix;
          Real dy = y - ( Real ) iy;
          if( iy >= this -> getDimensions()[ tnlY ] - 1 )
          {
             if( ix >= this -> getDimensions()[ tnlX ] - 1 )
                return  this -> getElement( this -> getDimensions()[ tnlX ] - 1,
                                            this -> getDimensions()[ tnlY ] - 1 );
             return ( Real( 1.0 ) - dx ) * this -> getElement( ix,
                                                               this -> getDimensions()[ tnlY ] - 1 ) +
                                                               dx * this -> getElement( ix + 1,
                                                               this -> getDimensions()[ tnlY ] - 1 );
          }
          if( ix >= this -> getDimensions()[ tnlX ] - 1 )
             return ( Real( 1.0 ) - dy ) * this -> getElement( this -> getDimensions()[ tnlX ] - 1,
                                                               iy ) +
                                                               dy * this -> getElement( this -> getDimensions()[ tnlX ] - 1,
                                                               iy + 1 );
          Real a1, a2;
          a1 = ( Real( 1.0 ) - dx ) * this -> getElement( ix, iy ) +
                                 dx * this -> getElement( ix + 1, iy );
    
          a2 = ( Real( 1.0 ) - dx ) * this -> getElement( ix, iy + 1 ) +
                                 dx * this -> getElement( ix + 1, iy + 1 );
          return ( Real( 1.0 ) - dy ) * a1 + dy * a2;
       }
       if( Dimensions == 3 )
       {
          tnlAssert( 0, cerr << "Interpolation is not implemented yet.");
       }
       if( Dimensions > 3 )
       {
          cerr << "Interpolation for 4D grids is not implemented yet." << endl;
          abort();
       }
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: getValue( const Real& x ) const
    {
    
       return this -> getValue( tnlTuple< 1, Real >( x ) );
    
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: getValue( const Real& x,
                                                                 const Real& y ) const
    {
    
       return this -> getValue( tnlTuple< 2, Real >( x, y ) );
    
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: getValue( const Real& x,
                                                                 const Real& y,
                                                                 const Real& z ) const
    {
    
       return this -> getValue( tnlTuple< 3, Real >( x, y, z ) );
    
    512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000
    }
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_x_f( const Index i1 ) const
    {
       tnlAssert( Dimensions == 1,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 1 is expected." << endl; );
       tnlAssert( i1 >= 0 &&
                  i1 < ( this -> getDimensions(). x() - 1 ),
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                       ( this -> getDimensions(). y() - 1  ) << " )" << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( tnlArray< 1, Real, tnlHost, Index > :: getElement( i1 + 1 ) -
                tnlArray< 1, Real, tnlHost, Index > ::  getElement( i1 ) ) / Hx;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_x_f( const Index i1,
                                                                    const Index i2 ) const
    {
       tnlAssert( Dimensions == 2,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 2 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 >= 0 &&
                  i1 < this -> getDimensions(). x() - 1 && i2 <= this -> getDimensions(). y() - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions() .x() - 1  ) << " ) " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions(). y() - 1  ) << " ] " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( this -> getElement( i1 + 1, i2 ) -
                this ->  getElement( i1, i2 ) ) / Hx;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_x_f( const Index i1,
                                                                    const Index i2,
                                                                    const Index i3 ) const
    {
       tnlAssert( Dimensions == 3,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 3 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 >= 0 && i3 >= 0 &&
                  i1 < this -> getDimensions()[ tnlX ] - 1 &&
                  i2 <= this -> getDimensions()[ tnlY ] - 1 &&
                  i3 <= this -> getDimensions()[ tnlZ ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ) " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl
                       << " i3 = " << i3 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlZ ] - 1  ) << " ] " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( this -> getElement( i1 + 1, i2, i3 ) -
                this ->  getElement( i1, i2, i3 ) ) / Hx;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_x_b( const Index i1 ) const
    {
       tnlAssert( Dimensions == 1,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 1 is expected." << endl; );
       tnlAssert( i1 > 0 &&
                  i1 <= ( tnlArray< 1, Real, tnlHost, Index > :: getDimensions()[ tnlX ] - 1 ),
                  cerr << " i1 = " << i1 << " and it should be in ( 0, " <<
                       ( tnlArray< 1, Real, tnlHost, Index > :: getDimensions()[ tnlX ] - 1  ) << " ] " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( tnlArray< 1, Real, tnlHost, Index > :: getElement( i1 ) -
                tnlArray< 1, Real, tnlHost, Index > :: getElement( i1 - 1 ) ) / Hx;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_x_b( const Index i1,
                                                                    const Index i2 ) const
    {
       tnlAssert( Dimensions == 2,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 2 are expected." << endl; );
       tnlAssert( i1 > 0 && i2 >= 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 && i2 <= this -> getDimensions()[ tnlY ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( this -> getElement( i1, i2 ) -
                this -> getElement( i1 - 1, i2 ) ) / Hx;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_x_b( const Index i1,
                                                                    const Index i2,
                                                                    const Index i3 ) const
    {
       tnlAssert( Dimensions == 3,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 3 are expected." << endl; );
       tnlAssert( i1 > 0 && i2 >= 0 && i3 >= 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 &&
                  i2 <= this -> getDimensions()[ tnlY ] - 1 &&
                  i3 <= this -> getDimensions()[ tnlZ ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl
                       << " i3 = " << i3 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlZ ] - 1  ) << " ] " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( this -> getElement( i1, i2, i3 ) -
                this ->  getElement( i1 - 1, i2, i3 ) ) / Hx;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_x( const Index i1 ) const
    {
       tnlAssert( Dimensions == 1,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 1 is expected." << endl; );
       tnlAssert( i1 > 0 &&
                  i1 < ( this -> getDimensions()[ tnlX ] - 1 ),
                  cerr << " i1 = " << i1 << " and it should be in ( 0, " <<
                       ( this -> getDimensions()[ tnlX ] - 1  ) << " ) " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( tnlArray< 1, Real, tnlHost, Index > :: getElement( i1 + 1 ) -
                tnlArray< 1, Real, tnlHost, Index > :: getElement( i1 - 1 ) ) / ( 2.0 * Hx );
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_x( const Index i1,
                                                                  const Index i2 ) const
    {
       tnlAssert( Dimensions == 2,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 2 are expected." << endl; );
       tnlAssert( i1 > 0 && i2 >= 0 &&
                  i1 < this -> getDimensions()[ tnlX ] - 1 && i2 <= this -> getDimensions()[ tnlY ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ) " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( this -> getElement( i1 + 1, i2 ) -
                this -> getElement( i1 - 1, i2 ) ) / ( 2.0 * Hx );
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_x( const Index i1,
                                                                  const Index i2,
                                                                  const Index i3 ) const
    {
       tnlAssert( Dimensions == 3,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 3 are expected." << endl; );
       tnlAssert( i1 > 0 && i2 >= 0 && i3 >= 0 &&
                  i1 < this -> getDimensions()[ tnlX ] - 1 &&
                  i2 <= this -> getDimensions()[ tnlY ] - 1 &&
                  i3 <= this -> getDimensions()[ tnlZ ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ) " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl
                       << " i3 = " << i3 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlZ ] - 1  ) << " ] " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( this -> getElement( i1 + 1, i2, i3 ) -
                this -> getElement( i1 - 1, i2, i3 ) ) / ( 2.0 * Hx );
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_xx( const Index i1 ) const
    {
       tnlAssert( Dimensions == 1,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 1 is expected." << endl; );
       tnlAssert( i1 > 0 &&
                  i1 < ( tnlArray< 1, Real, tnlHost, Index > :: getDimensions()[ tnlX ] - 1 ),
                  cerr << " i1 = " << i1 << " and it should be in ( 0, " <<
                       ( tnlArray< 1, Real, tnlHost, Index > :: getDimensions()[ tnlX ] - 1  ) << " ) " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( tnlArray< 1, Real, tnlHost, Index > :: getElement( i1 + 1 ) -
                2.0 * tnlArray< 1, Real, tnlHost, Index > :: getElement( i1 ) +
                tnlArray< 1, Real, tnlHost, Index > :: getElement( i1 - 1 ) ) / ( Hx * Hx );
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_xx( const Index i1,
                                                                   const Index i2 ) const
    {
       tnlAssert( Dimensions == 2,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 2 are expected." << endl; );
       tnlAssert( i1 > 0 && i2 >= 0 &&
                  i1 < this -> getDimensions()[ tnlX ] - 1 && i2 <= this -> getDimensions()[ tnlY ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ) " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( this -> getElement( i1 + 1, i2 ) -
                2.0 * this -> getElement( i1, i2 ) +
                this -> getElement( i1 - 1, i2 ) ) / ( Hx * Hx );
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_xx( const Index i1,
                                                                   const Index i2,
                                                                   const Index i3 ) const
    {
       tnlAssert( Dimensions == 3,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 3 are expected." << endl; );
       tnlAssert( i1 > 0 && i2 >= 0 && i3 >= 0 &&
                  i1 < this -> getDimensions()[ tnlX ] - 1 &&
                  i2 <= this -> getDimensions()[ tnlY ] - 1 &&
                  i3 <= this -> getDimensions()[ tnlZ ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ) " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl
                       << " i3 = " << i3 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlZ ] - 1  ) << " ] " << endl; );
    
       const Real& Hx = spaceSteps[ 0 ];
       tnlAssert( Hx > 0, cerr << "Hx = " << Hx << endl; );
       return ( this -> getElement( i1 + 1, i2, i3 ) -
                2.0 * this -> getElement( i1, i2, i3 ) +
                this -> getElement( i1 - 1, i2, i3 ) ) / ( Hx * Hx );
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_y_f( const Index i1,
                                                                    const Index i2 ) const
    {
       tnlAssert( Dimensions == 2,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 2 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 >= 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 && i2 < this -> getDimensions()[ tnlY ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ) " << endl; );
    
       const Real& Hy = spaceSteps[ 1 ];
       tnlAssert( Hy > 0, cerr << "Hy = " << Hy << endl; );
       return ( this -> getElement( i1, i2 + 1 ) -
                this -> getElement( i1, i2 ) ) / Hy;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_y_f( const Index i1,
                                                                    const Index i2,
                                                                    const Index i3 ) const
    {
       tnlAssert( Dimensions == 3,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 3 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 >= 0 && i3 >= 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 &&
                  i2 < this -> getDimensions()[ tnlY ] - 1 &&
                  i3 <= this -> getDimensions()[ tnlZ ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ) " << endl
                       << " i3 = " << i3 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlZ ] - 1  ) << " ] " << endl; );
    
       const Real& Hy = spaceSteps[ 1 ];
       tnlAssert( Hy > 0, cerr << "Hy = " << Hy << endl; );
       return ( this -> getElement( i1, i2 + 1, i3 ) -
                this -> getElement( i1, i2, i3 ) ) / Hy;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_y_b( const Index i1,
                                                                    const Index i2 ) const
    {
       tnlAssert( Dimensions == 2,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 2 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 > 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 && i2 <= this -> getDimensions()[ tnlY ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl; );
    
       const Real& Hy = spaceSteps[ 1 ];
       tnlAssert( Hy > 0, cerr << "Hy = " << Hy << endl; );
       return ( this -> getElement( i1, i2 ) -
                this -> getElement( i1, i2 - 1 ) ) / Hy;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_y_b( const Index i1,
                                                                    const Index i2,
                                                                    const Index i3 ) const
    {
       tnlAssert( Dimensions == 3,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 3 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 > 0 && i3 >= 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 &&
                  i2 <= this -> getDimensions()[ tnlY ] - 1 &&
                  i3 <= this -> getDimensions()[ tnlZ ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl
                       << " i3 = " << i3 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlZ ] - 1  ) << " ] " << endl; );
    
       const Real& Hy = spaceSteps[ 1 ];
       tnlAssert( Hy > 0, cerr << "Hy = " << Hy << endl; );
       return ( this -> getElement( i1, i2, i3 ) -
                this -> getElement( i1, i2 - 1, i3 ) ) / Hy;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_y( const Index i1,
                                                                  const Index i2 ) const
    {
       tnlAssert( Dimensions == 2,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 2 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 > 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 && i2 < this -> getDimensions()[ tnlY ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ) " << endl; );
    
       const Real& Hy = spaceSteps[ 1 ];
       tnlAssert( Hy > 0, cerr << "Hy = " << Hy << endl; );
       return ( this -> getElement( i1, i2 + 1 ) -
                this -> getElement( i1, i2 - 1 ) ) / ( 2.0 * Hy );
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_y( const Index i1,
                                                                  const Index i2,
                                                                  const Index i3 ) const
    {
       tnlAssert( Dimensions == 3,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 3 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 > 0 && i3 >= 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 &&
                  i2 < this -> getDimensions()[ tnlY ] - 1 &&
                  i3 <= this -> getDimensions()[ tnlZ ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ) " << endl
                       << " i3 = " << i3 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlZ ] - 1  ) << " ] " << endl; );
    
       const Real& Hy = spaceSteps[ 1 ];
       tnlAssert( Hy > 0, cerr << "Hy = " << Hy << endl; );
       return ( this -> getElement( i1, i2 + 1, i3 ) -
                this -> getElement( i1, i2 - 1, i3 ) ) / ( 2.0 * Hy );
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_yy( const Index i1,
                                                                   const Index i2 ) const
    {
       tnlAssert( Dimensions == 2,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 2 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 > 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 && i2 < this -> getDimensions()[ tnlY ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ) " << endl; );
    
       const Real& Hy = spaceSteps[ 1 ];
       tnlAssert( Hy > 0, cerr << "Hy = " << Hy << endl; );
       return ( this -> getElement( i1, i2 + 1 ) -
                2.0 * this -> getElement( i1, i2 ) +
                this -> getElement( i1, i2 - 1 ) ) / ( Hy * Hy );
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_yy( const Index i1,
                                                                   const Index i2,
                                                                   const Index i3 ) const
    {
       tnlAssert( Dimensions == 3,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 3 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 > 0 && i3 >= 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 &&
                  i2 < this -> getDimensions()[ tnlY ] - 1 &&
                  i3 <= this -> getDimensions()[ tnlZ ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ) " << endl
                       << " i3 = " << i3 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlZ ] - 1  ) << " ] " << endl; );
    
       const Real& Hy = spaceSteps[ 1 ];
       tnlAssert( Hy > 0, cerr << "Hy = " << Hy << endl; );
       return ( this -> getElement( i1, i2 + 1, i3 ) -
                2.0 * this -> getElement( i1, i2, i3 ) +
                this -> getElement( i1, i2 - 1, i3 ) ) / ( Hy * Hy );
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_z_f( const Index i1,
                                                                    const Index i2,
                                                                    const Index i3 ) const
    {
       tnlAssert( Dimensions == 3,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 3 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 >= 0 && i3 >= 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 &&
                  i2 <= this -> getDimensions()[ tnlY ] - 1 &&
                  i3 < this -> getDimensions()[ tnlZ ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl
                       << " i3 = " << i3 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlZ ] - 1  ) << " ) " << endl; );
    
       const Real& Hz = spaceSteps[ 2 ];
       tnlAssert( Hz > 0, cerr << "Hz = " << Hz << endl; );
       return ( this -> getElement( i1, i2, i3 + 1 ) -
                this -> getElement( i1, i2, i3 ) ) / Hz;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_z_b( const Index i1,
                                                                    const Index i2,
                                                                    const Index i3 ) const
    {
       tnlAssert( Dimensions == 3,
                  cerr << "The array " << this -> getName()
                       << " has " << Dimensions << " but 3 are expected." << endl; );
       tnlAssert( i1 >= 0 && i2 >= 0 && i3 > 0 &&
                  i1 <= this -> getDimensions()[ tnlX ] - 1 &&
                  i2 <= this -> getDimensions()[ tnlY ] - 1 &&
                  i3 <= this -> getDimensions()[ tnlZ ] - 1,
                  cerr << " i1 = " << i1 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlX ] - 1  ) << " ] " << endl
                       << " i2 = " << i2 << " and it should be in [ 0, " <<
                          ( this -> getDimensions()[ tnlY ] - 1  ) << " ] " << endl
                       << " i3 = " << i3 << " and it should be in ( 0, " <<
                          ( this -> getDimensions()[ tnlZ ] - 1  ) << " ] " << endl; );
    
       const Real& Hz = spaceSteps[ 2 ];
       tnlAssert( Hz > 0, cerr << "Hz = " << Hz << endl; );
       return ( this -> getElement( i1, i2, i3 ) -
                this -> getElement( i1, i2, i3 - 1 ) ) / Hz;
    };
    
    template< int Dimensions, typename Real, tnlDevice Device, typename Index >
    Real tnlGrid< Dimensions, Real, Device, Index > :: Partial_z( const Index i1,
                                                                  const Index i2,
                                                                  const Index i3 ) const