{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "PyCA Tutorial\n", "=============\n", "\n", "The main focus of PyCA is to provide data types (for images and vector fields) and corresponding C++/CUDA operations. We import the Core module as follows:\n", "\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import PyCA.Core as ca" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 12 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Image3D and Field3D datatypes\n", "---------------------------------\n", "\n", "The main data types in PyCA are Image3D's and Field3D's, objects that represent a block of memory containing floats. Each Image3D/Field3D is described by two attributes: its `grid` and `memType`.\n", "For its grid, we declare a GridInfo object that describes a grid with the grid's size, spacing and origin. By default the spacing is (1,1,1) and the origin is (0,0,0). We declare these objects using other data types: Vec3Di and Vec3Df (integer and float 3D vectors).\n", "For an object's memory type, there are two options: `MEM_HOST` and `MEM_DEVICE` for CPU and GPU memory. Since it is common to use the default spacing and origin, there is a simplified constructor which takes the x,y,z dimensions and memType directly (see declaration of `Im2` below)." ] }, { "cell_type": "code", "collapsed": true, "input": [ "grid = ca.GridInfo(ca.Vec3Di(20, 20, 20), ca.Vec3Df(1.0, 1.0, 1.0), ca.Vec3Df(0.0, 0.0, 0.0))\n", "grid = ca.GridInfo(ca.Vec3Di(20, 20, 20)) #equivalent\n", "memType = ca.MEM_DEVICE #for GPU Memory\n", "\n", "Im1 = ca.Image3D(grid, memType)\n", "Im2 = ca.Image3D(20, 20, 20, memType) # also equivalent\n", "print Im1\n", "print Im2\n", "\n", "VF1 = ca.Field3D(Im1.grid(), Im1.memType())\n", "VF2 = ca.Field3D(20, 20, 20, Im1.memType()) # again, also equivalent\n", "print VF1\n" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Image3D: size (20, 20, 20) origin (0 0 0) spacing (1 1 1) MemType: MEM_DEVICE\n", "Image3D: size (20, 20, 20) origin (0 0 0) spacing (1 1 1) MemType: MEM_DEVICE\n", "Field3D: size (20, 20, 20) origin (0 0 0) spacing (1 1 1) MemType: MEM_DEVICE\n" ] } ], "prompt_number": 13 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also change the grid and memType of current Image3D's/Field3D's, provided that we don't make the grid larger than the current pre-allocated memory." ] }, { "cell_type": "code", "collapsed": false, "input": [ "grid2 = ca.GridInfo(ca.Vec3Di(20, 20, 20), ca.Vec3Df(.5, .5, .5), ca.Vec3Df(-19.0, -19.0, -19.0))\n", "memTypeCPU = ca.MEM_HOST\n", "\n", "Im1.setGrid(grid2)\n", "Im1.toType(memTypeCPU)\n", "print Im1\n", "Im1.setGrid(grid) #Change back\n", "Im1.toType(ca.MEM_DEVICE)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Image3D: size (20, 20, 20) origin (-19 -19 -19) spacing (0.5 0.5 0.5) MemType: MEM_HOST\n" ] } ], "prompt_number": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Working with 2D Images and Fields\n", "Although our data types are called Image3D's and Field3D's, it is trivial to work with 2D Images. In PyCA, a 2D image is an Image3D with size (M x N x 1), and likewise for a 2D Field - and everything will work as expected." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Setting Image3D and Field3D Memory Values\n", "Currently, our Image3D and Field3D are just allocated memory and don't contain any meaningful data. We can set their values as follows" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ca.SetMem(Im1, 1.0) #for an Image of all ones\n", "ca.SetMem(VF1, ca.Vec3Df(1.0, 2.0, 3.0)) #For a Field that is (1, 2, 3) everywhere\n", "\n", "ca.SetToZero(VF1) # V Field where each element is (0, 0, 0)\n", "ca.SetToIdentity(VF1) # H Field where each element (x, y, z)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 15 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another common way to set the data is to copy it from a previously defined Image3D or Field3D, and in fact, we can copy between an Image3D and a Field3D provided we give the correct index (x=0, y=1, z=2)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ca.SetMem(Im1, 4.0)\n", "ca.Copy(Im2, Im1) # element-wise copy, Im2 = Im1\n", "ca.Copy(VF1, Im2, 1) #copy into the y field: VF1[:,:,:,1] = Im2\n", "ca.Copy(Im2, VF1, 2) #copy from the y field:" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 16 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interacting with Numpy\n", "\n", "We can transfer memory contents between an Image3D/Field3D and a Numpy array:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using the *FromNpArr functions\n", "The functions ImFromNPArr and FieldFromNPArr each take a Numpy array and copy it into a Image3D/Field3D. This is the easiest way to interact with Numpy arrays, but it is also the slowest." ] }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy as np\n", "import PyCA.Common as common\n", "\n", "np_arr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) #create sample 3x3 numpy array\n", "Im2 = common.ImFromNPArr(np_arr, ca.MEM_DEVICE) #create Image3D from the numpy array\n", "print Im2.grid()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Grid: size (3, 3, 1) origin (0 0 0) spacing (1 1 1)\n" ] } ], "prompt_number": 17 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that here a 2D array was numpy array was given and was turned into an Image3D with size (3, 3, 1). ImFromNPArr expects either a MxN numpy array or an MxNxK numpy array. Also notice that the spacing and origin of the grid were set by default to (1, 1, 1) and (0, 0, 0). We can do a similar thing with a Field3D. FieldFromNpArr expects either a MxNx2 numpy array or a MxNxKx3 numpy array." ] }, { "cell_type": "code", "collapsed": false, "input": [ "np_arr_2D = np.zeros((20, 20, 2))\n", "VF_2D = common.FieldFromNPArr(np_arr_2D, ca.MEM_DEVICE)\n", "print VF_2D.grid()\n", "\n", "np_arr_3D = np.zeros((20, 20, 20, 3))\n", "VF_3D = common.FieldFromNPArr(np_arr_3D, ca.MEM_DEVICE)\n", "print VF_3D.grid()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Grid: size (20, 20, 1) origin (0 0 0) spacing (1 1 1)\n", "Grid: size (20, 20, 20) origin (0 0 0) spacing (1 1 1)\n" ] } ], "prompt_number": 18 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Converting to numpy array with AsNPCopy\n", "Of course, you can go the other way too, from an Image3D/Field3D to a numpy array, via the AsNPCopy function:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np_arr2 = common.AsNPCopy(Im2)\n", "print 'Image3D as numpy array:\\n', np_arr2\n", "np_vf2D = common.AsNPCopy(VF_2D)\n", "print 'Field3D as numpy array shape:', np_vf2D.shape" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Image3D as numpy array:\n", "[[[ 1.]\n", " [ 2.]\n", " [ 3.]]\n", "\n", " [[ 4.]\n", " [ 5.]\n", " [ 6.]]\n", "\n", " [[ 7.]\n", " [ 8.]\n", " [ 9.]]]\n", "Field3D as numpy array shape: (20, 20, 1, 3)\n" ] } ], "prompt_number": 24 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that these always return 3D (for images) or 4D (for fields) numpy arrays. If you are working with 2D images and fields, you will probably want to `squeeze` these. In addition, Field3Ds always represent 3D vectors, so if you are working in 2D, the final entry is probably of no interest and can be dropped." ] }, { "cell_type": "code", "collapsed": false, "input": [ "np_arr2 = np.squeeze(common.AsNPCopy(Im2))\n", "print 'Image3D as numpy array:\\n', np_arr2\n", "np_vf2D = np.squeeze(common.AsNPCopy(VF_2D))[:,:,:2]\n", "print 'Field3D as numpy array shape:', np_vf2D.shape" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Image3D as numpy array:\n", "[[ 1. 2. 3.]\n", " [ 4. 5. 6.]\n", " [ 7. 8. 9.]]\n", "Field3D as numpy array shape: (20, 20, 2)\n" ] } ], "prompt_number": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using the .asnp() member function\n", "The \\*FromNpArr functions are inherently slow. However, since Image3D's and Field3D's are blocks of memory (much like Numpy arrays), we can interact with Image3D's as numpy arrays using the .asnp() member function. However, since Numpy arrays only exist on host memory, the Image3D/Field3D is required to have memType of MEM_HOST. Also, the numpy array returned by `asnp()` does not own the memory block, so if the original `Image3D`\\\\`Field3D` goes out of scope and is deleted, the numpy array will point to invalid memory and can cause crashes. This function can increase speed, but use with **extreme caution**." ] }, { "cell_type": "code", "collapsed": false, "input": [ "Im = ca.Image3D(ca.GridInfo(ca.Vec3Di(4, 4, 1)), ca.MEM_HOST)\n", "ca.SetMem(Im, 0.0)\n", "Imnp = Im.asnp()\n", "# now we can treat Imnp like we would any numpy array\n", "Imnp[1:3, 1:3, :] = 5.0\n", "print Im\n", "print np.squeeze(Imnp)\n", "print type(Imnp)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Image3D: size (4, 4, 1) origin (0 0 0) spacing (1 1 1) MemType: MEM_HOST\n", "[[ 0. 0. 0. 0.]\n", " [ 0. 5. 5. 0.]\n", " [ 0. 5. 5. 0.]\n", " [ 0. 0. 0. 0.]]\n", "\n" ] } ], "prompt_number": 19 }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this code, `Im` and `Imnp` represent the same block of memory, so changing the contents of `Imnp` also changes the contents of `Im`. However, we can treat `Imnp` in the same way as any Numpy array, and supports Numpy array operatins (such as indexing, etc.). We can also copy the memory over using Numpy's copy function" ] }, { "cell_type": "code", "collapsed": false, "input": [ "Imnp2 = Im.asnp().copy()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 20 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This method is still much quicker than using the \\*FromNpArr functions" ] } ], "metadata": {} } ] }