namespace PyTrilinos
{

// Static variables
const Epetra_SerialComm   Epetra_NumPyVector::defaultComm = Epetra_SerialComm();
PyArrayObject           * Epetra_NumPyVector::tmp_array   = NULL               ;
Epetra_Map              * Epetra_NumPyVector::tmp_map     = NULL               ;

// Static helper functions
// =============================================================================
double * Epetra_NumPyVector::getArray(PyObject * pyObject)
{
  // Try to build a contiguous PyArrayObject from the pyObject
  if (!tmp_array)
    tmp_array = (PyArrayObject *)
      PyArray_ContiguousFromObject(pyObject,PyArray_DOUBLE,0,0);
  
  // If this fails, clean up and throw a PythonException
  if (!tmp_array)
  {
    cleanup();
    throw PythonException();
  }

  return (double*)(tmp_array->data);
}

// =============================================================================
double * Epetra_NumPyVector::getArray(const Epetra_BlockMap & blockMap,
				      PyObject * pyObject)
{
  // Only build the tmp_array if it does not already exist
  if (!tmp_array)
  {
    // Default dimensions
    npy_intp defaultDims[ ] = { blockMap.NumMyPoints() };

    // PyObject argument is a bool
    if (PyBool_Check(pyObject))
    {
      tmp_array = (PyArrayObject *)
	PyArray_SimpleNew(1,defaultDims,PyArray_DOUBLE);
      if (tmp_array == NULL)
      {
	cleanup();
	throw PythonException();
      }
      else
      {
	if (pyObject == Py_True)     // bool zeroOut is True
	{
	  double * data = (double*) tmp_array->data;
	  for (int i=0; i<defaultDims[0]; ++i) data[i] = 0.0;
	}
      }

    // PyObject argument is not an bool ... try to build a contiguous
    // PyArrayObject from it
    }
    else
    {
      tmp_array = (PyArrayObject *)
	PyArray_ContiguousFromObject(pyObject,PyArray_DOUBLE,0,0);

      // If this fails, clean up and throw a PythonException
      if (!tmp_array)
      {
	cleanup();
	throw PythonException();
      }
      // If the contiguous PyArrayObject built successfully, make sure
      // it has the correct number of dimensions
      else
      {
	int nd = tmp_array->nd;
	npy_intp arraySize = PyArray_MultiplyList(tmp_array->dimensions,nd);
	if (arraySize != defaultDims[0])
	{
	  PyArrayObject * myArray = (PyArrayObject *)
	    PyArray_SimpleNew(1,defaultDims,PyArray_DOUBLE);
	  double * myData  = (double *) myArray->data;
	  double * tmpData = (double *) tmp_array->data;
	  for (int i=0; i<defaultDims[0]; i++)
	  {
	    myData[i] = tmpData[i];
	  }
	  Py_XDECREF(tmp_array);
	  tmp_array = myArray;
	}
      }
    }
  }
  return (double*)(tmp_array->data);
}

// =============================================================================
Epetra_Map & Epetra_NumPyVector::getMap(PyObject * pyObject)
{
  if (!tmp_array) getArray(pyObject);
  if (!tmp_map)
  {
    const int totalLength = PyArray_Size((PyObject *)tmp_array);
    tmp_map = new Epetra_Map(totalLength,0,defaultComm);
  }
  return *tmp_map;
}

// =============================================================================
int Epetra_NumPyVector::getVectorSize(PyObject * pyObject)
{
  if (!tmp_map) getMap(pyObject);
  return tmp_map->NumMyPoints();
}

// =============================================================================
void Epetra_NumPyVector::cleanup()
{
  if (tmp_array)
  {
    Py_DECREF(tmp_array);
    tmp_array = NULL;
  }
  if (tmp_map)
  {
    delete tmp_map;
    tmp_map = NULL;
  }
}

// =============================================================================

// Constructors
// =============================================================================
Epetra_NumPyVector::Epetra_NumPyVector(const Epetra_BlockMap & blockMap, bool zeroOut):
  Epetra_Vector(blockMap, zeroOut)
{
  // Create the array object
  npy_intp dims[ ] = { blockMap.NumMyPoints() };
  double *v = NULL;
  Epetra_Vector::ExtractView(&v);
  array = (PyArrayObject *)
    PyArray_SimpleNewFromData(1,dims,PyArray_DOUBLE,(void *)v);
  if (!array)
  {
    cleanup();
    throw PythonException();
  }

  // Copy the Epetra_BlockMap
  map = new Epetra_BlockMap(blockMap);
}

// =============================================================================
Epetra_NumPyVector::Epetra_NumPyVector(const Epetra_Vector & source):
  Epetra_Vector(source)
{
  map = new Epetra_BlockMap(source.Map());
  npy_intp dims[ ] = { map->NumMyPoints() };
  double *v = NULL;
  Epetra_Vector::ExtractView(&v);
  array = (PyArrayObject *)
    PyArray_SimpleNewFromData(1,dims,PyArray_DOUBLE,(void *)v);
  if (!array)
  {
    cleanup();
    throw PythonException();
  }
}

// =============================================================================
Epetra_NumPyVector::Epetra_NumPyVector(const Epetra_BlockMap & blockMap,
                                       PyObject * pyObject):
  Epetra_Vector(View, blockMap, getArray(blockMap,pyObject))
{
  // Get the pointer to the array from static variable and clear
  array     = tmp_array;
  tmp_array = NULL;

  // Copy the Epetra_BlockMap
  map = new Epetra_BlockMap(blockMap);
}

// =============================================================================
Epetra_NumPyVector::Epetra_NumPyVector(Epetra_DataAccess CV,
				       const Epetra_Vector & source):
  Epetra_Vector(CV,source,0)
{
  // Store the Epetra_Vector's map
  map = new Epetra_BlockMap(source.Map());

  // Wrap the Epetra_Vector
  npy_intp dims[ ] = { (npy_intp) map->NumMyElements() };
  double *v = NULL;
  Epetra_Vector::ExtractView(&v);
  array = (PyArrayObject *)
    PyArray_SimpleNewFromData(1,dims,PyArray_DOUBLE,(void *)v);
  if (!array)
  {
    cleanup();
    throw PythonException();
  }
}

// =============================================================================
Epetra_NumPyVector::Epetra_NumPyVector(Epetra_DataAccess CV,
				       const Epetra_MultiVector & source,
				       int index):
  Epetra_Vector(CV,source,index)
{
  // Store the Epetra_MultiVector's map
  map = new Epetra_BlockMap(source.Map());

  // Wrap the Epetra_MultiVector
  npy_intp dims[ ] = { map->NumMyElements() };
  double *v = NULL;
  Epetra_Vector::ExtractView(&v);
  array = (PyArrayObject *)
    PyArray_SimpleNewFromData(1,dims,PyArray_DOUBLE,(void *)v);
  if (!array)
  {
    cleanup();
    throw PythonException();
  }
}

// =============================================================================
Epetra_NumPyVector::Epetra_NumPyVector(PyObject * pyObject):
  Epetra_Vector(View, getMap(pyObject), getArray(pyObject)) 
{
  // Store the pointer to the Epetra_Map
  map     = tmp_map;
  tmp_map = NULL;

  // Store the pointer to the PyArrayObject
  array     = tmp_array;
  tmp_array = NULL;
}

// =============================================================================
// Destructor
Epetra_NumPyVector::~Epetra_NumPyVector()
{
  Py_XDECREF(array);
  delete map;
}

// =============================================================================
PyObject * Epetra_NumPyVector::ExtractCopy() const
{
  return PyArray_NewCopy(array,PyArray_ANYORDER);
}

// =============================================================================
PyObject * Epetra_NumPyVector::ExtractView() const
{
  Py_INCREF(array);
  return PyArray_Return(array);
}

// =============================================================================
double Epetra_NumPyVector::Dot(const Epetra_Vector & A) const
{
  double result[1];
  int status = Epetra_MultiVector::Dot(A, result);
  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "Dot returned error code %d", status);
    goto fail;
  }
  return result[0];
 fail:
  // Return type is double, so we cannot return NULL on failure
  return DBL_MAX;
}

