PetscVec
Date: 2013-07-02

    classdef
       petsc-3.4.2 2013-07-02 PetscVec < PetscObject
    %
    %   PetscVec - Holds field variables, right hand sides to linear systems etc.
    %
    %   Creation:
    %     v = PetscVec;
    %       v.SetType('seq');
    %       v.SetSizes(3);
    %
    %     v = PetscVec([1 2 3]);
    %
    %   If v is a PetscVec then a = v(:) returns a MATLAB array of the vector
    %       and v(:) = a; assigns the array values in a into the vector.
    %       v(1:3) = [2.0 2. 3.0]; also work
    %
    %   Indexing into PETSc Vecs and Mats from MATLAB starts with index of 1, NOT 0 like
    %     everywhere else in PETSc, but Shri felt MATLAB users could not handle 0.
    %
      properties
        VecFromDM=0;
        DM = [];
      end
      methods
        function [obj] = SetVecfromDM(obj,value)
          obj.VecFromDM = value;
        end
        function [obj] = SetDM(obj,DM)
            obj.DM = DM;
        end
        function obj = PetscVec(array,flg)
          if (nargin > 1)
            %  PetscVec(pid,'pobj') uses an already existing PETSc Vec object
            obj.pobj = array;
            return
          end
          comm = PETSC_COMM_SELF();
          [err,obj.pobj] = calllib('libpetsc', 'VecCreate',comm ,0);PetscCHKERRQ(err);
          if (nargin > 0)
            % Vec(array) creates a Vec initialized with the given array
            err = calllib('libpetsc', 'VecSetType', obj.pobj,'seq');PetscCHKERRQ(err);
            err = calllib('libpetsc', 'VecSetSizes', obj.pobj,length(array),length(array));PetscCHKERRQ(err);
            idx = 0:length(array)-1;
            err = calllib('libpetsc', 'VecSetValues', obj.pobj,length(idx),idx,array,Petsc.INSERT_VALUES);PetscCHKERRQ(err);
            err = calllib('libpetsc', 'VecAssemblyBegin', obj.pobj);PetscCHKERRQ(err);
            err = calllib('libpetsc', 'VecAssemblyEnd', obj.pobj);PetscCHKERRQ(err);
          end
        end
        function err = SetFromOptions(obj)
          err = calllib('libpetsc', 'VecSetFromOptions', obj.pobj);PetscCHKERRQ(err);
        end
        function err = SetType(obj,name)
          err = calllib('libpetsc', 'VecSetType', obj.pobj,name);PetscCHKERRQ(err);
        end
        function err = SetSizes(obj,m,n)
          if (nargin == 2)
            n = Petsc.DECIDE;
          end
          err = calllib('libpetsc', 'VecSetSizes', obj.pobj,m,n);PetscCHKERRQ(err);
        end
        function [n,err] = GetSize(obj)
          n = 0;
          [err,n] = calllib('libpetsc', 'VecGetLocalSize', obj.pobj,n);PetscCHKERRQ(err);
        end
        function err = SetValues(obj,idx,values,insertmode)
          if (ischar(idx)) % assume it is ':'
            [n,err] = GetSize(obj);
            idx = 1:n;
          end
          if (nargin < 3)
            values = idx;
          end
          if (nargin  < 4)
            insertmode = Petsc.INSERT_VALUES;
          end
          idx = idx - 1;
          err = calllib('libpetsc', 'VecSetValues', obj.pobj,length(idx),idx,values,insertmode);PetscCHKERRQ(err);
        end
        function [values,err] = GetValues(obj,idx)
          if (ischar(idx)) % assume it is ':'
            [n,err] = GetSize(obj);
            idx = 1:n;
          end
          idx = idx - 1;
          values = zeros(1,length(idx));
          [err,idx,values] = calllib('libpetsc', 'VecGetValues', obj.pobj,length(idx),idx,values);PetscCHKERRQ(err);
          values = values'; % Want to return a column vector since that is more natural in MATLAB
        end
        function err = AssemblyBegin(obj)
          err = calllib('libpetsc', 'VecAssemblyBegin', obj.pobj);PetscCHKERRQ(err);
        end
        function err = AssemblyEnd(obj)
          err = calllib('libpetsc', 'VecAssemblyEnd', obj.pobj);PetscCHKERRQ(err);
        end
        function [vec,err] = Duplicate(obj)
          [err,pid] = calllib('libpetsc', 'VecDuplicate', obj.pobj,0);PetscCHKERRQ(err);
          vec = PetscVec(pid,'pobj');
        end
        function err = Copy(obj,v)
          err = calllib('libpetsc', 'VecCopy', obj.pobj,v.pobj);PetscCHKERRQ(err);
        end
        function err = Set(obj,v)
          err = calllib('libpetsc', 'VecSet', obj.pobj,v);PetscCHKERRQ(err);
        end
        function err = View(obj,viewer)
          if (nargin == 1)
            err = calllib('libpetsc', 'VecView', obj.pobj,0);PetscCHKERRQ(err);
          else
            err = calllib('libpetsc', 'VecView', obj.pobj,viewer.pobj);PetscCHKERRQ(err);
          end
        end
        function err = Destroy(obj)
          err = calllib('libpetsc', 'VecDestroy', obj.pobj);PetscCHKERRQ(err);
        end
    %
    %   The following overload a = x(idx)
    %
        function varargout = subsref(obj,S)
          %  MATLAB design of subsref is MORONIC
          %  To overload () it automatically overloads . which is used
          %  for method calls so we need to force the method calls to use
          %  the 'regular' subsref
          if (S(1).type == '.')
            [varargout{1:nargout}] = builtin('subsref', obj, S);
          else
            if (obj.VecFromDM)
              varargout = {obj.GetValues_DM(S)};
            else
              varargout = {obj.GetValues(S.subs{1})};
            end
          end
        end
        function varargout = GetValues_DM(obj,S)
          M = obj.DM.M; N = obj.DM.N; P = obj.DM.P;
          ndim = obj.DM.ndim;
          if (ndim == 1)  %% 1D DM
            idx = S.subs{1};
          elseif (ndim == 2)  %% 2D DM
            idx = M*(S.subs{2}-1) + S.subs{1};
          elseif (ndim == 3)  %% 3D DM
            idx = N*M(S.subs{3}-1) + M*(S.subs{2}-1) + S.subs{1};
          end
          varargout = {obj.GetValues(idx)};
        end
    %
    %   The following overload x(idx) = a
    %
        function obj = subsasgn(obj,S,value)
          if (S(1).type ~= '.')
            if (obj.VecFromDM)
              [obj] = obj.SetValues_DM(S,value);
            else
              obj.SetValues(S.subs{1},value);
            end
          end
        end
        function [obj] = SetValues_DM(obj,S,value)
          M = obj.DM.M; N = obj.DM.N; P = obj.DM.P;
          ndim = obj.DM.ndim;
          if (ndim == 1)  %% 1D DM
            idx = S.subs{1};
          elseif (ndim == 2)  %% 2D DM
            idx = M*(S.subs{2}-1) + S.subs{1};
          elseif (ndim == 3)  %% 3D DM
            idx = N*M(S.subs{3}-1) + M*(S.subs{2}-1) + S.subs{1};
          end
          obj.SetValues(idx,value);
        end
      end
    end