// =============================================================================
double Epetra_NumPyVector::Norm1() const
{
  double result[1];
  int status = Epetra_MultiVector::Norm1(result);
  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "Norm1 returned error code %d", status);
    goto fail;
  }
  return result[0];
 fail:
  // Return type is double, so we cannot return NULL on failure
  return DBL_MAX;
}

// =============================================================================
double Epetra_NumPyVector::Norm2() const
{
  double result[1];
  int status = Epetra_MultiVector::Norm2(result);
  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "Norm2 returned error code %d", status);
    goto fail;
  }
  return result[0];
 fail:
  // Return type is double, so we cannot return NULL on failure
  return DBL_MAX;
}

// =============================================================================
double Epetra_NumPyVector::NormInf() const
{
  double result[1];
  int status = Epetra_MultiVector::NormInf(result);
  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "NormInf returned error code %d", status);
    goto fail;
  }
  return result[0];
 fail:
  // Return type is double, so we cannot return NULL on failure
  return DBL_MAX;
}

// =============================================================================
double Epetra_NumPyVector::NormWeighted(const Epetra_Vector & weights) const
{
  double result[1];
  int status = Epetra_MultiVector::NormWeighted(weights,result);
  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "NormWeighted returned error code %d", status);
    goto fail;
  }
  return result[0];
 fail:
  // Return type is double, so we cannot return NULL on failure
  return DBL_MAX;
}

// =============================================================================
double Epetra_NumPyVector::MinValue() const
{
  double result[1];
  int status = Epetra_MultiVector::MinValue(result);
  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "MinValue returned error code %d", status);
    goto fail;
  }
  return result[0];
 fail:
  // Return type is double, so we cannot return NULL on failure
  return DBL_MAX;
}

// =============================================================================
double Epetra_NumPyVector::MaxValue() const
{
  double result[1];
  int status = Epetra_MultiVector::MaxValue(result);
  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "MaxValue returned error code %d", status);
    goto fail;
  }
  return result[0];
 fail:
  // Return type is double, so we cannot return NULL on failure
  return DBL_MAX;
}

// =============================================================================
double Epetra_NumPyVector::MeanValue() const
{
  double result[1];
  int status = Epetra_MultiVector::MeanValue(result);
  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "MeanValue returned error code %d", status);
    goto fail;
  }
  return result[0];
 fail:
  // Return type is double, so we cannot return NULL on failure
  return DBL_MAX;
}

// =============================================================================
int Epetra_NumPyVector::ReplaceGlobalValues(PyObject * values, PyObject * indices)
{
  PyArrayObject * myValues  = NULL;
  PyArrayObject * myIndices = NULL;
  int lenValues;
  int lenIndices;
  int result;
  myValues  = (PyArrayObject *)
    PyArray_ContiguousFromObject(values,PyArray_DOUBLE,0,0);
  if (!myValues) goto fail;
  myIndices = (PyArrayObject *)
    PyArray_ContiguousFromObject(indices,PyArray_INT,0,0);
  if (!myIndices) goto fail;
  lenValues  = (int) PyArray_MultiplyList(myValues->dimensions,  myValues->nd );
  lenIndices = (int) PyArray_MultiplyList(myIndices->dimensions, myIndices->nd);
  if (lenValues != lenIndices)
  {
    PyErr_Format(PyExc_ValueError,
		 "Sequence lengths are %d and %d, but must be of same length",
		 lenValues, lenIndices);
    goto fail;
  }
  result = Epetra_Vector::ReplaceGlobalValues(lenValues,
					      (double *) myValues->data,
					      (int    *) myIndices->data);
  Py_DECREF(myValues );
  Py_DECREF(myIndices);
  return result;
 fail:
  Py_XDECREF(myValues );
  Py_XDECREF(myIndices);
  return -1;
}

// =============================================================================
int Epetra_NumPyVector::ReplaceGlobalValues(int blockOffset, PyObject * values,
					    PyObject * indices)
{
  PyArrayObject * myValues  = NULL;
  PyArrayObject * myIndices = NULL;
  int lenValues;
  int lenIndices;
  int result;
  myValues  = (PyArrayObject *)
    PyArray_ContiguousFromObject(values,PyArray_DOUBLE,0,0);
  if (!myValues) goto fail;
  myIndices = (PyArrayObject *)
    PyArray_ContiguousFromObject(indices,PyArray_INT,0,0);
  if (!myIndices) goto fail;
  lenValues  = (int) PyArray_MultiplyList(myValues->dimensions,  myValues->nd );
  lenIndices = (int) PyArray_MultiplyList(myIndices->dimensions, myIndices->nd);
  if (lenValues != lenIndices)
  {
    PyErr_Format(PyExc_ValueError,
		 "Sequence lengths are %d and %d, but must be of same length",
		 lenValues, lenIndices);
    goto fail;
  }
  result = Epetra_Vector::ReplaceGlobalValues(lenValues, blockOffset,
					      (double *) myValues->data,
					      (int    *) myIndices->data);
  Py_DECREF(myValues );
  Py_DECREF(myIndices);
  return result;
 fail:
  Py_XDECREF(myValues );
  Py_XDECREF(myIndices);
  return -1;
}

// =============================================================================
int Epetra_NumPyVector::ReplaceMyValues(PyObject * values, PyObject * indices)
{
  PyArrayObject * myValues  = NULL;
  PyArrayObject * myIndices = NULL;
  int lenValues;
  int lenIndices;
  int result;
  myValues  = (PyArrayObject *)
    PyArray_ContiguousFromObject(values,PyArray_DOUBLE,0,0);
  if (!myValues) goto fail;
  myIndices = (PyArrayObject *)
    PyArray_ContiguousFromObject(indices,PyArray_INT,0,0);
  if (!myIndices) goto fail;
  lenValues  = (int) PyArray_MultiplyList(myValues->dimensions,  myValues->nd );
  lenIndices = (int) PyArray_MultiplyList(myIndices->dimensions, myIndices->nd);
  if (lenValues != lenIndices)
  {
    PyErr_Format(PyExc_ValueError,
		 "Sequence lengths are %d and %d, but must be of same length",
		 lenValues, lenIndices);
    goto fail;
  }
  result = Epetra_Vector::ReplaceMyValues(lenValues,
					  (double *) myValues->data,
					  (int    *) myIndices->data);
  Py_DECREF(myValues );
  Py_DECREF(myIndices);
  return result;
 fail:
  Py_XDECREF(myValues );
  Py_XDECREF(myIndices);
  return -1;
}

// =============================================================================
int Epetra_NumPyVector::ReplaceMyValues(int blockOffset, PyObject * values,
					PyObject * indices)
{
  PyArrayObject * myValues  = NULL;
  PyArrayObject * myIndices = NULL;
  int lenValues;
  int lenIndices;
  int result;
  myValues  = (PyArrayObject *)
    PyArray_ContiguousFromObject(values,PyArray_DOUBLE,0,0);
  if (!myValues) goto fail;
  myIndices = (PyArrayObject *)
    PyArray_ContiguousFromObject(indices,PyArray_INT,0,0);
  if (!myIndices) goto fail;
  lenValues  = (int) PyArray_MultiplyList(myValues->dimensions,  myValues->nd );
  lenIndices = (int) PyArray_MultiplyList(myIndices->dimensions, myIndices->nd);
  if (lenValues != lenIndices)
  {
    PyErr_Format(PyExc_ValueError,
		 "Sequence lengths are %d and %d, but must be of same length",
		 lenValues, lenIndices);
    goto fail;
  }
  result = Epetra_Vector::ReplaceMyValues(lenValues, blockOffset,
					  (double *) myValues->data,
					  (int    *) myIndices->data);
  Py_DECREF(myValues );
  Py_DECREF(myIndices);
  return result;
 fail:
  Py_XDECREF(myValues );
  Py_XDECREF(myIndices);
  return -1;
}

// =============================================================================
int Epetra_NumPyVector::SumIntoGlobalValues(PyObject * values, PyObject * indices)
{
  PyArrayObject * myValues  = NULL;
  PyArrayObject * myIndices = NULL;
  int lenValues;
  int lenIndices;
  int result;
  myValues  = (PyArrayObject *)
    PyArray_ContiguousFromObject(values,PyArray_DOUBLE,0,0);
  if (!myValues) goto fail;
  myIndices = (PyArrayObject *)
    PyArray_ContiguousFromObject(indices,PyArray_INT,0,0);
  if (!myIndices) goto fail;
  lenValues  = (int) PyArray_MultiplyList(myValues->dimensions,  myValues->nd );
  lenIndices = (int) PyArray_MultiplyList(myIndices->dimensions, myIndices->nd);
  if (lenValues != lenIndices)
  {
    PyErr_Format(PyExc_ValueError,
		 "Sequence lengths are %d and %d, but must be of same length",
		 lenValues, lenIndices);
    goto fail;
  }
  result = Epetra_Vector::SumIntoGlobalValues(lenValues,
					      (double *) myValues->data,
					      (int    *) myIndices->data);
  Py_DECREF(myValues );
  Py_DECREF(myIndices);
  return result;
 fail:
  Py_XDECREF(myValues );
  Py_XDECREF(myIndices);
  return -1;
}

// =============================================================================
int Epetra_NumPyVector::SumIntoGlobalValues(int blockOffset, PyObject * values,
					    PyObject * indices)
{
  PyArrayObject * myValues  = NULL;
  PyArrayObject * myIndices = NULL;
  int lenValues;
  int lenIndices;
  int result;
  myValues  = (PyArrayObject *)
    PyArray_ContiguousFromObject(values,PyArray_DOUBLE,0,0);
  if (!myValues) goto fail;
  myIndices = (PyArrayObject *)
    PyArray_ContiguousFromObject(indices,PyArray_INT,0,0);
  if (!myIndices) goto fail;
  lenValues  = (int) PyArray_MultiplyList(myValues->dimensions,  myValues->nd );
  lenIndices = (int) PyArray_MultiplyList(myIndices->dimensions, myIndices->nd);
  if (lenValues != lenIndices)
  {
    PyErr_Format(PyExc_ValueError,
		 "Sequence lengths are %d and %d, but must be of same length",
		 lenValues, lenIndices);
    goto fail;
  }
  result = Epetra_Vector::SumIntoGlobalValues(lenValues, blockOffset,
					      (double *) myValues->data,
					      (int    *) myIndices->data);
  Py_DECREF(myValues );
  Py_DECREF(myIndices);
  return result;
 fail:
  Py_XDECREF(myValues );
  Py_XDECREF(myIndices);
  return -1;
}

// =============================================================================
int Epetra_NumPyVector::SumIntoMyValues(PyObject * values, PyObject * indices)
{
  PyArrayObject * myValues  = NULL;
  PyArrayObject * myIndices = NULL;
  int lenValues;
  int lenIndices;
  int result;
  myValues  = (PyArrayObject *)
    PyArray_ContiguousFromObject(values,PyArray_DOUBLE,0,0);
  if (!myValues) goto fail;
  myIndices = (PyArrayObject *)
    PyArray_ContiguousFromObject(indices,PyArray_INT,0,0);
  if (!myIndices) goto fail;
  lenValues  = (int) PyArray_MultiplyList(myValues->dimensions,  myValues->nd );
  lenIndices = (int) PyArray_MultiplyList(myIndices->dimensions, myIndices->nd);
  if (lenValues != lenIndices)
  {
    PyErr_Format(PyExc_ValueError,
		 "Sequence lengths are %d and %d, but must be of same length",
		 lenValues, lenIndices);
    goto fail;
  }
  result = Epetra_Vector::SumIntoMyValues(lenValues,
					  (double *) myValues->data,
					  (int    *) myIndices->data);
  Py_DECREF(myValues );
  Py_DECREF(myIndices);
  return result;
 fail:
  Py_XDECREF(myValues );
  Py_XDECREF(myIndices);
  return -1;
}

// =============================================================================
int Epetra_NumPyVector::SumIntoMyValues(int blockOffset, PyObject * values,
					PyObject * indices)
{
  PyArrayObject * myValues  = NULL;
  PyArrayObject * myIndices = NULL;
  int lenValues;
  int lenIndices;
  int result;
  myValues  = (PyArrayObject *)
    PyArray_ContiguousFromObject(values,PyArray_DOUBLE,0,0);
  if (!myValues) goto fail;
  myIndices = (PyArrayObject *)
    PyArray_ContiguousFromObject(indices,PyArray_INT,0,0);
  if (!myIndices) goto fail;
  lenValues  = (int) PyArray_MultiplyList(myValues->dimensions,  myValues->nd );
  lenIndices = (int) PyArray_MultiplyList(myIndices->dimensions, myIndices->nd);
  if (lenValues != lenIndices)
  {
    PyErr_Format(PyExc_ValueError,
		 "Sequence lengths are %d and %d, but must be of same length",
		 lenValues, lenIndices);
    goto fail;
  }
  result = Epetra_Vector::SumIntoMyValues(lenValues, blockOffset,
					  (double *) myValues->data,
					  (int    *) myIndices->data);
  Py_DECREF(myValues );
  Py_DECREF(myIndices);
  return result;
 fail:
  Py_XDECREF(myValues );
  Py_XDECREF(myIndices);
  return -1;
}

}  // Namespace PyTrilinos
namespace PyTrilinos
{

// Static variables
const Epetra_SerialComm   Epetra_NumPyMultiVector::defaultComm = Epetra_SerialComm();
PyArrayObject           * Epetra_NumPyMultiVector::tmp_array   = NULL               ;
Epetra_Map              * Epetra_NumPyMultiVector::tmp_map     = NULL               ;
PyArrayObject           * Epetra_NumPyMultiVector::tmp_range   = NULL               ;

// Static helper functions
// =============================================================================
double * Epetra_NumPyMultiVector::getArray(PyObject * pyObject)
{
  // Try to build a contiguous PyArrayObject from the pyObject
  if (!tmp_array)
    tmp_array = (PyArrayObject *)
      PyArray_ContiguousFromObject(pyObject,NPY_DOUBLE,0,0);
  
  // If this fails, clean up and throw a PythonException
  if (!tmp_array)
  {
    cleanup();
    throw PythonException();
  }
  // If the contiguous PyArrayObject built successfully, make sure it has the correct
  // number of dimensions
  else
  {
    if (PyArray_NDIM(tmp_array) < 2)
    {
      PyObject * tuple = Py_BuildValue("(ii)",1,-1);
      tmp_array = (PyArrayObject *) PyArray_Reshape(tmp_array,tuple);
      Py_DECREF(tuple);
    }
  }

  return (double *) (PyArray_DATA(tmp_array));
}

// =============================================================================
double * Epetra_NumPyMultiVector::getArray(const Epetra_BlockMap & blockMap,
					   PyObject * pyObject)
{
  // PyObject argument is an int
  if (PyInt_Check(pyObject))
  {
    int numVectors = (int) PyInt_AsLong(pyObject);
    npy_intp dimensions[ ] = { numVectors, blockMap.NumMyPoints() };
    tmp_array = (PyArrayObject *)
      PyArray_SimpleNew(2,dimensions,NPY_DOUBLE);
    if (!tmp_array)
    {
      cleanup();
      throw PythonException();
    }

  // PyObject argument is not an int ... try to build a contiguous PyArrayObject from it
  }
  else
  {
    if (!tmp_array)
      tmp_array = (PyArrayObject *)
	PyArray_ContiguousFromObject(pyObject,NPY_DOUBLE,0,0);

    // If this fails, clean up and throw a PythonException
    if (!tmp_array)
    {
      cleanup();
      throw PythonException();
    }
    // If the contiguous PyArrayObject built successfully, make sure it has the correct
    // number of dimensions
    else
    {
      int nd = PyArray_NDIM(tmp_array);
      npy_intp dimensions[ ] = { 1, blockMap.NumMyPoints() };  // Default dimensions
      bool reallocate = false;
      npy_intp arraySize = PyArray_MultiplyList(PyArray_DIMS(tmp_array),nd);

      if (nd < 2)
      {
	reallocate = true;
      }
      else
      {
	arraySize /= PyArray_DIMS(tmp_array)[0];
	if (arraySize != dimensions[1])
	{
	  dimensions[0] = PyArray_DIMS(tmp_array)[0];
	  reallocate = true;
	}
      }

      // Reallocate the tmp_array if necessary
      if (reallocate)
      {
	PyArrayObject * myArray = (PyArrayObject *)
	  PyArray_SimpleNew(2,dimensions,NPY_DOUBLE);
	if (!myArray)
	{
	  cleanup();
	  throw PythonException();
	}
	double        * myData  = (double *) PyArray_DATA(myArray);
	double        * tmpData = (double *) PyArray_DATA(tmp_array);
	for (int i=0; i<dimensions[0]; i++)
	{
	  for (int j=0; j<arraySize && j<dimensions[1]; j++)
	  {
	    myData[i*dimensions[1]+j] = tmpData[i*arraySize+j];
	  }
	}
	Py_XDECREF(tmp_array);
	tmp_array = myArray;
      }
    }
  }
  return (double *) (PyArray_DATA(tmp_array));
}

// =============================================================================
Epetra_Map & Epetra_NumPyMultiVector::getMap(PyObject * pyObject)
{
  if (!tmp_array) getArray(pyObject);
  if (!tmp_map)
  {
    const int totalLength = PyArray_Size((PyObject *)tmp_array);
    const int numVectors  = PyArray_DIMS(tmp_array)[0];
    tmp_map = new Epetra_Map(totalLength/numVectors,0,defaultComm);
  }
  return *tmp_map;
}

// =============================================================================
int Epetra_NumPyMultiVector::getNumVectors(PyObject * pyObject)
{
  if (!tmp_array) getArray(pyObject);
  return PyArray_DIMS(tmp_array)[0];
}

// =============================================================================
int Epetra_NumPyMultiVector::getNumVectors(const Epetra_BlockMap & blockMap,
					   PyObject * pyObject)
{
  if (!tmp_array) getArray(blockMap,pyObject);
  return PyArray_DIMS(tmp_array)[0];
}

// =============================================================================
int Epetra_NumPyMultiVector::getVectorSize(PyObject * pyObject)
{
  if (!tmp_map) getMap(pyObject);
  return tmp_map->NumMyPoints();
}

// =============================================================================
int * Epetra_NumPyMultiVector::getRange(PyObject * range,
					const Epetra_MultiVector & source)
{
  // Handle the default case (range == NULL), which is to return a
  // range of all the Epetra_MultiVector vectors
  if (range == NULL)
  {
    npy_intp dims[ ] = { (npy_intp) source.NumVectors() };
    tmp_range = (PyArrayObject *) PyArray_SimpleNew(1,dims,NPY_INT);
    if (!tmp_range)
    {
      cleanup();
      throw PythonException();
    }
    int * data = (int *) PyArray_DATA(tmp_range);
    for (int i=0; i<dims[0]; i++) data[i] = i;
  }

  // Try to create a contiguous array of integers from the PyObject
  if (!tmp_range)
    tmp_range = (PyArrayObject *)
      PyArray_ContiguousFromObject(range,NPY_INT,1,1);

  // If this fails, clean up and throw a PythonException
  if (!tmp_range)
  {
    cleanup();
    throw PythonException();
  }

  // Obtain the length and return the array of integers
  return (int *) (PyArray_DATA(tmp_range));
}

// =============================================================================
int Epetra_NumPyMultiVector::getRangeLen(PyObject * range,
					 const Epetra_MultiVector & source)
{
  if (!tmp_range) getRange(range, source);
  return PyArray_Size((PyObject*)tmp_range);
}

// =============================================================================
void Epetra_NumPyMultiVector::cleanup()
{
  if (tmp_array)
  {
    Py_DECREF(tmp_array);
    tmp_array = NULL;
  }
  if (tmp_map)
  {
    delete tmp_map;
    tmp_map = NULL;
  }
  if (tmp_range)
  {
    Py_DECREF(tmp_range);
    tmp_range = NULL;
  }
}

// =============================================================================

// Constructors
// =============================================================================
Epetra_NumPyMultiVector::Epetra_NumPyMultiVector(const Epetra_BlockMap & blockMap,
						 int numVectors, bool zeroOut):
  Epetra_MultiVector(blockMap, numVectors, zeroOut)
{
  // Create the array object
  npy_intp dims[ ] = { numVectors, blockMap.NumMyPoints() };
  double **v = NULL;
  Epetra_MultiVector::ExtractView(&v);
  array = (PyArrayObject *) PyArray_SimpleNewFromData(2,dims,NPY_DOUBLE,
						      (void *)v[0]);
  if (!array)
  {
    cleanup();
    throw PythonException();
  }
  // Copy the Epetra_BlockMap
  map = new Epetra_BlockMap(blockMap);
}

// =============================================================================
Epetra_NumPyMultiVector::Epetra_NumPyMultiVector(const Epetra_MultiVector & source):
  Epetra_MultiVector(source)
{
  map = new Epetra_BlockMap(source.Map());
  npy_intp dims[ ] = { NumVectors(), map->NumMyPoints() };
  double **v = NULL;
  Epetra_MultiVector::ExtractView(&v);
  array = (PyArrayObject *) PyArray_SimpleNewFromData(2,dims,NPY_DOUBLE,
						      (void *)v[0]);
  if (!array)
  {
    cleanup();
    throw PythonException();
  }
}

// =============================================================================
Epetra_NumPyMultiVector::Epetra_NumPyMultiVector(const Epetra_BlockMap & blockMap,
						 PyObject * pyObject):
  Epetra_MultiVector(View, blockMap, getArray(blockMap,pyObject),
		     blockMap.NumMyPoints(), getNumVectors(blockMap,pyObject))
{
  // Store the array pointer
  array     = tmp_array;
  tmp_array = NULL;

  // Copy the Epetra_BlockMap
  map = new Epetra_BlockMap(blockMap);
}

// =============================================================================
Epetra_NumPyMultiVector::Epetra_NumPyMultiVector(Epetra_DataAccess CV,
						 const Epetra_NumPyMultiVector & source,
						 PyObject * range):
  Epetra_MultiVector(CV, (const Epetra_MultiVector &) source,
		     getRange(   range, (const Epetra_MultiVector) source),
		     getRangeLen(range, (const Epetra_MultiVector) source))
{
  // Store the Epetra_NumPyMultiVector's map
  map = new Epetra_BlockMap(source.Map());

  // Inintialize the local numpy array
  PyArrayObject * src_array = (PyArrayObject *) (source.ExtractView());
  int nd;
  // This shouldn't happen, but it does . . .
  if (NULL == src_array) nd = 2;
  else nd = PyArray_NDIM(src_array);
  npy_intp * dims = new npy_intp[nd];
  dims[0] = NumVectors();
  if (NULL == src_array) dims[1] = source.MyLength();
  else for (int i=1; i<nd; i++) dims[i] = PyArray_DIMS(src_array)[i];

  double **v = NULL;
  Epetra_MultiVector::ExtractView(&v);
  array = (PyArrayObject *) PyArray_SimpleNewFromData(nd,dims,NPY_DOUBLE,
						      (void *)v[0]);
  delete [] dims;
  if (!array)
  {
    cleanup();
    throw PythonException();
  }

  // We're done with the tmp_range array
  Py_XDECREF(tmp_range);
  tmp_range = NULL;
}

// =============================================================================
Epetra_NumPyMultiVector::Epetra_NumPyMultiVector(Epetra_DataAccess CV,
						 const Epetra_MultiVector & source,
						 PyObject * range):
  Epetra_MultiVector(CV, source, getRange(range, source), getRangeLen(range, source))
{
  // Store the local map
  map = new Epetra_BlockMap(source.Map());

  // Wrap the Epetra_MultiVector
  npy_intp dims[ ] = { NumVectors(), MyLength() };
  double **v  = NULL;
  Epetra_MultiVector::ExtractView(&v);
  array = (PyArrayObject *) PyArray_SimpleNewFromData(2,dims,NPY_DOUBLE,
						      (void *)v[0]);
  if (!array)
  {
    cleanup();
    throw PythonException();
  }

  // We're done with the tmp_range array
  Py_XDECREF(tmp_range);
  tmp_range = NULL;
}

// =============================================================================
Epetra_NumPyMultiVector::Epetra_NumPyMultiVector(PyObject * pyObject):
  Epetra_MultiVector(View, getMap(pyObject), getArray(pyObject),
		     getVectorSize(pyObject), getNumVectors(pyObject))
{
  // Store the pointer to the Epetra_Map
  map     = tmp_map;
  tmp_map = NULL;

  // Store the pointer to the PyArrayObject
  array     = tmp_array;
  tmp_array = NULL;
}

// =============================================================================
// Destructor
Epetra_NumPyMultiVector::~Epetra_NumPyMultiVector()
{
  Py_XDECREF(array);
  delete map;
}

// =============================================================================
PyObject * Epetra_NumPyMultiVector::ExtractCopy() const
{
  return PyArray_NewCopy(array,NPY_ANYORDER);
}

// =============================================================================
PyObject * Epetra_NumPyMultiVector::ExtractView() const
{
  Py_INCREF(array);
  return PyArray_Return(array);
}

// =============================================================================
PyObject * Epetra_NumPyMultiVector::Dot(const Epetra_MultiVector & a) const
{
  int n = NumVectors();
  double * result = new double[n];
  npy_intp numVectors[ ] = {n};
  PyObject * po;
  double * data;

  int status = Epetra_MultiVector::Dot(a, result);

  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "Dot returned error code %d", status);
    goto fail;
  }
  po = PyArray_SimpleNew(1, numVectors, NPY_DOUBLE);
  data = (double*) PyArray_DATA(((PyArrayObject*)po));
  for (int i=0; i<n; i++) data[i] = result[i];
  delete [] result;
  return PyArray_Return((PyArrayObject*)po);
 fail:
  delete [] result;
  return NULL;
}

// =============================================================================
PyObject * Epetra_NumPyMultiVector::Norm1() const
{
  int n = NumVectors();
  double * result = new double[n];
  npy_intp numVectors[ ] = {n};
  PyObject * po;
  double * data;

  int status = Epetra_MultiVector::Norm1(result);

  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "Norm1 returned error code %d", status);
    goto fail;
  }
  po   = PyArray_SimpleNew(1, numVectors, NPY_DOUBLE);
  data = (double*) PyArray_DATA((PyArrayObject*)po);
  for (int i=0; i<n; i++) data[i] = result[i];
  delete [] result;
  return PyArray_Return((PyArrayObject*)po);
 fail:
  delete [] result;
  return NULL;
}

// =============================================================================
PyObject * Epetra_NumPyMultiVector::Norm2() const
{
  int n = NumVectors();
  double * result = new double[n];
  npy_intp numVectors[ ] = {n};
  PyObject * po;
  double * data;

  int status = Epetra_MultiVector::Norm2(result);

  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "Norm2 returned error code %d", status);
    goto fail;
  }
  po   = PyArray_SimpleNew(1, numVectors, NPY_DOUBLE);
  data = (double*) PyArray_DATA((PyArrayObject*)po);
  for (int i=0; i<n; i++) data[i] = result[i];
  delete [] result;
  return PyArray_Return((PyArrayObject*)po);
 fail:
  delete [] result;
  return NULL;
}

// =============================================================================
PyObject * Epetra_NumPyMultiVector::NormInf() const
{
  int n = NumVectors();
  double * result = new double[n];
  npy_intp numVectors[ ] = {n};
  PyObject * po;
  double * data;  

  int status = Epetra_MultiVector::NormInf(result);

  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "NormInf returned error code %d", status);
    goto fail;
  }
  po   = PyArray_SimpleNew(1, numVectors, NPY_DOUBLE);
  data = (double*) PyArray_DATA((PyArrayObject*)po);
  for (int i=0; i<n; i++) data[i] = result[i];
  delete [] result;
  return PyArray_Return((PyArrayObject*)po);
 fail:
  delete [] result;
  return NULL;
}

// =============================================================================
PyObject * Epetra_NumPyMultiVector::
NormWeighted(const Epetra_MultiVector & weights) const
{
  int n = NumVectors();
  double * result = new double[n];
  npy_intp numVectors[ ] = {n};
  PyObject * po;
  double * data;  

  int status = Epetra_MultiVector::NormWeighted(weights,result);

  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "NormWeighted returned error code %d", status);
    goto fail;
  }
  po   = PyArray_SimpleNew(1, numVectors, NPY_DOUBLE);
  data = (double*) PyArray_DATA((PyArrayObject*)po);
  for (int i=0; i<n; i++) data[i] = result[i];
  delete [] result;
  return PyArray_Return((PyArrayObject*)po);
 fail:
  delete [] result;
  return NULL;
}

// =============================================================================
PyObject * Epetra_NumPyMultiVector::MinValue() const
{
  int n = NumVectors();
  double * result = new double[n];
  npy_intp numVectors[ ] = {n};
  PyObject * po;
  double * data;

  int status = Epetra_MultiVector::MinValue(result);

  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "MinValue returned error code %d", status);
    goto fail;
  }
  po   = PyArray_SimpleNew(1, numVectors, NPY_DOUBLE);
  data = (double*) PyArray_DATA((PyArrayObject*)po);
  for (int i=0; i<n; i++) data[i] = result[i];
  delete [] result;
  return PyArray_Return((PyArrayObject*)po);
 fail:
  delete [] result;
  return NULL;
}

// =============================================================================
PyObject * Epetra_NumPyMultiVector::MaxValue() const
{
  int n = NumVectors();
  double * result = new double[n];
  npy_intp numVectors[ ] = {n};
  PyObject * po;
  double * data;

  int status = Epetra_MultiVector::MaxValue(result);

  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "MaxValue returned error code %d", status);
    goto fail;
  }
  po   = PyArray_SimpleNew(1, numVectors, NPY_DOUBLE);
  data = (double*) PyArray_DATA((PyArrayObject*)po);
  for (int i=0; i<n; i++) data[i] = result[i];
  delete [] result;
  return PyArray_Return((PyArrayObject*)po);
 fail:
  delete [] result;
  return NULL;
}

// =============================================================================
PyObject * Epetra_NumPyMultiVector::MeanValue() const
{
  int n = NumVectors();
  double * result = new double[n];
  npy_intp numVectors[ ] = {n};
  PyObject * po;
  double * data;

  int status = Epetra_MultiVector::MeanValue(result);

  if (status)
  {
    PyErr_Format(PyExc_RuntimeError, "MeanValue returned error code %d", status);
    goto fail;
  }
  po = PyArray_SimpleNew(1, numVectors, NPY_DOUBLE);
  data = (double*) PyArray_DATA((PyArrayObject*)po);
  for (int i=0; i<n; i++) data[i] = result[i];
  delete [] result;
  return PyArray_Return((PyArrayObject*)po);
 fail:
  delete [] result;
  return NULL;
}

}  // Namespace PyTrilinos
예제 #3
0
namespace PyTrilinos
{

// Static variables
const Epetra_SerialComm   Epetra_NumPyIntVector::defaultComm = Epetra_SerialComm();
PyArrayObject           * Epetra_NumPyIntVector::tmp_array   = NULL               ;
Epetra_Map              * Epetra_NumPyIntVector::tmp_map     = NULL               ;

// Static helper functions
// =============================================================================
int * Epetra_NumPyIntVector::getArray(PyObject * pyObject)
{
  // Try to build a contiguous PyArrayObject from the pyObject
  if (!tmp_array)
    tmp_array = (PyArrayObject *)
      PyArray_ContiguousFromObject(pyObject,NPY_INT,0,0);
  
  // If this fails, clean up and throw a PythonException
  if (!tmp_array)
  {
    cleanup();
    throw PythonException();
  }
  return (int*)(PyArray_DATA(tmp_array));
}

// =============================================================================
int * Epetra_NumPyIntVector::getArray(const Epetra_BlockMap & blockMap,
				      PyObject * pyObject)
{
  // Only build the tmp_array if it does not already exist
  if (!tmp_array)
  {
    // Default dimensions
    npy_intp defaultDims[ ] = { blockMap.NumMyPoints() };

    // PyObject argument is a bool
    if (PyBool_Check(pyObject))
    {
      tmp_array = (PyArrayObject *)
	PyArray_SimpleNew(1,defaultDims,NPY_INT);
    }
    // PyObject argument is not a bool ... try to build a contiguous
    // PyArrayObject from it
    else
    {
      tmp_array = (PyArrayObject *)
	PyArray_ContiguousFromObject(pyObject,NPY_INT,0,0);
    }
    // If any PyArray factory functions fail, clean up and throw a
    // PythonException
    if (!tmp_array)
    {
      cleanup();
      throw PythonException();
    }
    int  nd = PyArray_NDIM(tmp_array);
    npy_intp arraySize = PyArray_MultiplyList(PyArray_DIMS(tmp_array),nd);
    if (arraySize != defaultDims[0])
    {
      PyArrayObject * myArray = (PyArrayObject *)
	PyArray_SimpleNew(1,defaultDims,NPY_INT);
      if (!myArray)
      {
	cleanup();
	throw PythonException();
      }
      int * myData  = (int *) PyArray_DATA(myArray);
      int * tmpData = (int *) PyArray_DATA(tmp_array);
      for (int i=0; i<defaultDims[0]; i++)
      {
	myData[i] = tmpData[i];
      }
      Py_XDECREF(tmp_array);
      tmp_array = myArray;
    }
  }
  return (int*)(PyArray_DATA(tmp_array));
}

// =============================================================================
Epetra_Map & Epetra_NumPyIntVector::getMap(PyObject * pyObject)
{
  if (!tmp_array) getArray(pyObject);
  if (!tmp_map)
  {
    const int totalLength = PyArray_Size((PyObject *)tmp_array);
    tmp_map = new Epetra_Map(totalLength,0,defaultComm);
  }
  return *tmp_map;
}

// =============================================================================
void Epetra_NumPyIntVector::cleanup()
{
  if (tmp_array)
  {
    Py_DECREF(tmp_array);
    tmp_array = NULL;
  }
  if (tmp_map)
  {
    delete tmp_map;
    tmp_map = NULL;
  }
}

// =============================================================================

// Constructors
// =============================================================================
Epetra_NumPyIntVector::Epetra_NumPyIntVector(const Epetra_BlockMap & blockMap,
					     bool zeroOut):
  Epetra_IntVector(blockMap, zeroOut)
{
  // Create the array object
  npy_intp dims[ ] = { blockMap.NumMyPoints() };
  int *v = NULL;
  Epetra_IntVector::ExtractView(&v);
  array = (PyArrayObject *)
    PyArray_SimpleNewFromData(1,dims,NPY_INT,(void *)v);
  if (!array)
  {
    cleanup();
    throw PythonException();
  }
  // Copy the Epetra_BlockMap
  map = new Epetra_BlockMap(blockMap);
}

// =============================================================================
Epetra_NumPyIntVector::Epetra_NumPyIntVector(const Epetra_IntVector & source):
  Epetra_IntVector(source)
{
  map = new Epetra_BlockMap(source.Map());
  npy_intp dims[ ] = { map->NumMyPoints() };
  int *v = NULL;
  Epetra_IntVector::ExtractView(&v);
  array = (PyArrayObject *)
    PyArray_SimpleNewFromData(1,dims,NPY_INT,(void *)v);
  if (!array)
  {
    cleanup();
    throw PythonException();
  }
}

// =============================================================================
Epetra_NumPyIntVector::Epetra_NumPyIntVector(const Epetra_BlockMap & blockMap,
					     PyObject * pyObject):
  Epetra_IntVector(View, blockMap, getArray(blockMap,pyObject))
{
  // Get the pointer to the array from static variable and clear
  assert(NULL != tmp_array);
  array     = tmp_array;
  tmp_array = NULL;

  // Copy the Epetra_BlockMap
  map = new Epetra_BlockMap(blockMap);
}

// =============================================================================
Epetra_NumPyIntVector::Epetra_NumPyIntVector(PyObject * pyObject):
  Epetra_IntVector(View, getMap(pyObject), getArray(pyObject)) 
{
  // Store the pointer to the Epetra_Map
  assert(NULL != tmp_map);
  map     = tmp_map;
  tmp_map = NULL;

  // Store the pointer to the PyArrayObject
  assert(NULL != tmp_array);
  array     = tmp_array;
  tmp_array = NULL;
}

// =============================================================================
// Destructor
Epetra_NumPyIntVector::~Epetra_NumPyIntVector()
{
  Py_XDECREF(array);
  delete map;
}

// =============================================================================
PyObject * Epetra_NumPyIntVector::ExtractCopy() const
{
  return PyArray_NewCopy(array,NPY_ANYORDER);
}

// =============================================================================
PyObject * Epetra_NumPyIntVector::ExtractView() const
{
  Py_INCREF(array);
  return PyArray_Return(array);
}

// =============================================================================
PyObject * Epetra_NumPyIntVector::Values() const
{
  Py_INCREF(array);
  return PyArray_Return(array);
}

}  // Namepace PyTrilinos