From fbb36921f68ee76aba4923c13be7d84f3be568e0 Mon Sep 17 00:00:00 2001 From: Tanner Hobson Date: Fri, 8 Sep 2017 15:29:01 -0400 Subject: [PATCH 1/4] Add initial prototype of wrapper module --- Dockerfile | 91 +++++++++++ python/pbnjmodule.cpp | 348 ++++++++++++++++++++++++++++++++++++++++++ setup.py | 43 ++++++ 3 files changed, 482 insertions(+) create mode 100644 Dockerfile create mode 100644 python/pbnjmodule.cpp create mode 100644 setup.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ebc7e33 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,91 @@ +FROM ubuntu:latest +MAINTAINER Tanner Hobson + +RUN apt-get update && \ + apt-get install -y \ + build-essential $(: all : compile tool) \ + cmake $(: all : compile tool) \ + python $(: pistache : running tests) \ + libtbb-dev $(: embree ospray : threading framework) \ + libglu1-mesa-dev $(: embree ospray : OpenGL requirements) \ + freeglut3-dev $(: embree ospray : OpenGL requirements) \ + mesa-common-dev $(: embree ospray : OpenGL requirements) \ + libc6-dev $(: enchiladas : pthreads) \ + && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /opt/ +COPY rapidjson /opt/rapidjson +WORKDIR /opt/rapidjson/build/ +RUN true && \ + cmake .. \ + -DRAPIDJSON_BUILD_EXAMPLES:BOOL=OFF \ + -DRAPIDJSON_BUILD_TESTS:BOOL=OFF \ + && \ + make && \ + make install + +WORKDIR /opt/ +ADD ispc-v1.9.1-linux.tar.gz /opt/ +RUN mv ispc-v1.9.1-linux ispc +WORKDIR /opt/ispc/ +RUN update-alternatives --install /usr/bin/ispc ispc /opt/ispc/ispc 1 + +WORKDIR /opt/ +ADD embree-2.16.4.x86_64.linux.tar.gz /opt/ +RUN mv embree-2.16.4.x86_64.linux embree +WORKDIR /opt/embree/ + +WORKDIR /opt/ +COPY ospray /opt/ospray +WORKDIR /opt/ospray/build +RUN true && \ + cmake .. \ + -Dembree_DIR=/opt/embree \ + -DOSPRAY_ENABLE_APPS:BOOL=OFF \ + -DOSPRAY_TASKING_SYSTEM=OpenMP \ + && \ + make && \ + make install + +RUN apt-get update && \ + apt-get install -y \ + python3-dev \ + && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /opt/pbnj/ +COPY cmake ./cmake +COPY include ./include +COPY src ./src +COPY CMakeLists.txt ./CMakeLists.txt +WORKDIR /opt/pbnj/build +RUN true && \ + cmake .. \ + -DUSE_NETCDF:BOOL=OFF \ + -DBUILD_EXAMPLES:BOOL=OFF \ + -Dembree_DIR=/opt/embree \ + && \ + make && \ + make install + +RUN apt-get update && \ + apt-get install -y \ + python3-pip \ + && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /opt/pbnj/ +COPY python ./python +COPY setup.py ./setup.py +WORKDIR /opt/pbnj/ +RUN true && \ + python3 -m pip install virtualenv && \ + python3 -m virtualenv -p python3 venv + +RUN true && \ + env LD_RUN_PATH=/usr/local/lib:/opt/embree/lib venv/bin/pip install --verbose . +COPY test.py ./test.py +RUN true && \ + venv/bin/python3 test.py && \ + false diff --git a/python/pbnjmodule.cpp b/python/pbnjmodule.cpp new file mode 100644 index 0000000..f64d1f7 --- /dev/null +++ b/python/pbnjmodule.cpp @@ -0,0 +1,348 @@ +#include +#include +#include "pbnj.h" +#include "Configuration.h" +#include "Camera.h" + +extern "C" { + +/******************************************************************************* + * START pbnj.Configuration + ******************************************************************************/ + +typedef struct { + PyObject_HEAD + pbnj::Configuration *object; +} Configuration; + + +static void +Configuration_dealloc(Configuration *self) { + delete self->object; + self->object = NULL; +} + + +static PyObject * +Configuration_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + Configuration *self; + + self = (Configuration *)type->tp_alloc(type, 0); + if (self != NULL) { + self->object = NULL; + } + + return (PyObject *)self; +} + + +static int +Configuration_init(Configuration *self, PyObject *args) { + const char *filename; + + if (!PyArg_ParseTuple(args, "s", &filename)) { + return -1; + } + + self->object = new pbnj::Configuration(std::string(filename)); + + return 0; +} + +static char *ConfigurationDoc = NULL; + + +static PyTypeObject ConfigurationType = { + PyVarObject_HEAD_INIT(NULL, 0) + "_pbnj.Configuration", /* tp_name */ + sizeof(Configuration), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Configuration_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + ConfigurationDoc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Configuration_init, /* tp_init */ + 0, /* tp_alloc */ + Configuration_new, /* tp_new */ +}; + + +static PyObject * +Configuration_get_image_width(PyObject *self, PyObject *args) { + Configuration *config; + + if (!PyArg_ParseTuple(args, "O!", &ConfigurationType, &config)) { + return NULL; + } + + return PyLong_FromLong((long)config->object->imageWidth); +} + + +static PyMethodDef Configuration_get_image_width_method = { + "Configuration_get_image_width", + (PyCFunction)Configuration_get_image_width, + METH_VARARGS, + "Configuration_get_image_width documentation", +}; + + +static PyObject * +Configuration_get_image_height(PyObject *self, PyObject *args) { + Configuration *config; + + if (!PyArg_ParseTuple(args, "O!", &ConfigurationType, &config)) { + return NULL; + } + + return PyLong_FromLong((long)config->object->imageHeight); +} + + +static PyMethodDef Configuration_get_image_height_method = { + "Configuration_get_image_height", + (PyCFunction)Configuration_get_image_height, + METH_VARARGS, + "Configuration_get_image_height documentation", +}; + + +/******************************************************************************* + * END pbnj.Configuration + ******************************************************************************/ + +/******************************************************************************* + * START pbnj.Camera + ******************************************************************************/ + +typedef struct { + PyObject_HEAD + pbnj::Camera *object; +} Camera; + + +static void +Camera_dealloc(Camera *self) { + delete self->object; + self->object = NULL; +} + + +static PyObject * +Camera_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + Camera *self; + + self = (Camera *)type->tp_alloc(type, 0); + if (self != NULL) { + self->object = NULL; + } + + return (PyObject *)self; +} + + +static int +Camera_init(Camera *self, PyObject *args) { + int width, height; + + if (!PyArg_ParseTuple(args, "ii", &width, &height)) { + return -1; + } + + self->object = new pbnj::Camera(width, height); + + return 0; +} + + +static char *CameraDoc = NULL; + + +static PyTypeObject CameraType = { + PyVarObject_HEAD_INIT(NULL, 0) + "_pbnj.Camera", /* tp_name */ + sizeof(Camera), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)Camera_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + CameraDoc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Camera_init, /* tp_init */ + 0, /* tp_alloc */ + Camera_new, /* tp_new */ +}; + + +static PyObject * +Camera_get_image_width(PyObject *self, PyObject *args) { + Camera *camera; + + if (!PyArg_ParseTuple(args, "O!", &CameraType, &camera)) { + return NULL; + } + + return PyLong_FromLong((long)camera->object->imageWidth); +} + + +static PyMethodDef Camera_get_image_width_method = { + "Camera_get_image_width", + (PyCFunction)Camera_get_image_width, + METH_VARARGS, + "Camera_get_image_width documentation", +}; + + +static PyObject * +Camera_get_image_height(PyObject *self, PyObject *args) { + Camera *camera; + + if (!PyArg_ParseTuple(args, "O!", &CameraType, &camera)) { + return NULL; + } + + return PyLong_FromLong((long)camera->object->imageHeight); +} + + +static PyMethodDef Camera_get_image_height_method = { + "Camera_get_image_height", + (PyCFunction)Camera_get_image_height, + METH_VARARGS, + "Camera_get_image_height documentation", +}; + + +/******************************************************************************* + * END pbnj.Camera + ******************************************************************************/ + +/******************************************************************************* + * START pbnj + ******************************************************************************/ + +static PyObject * +pbnj_init(PyObject *self) { + int argc; + const char *argv[1]; + const std::string dummy = "dummy"; + + argc = 1; + argv[0] = dummy.c_str(); + + pbnj::pbnjInit(&argc, argv); + + Py_RETURN_NONE; +} + + +static PyMethodDef pbnj_init_method = { + "init", + (PyCFunction)pbnj_init, + METH_NOARGS, + "Initialize the PBNJ subsystem.", +}; + + +static PyMethodDef PbnjMethods[] = { + Configuration_get_image_width_method, + Configuration_get_image_height_method, + Camera_get_image_width_method, + Camera_get_image_height_method, + pbnj_init_method, + {NULL, NULL, 0, NULL}, +}; + + +static char *pbnj_doc = NULL; + + +static struct PyModuleDef pbnjmodule = { + PyModuleDef_HEAD_INIT, + "_pbnj", + pbnj_doc, + -1, /* module keeps state in global variables */ + PbnjMethods, +}; + + +PyMODINIT_FUNC +PyInit__pbnj(void) { + PyObject *m; + + ConfigurationType.tp_new = PyType_GenericNew; + if (PyType_Ready(&ConfigurationType) < 0) + return NULL; + + CameraType.tp_new = PyType_GenericNew; + if (PyType_Ready(&CameraType) < 0) + return NULL; + + m = PyModule_Create(&pbnjmodule); + if (m == NULL) + return NULL; + + Py_INCREF(&ConfigurationType); + PyModule_AddObject(m, "Configuration", (PyObject *)&ConfigurationType); + + Py_INCREF(&CameraType); + PyModule_AddObject(m, "Camera", (PyObject *)&CameraType); + + return m; +} + +} /* extern "C" */ diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..49ec099 --- /dev/null +++ b/setup.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +""" + +""" + +from distutils.core import setup, Extension + + +_pbnj = Extension( + '_pbnj', + language='c++', + libraries=[ + 'pbnj', + ], + sources=[ + 'python/pbnjmodule.cpp', + ], +) + + +setup( + name='pbnj', + version='0.0.1', + description='PBNJ', + author='Tanner Hobson', + author_email='thobson2@vols.utk.edu', + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Intended Audience :: Developers', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.6', + ], + packages=[ + ], + python_requires='>=3.5', + install_requires=[ + ], + entry_points={ + }, + ext_modules=[ + _pbnj, + ], +) From 908928e1e4e51f6ee41d36a4514e00fbb3b7e1aa Mon Sep 17 00:00:00 2001 From: Tanner Hobson Date: Sat, 14 Oct 2017 09:56:35 -0400 Subject: [PATCH 2/4] Switch to using SWIG for Python module generation --- Dockerfile | 82 ++++++++-- pbnj.i | 208 +++++++++++++++++++++++++ python/pbnjmodule.cpp | 348 ------------------------------------------ setup.py | 5 +- 4 files changed, 278 insertions(+), 365 deletions(-) create mode 100644 pbnj.i delete mode 100644 python/pbnjmodule.cpp diff --git a/Dockerfile b/Dockerfile index ebc7e33..3fc096f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,28 @@ -FROM ubuntu:latest -MAINTAINER Tanner Hobson +FROM ubuntu:latest AS rapidjson RUN apt-get update && \ apt-get install -y \ - build-essential $(: all : compile tool) \ + # build-essential $(: all : compile tool) \ + # Compilation tool for C/C++ programs cmake $(: all : compile tool) \ - python $(: pistache : running tests) \ - libtbb-dev $(: embree ospray : threading framework) \ - libglu1-mesa-dev $(: embree ospray : OpenGL requirements) \ - freeglut3-dev $(: embree ospray : OpenGL requirements) \ - mesa-common-dev $(: embree ospray : OpenGL requirements) \ - libc6-dev $(: enchiladas : pthreads) \ + # python $(: pistache : running tests) \ + # libtbb-dev $(: embree ospray : threading framework) \ + # libglu1-mesa-dev $(: embree ospray : OpenGL requirements) \ + # freeglut3-dev $(: embree ospray : OpenGL requirements) \ + # mesa-common-dev $(: embree ospray : OpenGL requirements) \ + # libc6-dev $(: enchiladas : pthreads) \ + && \ + rm -rf /var/lib/apt/lists/* + +RUN apt-get update && \ + apt-get install -y \ + build-essential $(: all : compile tool) \ + # python $(: pistache : running tests) \ + # libtbb-dev $(: embree ospray : threading framework) \ + # libglu1-mesa-dev $(: embree ospray : OpenGL requirements) \ + # freeglut3-dev $(: embree ospray : OpenGL requirements) \ + # mesa-common-dev $(: embree ospray : OpenGL requirements) \ + # libc6-dev $(: enchiladas : pthreads) \ && \ rm -rf /var/lib/apt/lists/* @@ -23,19 +35,41 @@ RUN true && \ -DRAPIDJSON_BUILD_TESTS:BOOL=OFF \ && \ make && \ - make install + make install DESTDIR=/stage +FROM ubuntu:latest AS ispc WORKDIR /opt/ ADD ispc-v1.9.1-linux.tar.gz /opt/ RUN mv ispc-v1.9.1-linux ispc WORKDIR /opt/ispc/ -RUN update-alternatives --install /usr/bin/ispc ispc /opt/ispc/ispc 1 +RUN mkdir -p /stage/usr/bin && \ + cp /opt/ispc/ispc /stage/usr/bin/ +FROM ubuntu:latest AS embree WORKDIR /opt/ ADD embree-2.16.4.x86_64.linux.tar.gz /opt/ RUN mv embree-2.16.4.x86_64.linux embree WORKDIR /opt/embree/ +FROM ubuntu:latest AS ospray + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + # Compilation tool for C/C++ programs + cmake \ + # python $(: pistache : running tests) \ + # libtbb-dev $(: embree ospray : threading framework) \ + # libglu1-mesa-dev $(: embree ospray : OpenGL requirements) \ + # freeglut3-dev $(: embree ospray : OpenGL requirements) \ + # mesa-common-dev $(: embree ospray : OpenGL requirements) \ + # libc6-dev $(: enchiladas : pthreads) \ + && \ + rm -rf /var/lib/apt/lists/* + +COPY --from=ispc /stage / +COPY --from=embree /opt/embree /opt/embree + WORKDIR /opt/ COPY ospray /opt/ospray WORKDIR /opt/ospray/build @@ -46,7 +80,12 @@ RUN true && \ -DOSPRAY_TASKING_SYSTEM=OpenMP \ && \ make && \ - make install + make install DESTDIR=/stage + +FROM ubuntu:latest AS pbnj +COPY --from=rapidjson /stage / +COPY --from=embree /opt/embree /opt/embree +COPY --from=ospray /stage / RUN apt-get update && \ apt-get install -y \ @@ -54,6 +93,18 @@ RUN apt-get update && \ && \ rm -rf /var/lib/apt/lists/* +RUN apt-get update && \ + apt-get install -y \ + cmake \ + && \ + rm -rf /var/lib/apt/lists/* + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + && \ + rm -rf /var/lib/apt/lists/* + WORKDIR /opt/pbnj/ COPY cmake ./cmake COPY include ./include @@ -76,7 +127,8 @@ RUN apt-get update && \ rm -rf /var/lib/apt/lists/* WORKDIR /opt/pbnj/ -COPY python ./python +COPY pbnj.py ./pbnj.py +COPY pbnj_wrap.cxx ./pbnj_wrap.cxx COPY setup.py ./setup.py WORKDIR /opt/pbnj/ RUN true && \ @@ -86,6 +138,4 @@ RUN true && \ RUN true && \ env LD_RUN_PATH=/usr/local/lib:/opt/embree/lib venv/bin/pip install --verbose . COPY test.py ./test.py -RUN true && \ - venv/bin/python3 test.py && \ - false +CMD ["venv/bin/python3", "test.py"] diff --git a/pbnj.i b/pbnj.i new file mode 100644 index 0000000..6676cdc --- /dev/null +++ b/pbnj.i @@ -0,0 +1,208 @@ +%module pbnj + +%include +%include + +%{ +#include "pbnj.h" +#include "Configuration.h" +#include "Camera.h" +#include "ConfigReader.h" +#include "DataFile.h" +#include "Renderer.h" +#include "TimeSeries.h" +#include "TransferFunction.h" +#include "Volume.h" + +namespace pbnj { +void init(void) { + int argc; + const char *argv[1]; + const std::string dummy = "dummy"; + + argc = 1; + argv[0] = dummy.c_str(); + + pbnj::pbnjInit(&argc, argv); +} +}; + +%} + +namespace pbnj { + +void init(void); + +enum CONFSTATE {ERROR_NODATA, ERROR_MULTISET, SINGLE_NOVAR, SINGLE_VAR, + MULTI_NOVAR, MULTI_VAR}; + +class Configuration { +public: + Configuration(std::string filename); + ~Configuration(); + + CONFSTATE getConfigState(); + + std::string configFilename; + + std::string dataFilename; + std::vector globbedFilenames; + std::string dataVariable; + int dataXDim; + int dataYDim; + int dataZDim; + + int imageWidth; + int imageHeight; + std::string imageFilename; + std::vector bgColor; + + std::vector colorMap; + std::vector opacityMap; + float opacityAttenuation; + + unsigned int samples; + + float cameraX; + float cameraY; + float cameraZ; + + float cameraUpX; + float cameraUpY; + float cameraUpZ; + + std::vector isosurfaceValues; +}; + +class Camera { +public: + Camera(int width, int height); + ~Camera(); + + void setPosition(float x, float y, float z); + void setUpVector(float x, float y, float z); + void setOrbitRadius(float radius); + void centerView(); + + OSPCamera asOSPRayObject(); + + int imageWidth; + int imageHeight; + + std::string ID; +}; + +class ConfigReader { + public: + ConfigReader(); + ~ConfigReader(); + + void parseConfigFile(std::string filename, + rapidjson::Document& config); +}; + +enum FILETYPE {UNKNOWN, BINARY, NETCDF}; + + +class DataFile { + + public: + DataFile(int x, int y, int z); + ~DataFile(); + + void loadFromFile(std::string filename, std::string variable="", + bool memmap=false); + void calculateStatistics(); + void printStatistics(); + + // experimental + void bin(unsigned int num_bins); + + std::string filename; + FILETYPE filetype; + + int xDim; + int yDim; + int zDim; + long int numValues; + + float minVal; // these should + float maxVal; // + float avgVal; // eventually be + float stdDev; // + float *data; // template types + + bool statsCalculated; +}; + + +enum IMAGETYPE {INVALID, PIXMAP, PNG}; + + +class Renderer { + public: + Renderer(); + ~Renderer(); + + void setBackgroundColor(unsigned char r, unsigned char g, unsigned char b); + void setBackgroundColor(std::vector bgColor); + void setVolume(pbnj::Volume *v); + void setIsosurface(pbnj::Volume *v, std::vector &isoValues); + void setCamera(pbnj::Camera *c); + void setSamples(unsigned int spp); + + void render(); + void renderToBuffer(unsigned char **buffer); + void renderToPNGObject(std::vector &png); + void renderImage(std::string imageFilename); + + int cameraWidth; + int cameraHeight; +}; + + +class TimeSeries { + + public: + TimeSeries(std::vector filenames, int x, int y, int z); + TimeSeries(std::vector filenames, std::string varname, + int x, int y, int z); + ~TimeSeries(); + + pbnj::Volume *getVolume(unsigned int index); + int getVolumeIndex(std::string filename); + unsigned int getLength(); + void setMaxMemory(unsigned int gigabytes); + + // attributes for volumes to receive when loaded + std::vector colorMap; + std::vector opacityMap; + float opacityAttenuation; + bool doMemoryMap; + + void setColorMap(std::vector &map); + void setOpacityMap(std::vector &map); + void setOpacityAttenuation(float attenuation); + void setMemoryMapping(bool toMMap); +}; + +class Volume { + + public: + //Volume(DataFile *df); + Volume(std::string filename, int x, int y, int z, + bool memmap=false); + Volume(std::string filename, std::string var_name, int x, int y, + int z, bool memmap=false); + ~Volume(); + + void attenuateOpacity(float amount); + void setColorMap(std::vector &map); + void setOpacityMap(std::vector &map); + std::vector getBounds(); + OSPVolume asOSPRayObject(); + + std::string ID; +}; + +}; diff --git a/python/pbnjmodule.cpp b/python/pbnjmodule.cpp deleted file mode 100644 index f64d1f7..0000000 --- a/python/pbnjmodule.cpp +++ /dev/null @@ -1,348 +0,0 @@ -#include -#include -#include "pbnj.h" -#include "Configuration.h" -#include "Camera.h" - -extern "C" { - -/******************************************************************************* - * START pbnj.Configuration - ******************************************************************************/ - -typedef struct { - PyObject_HEAD - pbnj::Configuration *object; -} Configuration; - - -static void -Configuration_dealloc(Configuration *self) { - delete self->object; - self->object = NULL; -} - - -static PyObject * -Configuration_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - Configuration *self; - - self = (Configuration *)type->tp_alloc(type, 0); - if (self != NULL) { - self->object = NULL; - } - - return (PyObject *)self; -} - - -static int -Configuration_init(Configuration *self, PyObject *args) { - const char *filename; - - if (!PyArg_ParseTuple(args, "s", &filename)) { - return -1; - } - - self->object = new pbnj::Configuration(std::string(filename)); - - return 0; -} - -static char *ConfigurationDoc = NULL; - - -static PyTypeObject ConfigurationType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pbnj.Configuration", /* tp_name */ - sizeof(Configuration), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Configuration_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - ConfigurationDoc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Configuration_init, /* tp_init */ - 0, /* tp_alloc */ - Configuration_new, /* tp_new */ -}; - - -static PyObject * -Configuration_get_image_width(PyObject *self, PyObject *args) { - Configuration *config; - - if (!PyArg_ParseTuple(args, "O!", &ConfigurationType, &config)) { - return NULL; - } - - return PyLong_FromLong((long)config->object->imageWidth); -} - - -static PyMethodDef Configuration_get_image_width_method = { - "Configuration_get_image_width", - (PyCFunction)Configuration_get_image_width, - METH_VARARGS, - "Configuration_get_image_width documentation", -}; - - -static PyObject * -Configuration_get_image_height(PyObject *self, PyObject *args) { - Configuration *config; - - if (!PyArg_ParseTuple(args, "O!", &ConfigurationType, &config)) { - return NULL; - } - - return PyLong_FromLong((long)config->object->imageHeight); -} - - -static PyMethodDef Configuration_get_image_height_method = { - "Configuration_get_image_height", - (PyCFunction)Configuration_get_image_height, - METH_VARARGS, - "Configuration_get_image_height documentation", -}; - - -/******************************************************************************* - * END pbnj.Configuration - ******************************************************************************/ - -/******************************************************************************* - * START pbnj.Camera - ******************************************************************************/ - -typedef struct { - PyObject_HEAD - pbnj::Camera *object; -} Camera; - - -static void -Camera_dealloc(Camera *self) { - delete self->object; - self->object = NULL; -} - - -static PyObject * -Camera_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - Camera *self; - - self = (Camera *)type->tp_alloc(type, 0); - if (self != NULL) { - self->object = NULL; - } - - return (PyObject *)self; -} - - -static int -Camera_init(Camera *self, PyObject *args) { - int width, height; - - if (!PyArg_ParseTuple(args, "ii", &width, &height)) { - return -1; - } - - self->object = new pbnj::Camera(width, height); - - return 0; -} - - -static char *CameraDoc = NULL; - - -static PyTypeObject CameraType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_pbnj.Camera", /* tp_name */ - sizeof(Camera), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)Camera_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - CameraDoc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)Camera_init, /* tp_init */ - 0, /* tp_alloc */ - Camera_new, /* tp_new */ -}; - - -static PyObject * -Camera_get_image_width(PyObject *self, PyObject *args) { - Camera *camera; - - if (!PyArg_ParseTuple(args, "O!", &CameraType, &camera)) { - return NULL; - } - - return PyLong_FromLong((long)camera->object->imageWidth); -} - - -static PyMethodDef Camera_get_image_width_method = { - "Camera_get_image_width", - (PyCFunction)Camera_get_image_width, - METH_VARARGS, - "Camera_get_image_width documentation", -}; - - -static PyObject * -Camera_get_image_height(PyObject *self, PyObject *args) { - Camera *camera; - - if (!PyArg_ParseTuple(args, "O!", &CameraType, &camera)) { - return NULL; - } - - return PyLong_FromLong((long)camera->object->imageHeight); -} - - -static PyMethodDef Camera_get_image_height_method = { - "Camera_get_image_height", - (PyCFunction)Camera_get_image_height, - METH_VARARGS, - "Camera_get_image_height documentation", -}; - - -/******************************************************************************* - * END pbnj.Camera - ******************************************************************************/ - -/******************************************************************************* - * START pbnj - ******************************************************************************/ - -static PyObject * -pbnj_init(PyObject *self) { - int argc; - const char *argv[1]; - const std::string dummy = "dummy"; - - argc = 1; - argv[0] = dummy.c_str(); - - pbnj::pbnjInit(&argc, argv); - - Py_RETURN_NONE; -} - - -static PyMethodDef pbnj_init_method = { - "init", - (PyCFunction)pbnj_init, - METH_NOARGS, - "Initialize the PBNJ subsystem.", -}; - - -static PyMethodDef PbnjMethods[] = { - Configuration_get_image_width_method, - Configuration_get_image_height_method, - Camera_get_image_width_method, - Camera_get_image_height_method, - pbnj_init_method, - {NULL, NULL, 0, NULL}, -}; - - -static char *pbnj_doc = NULL; - - -static struct PyModuleDef pbnjmodule = { - PyModuleDef_HEAD_INIT, - "_pbnj", - pbnj_doc, - -1, /* module keeps state in global variables */ - PbnjMethods, -}; - - -PyMODINIT_FUNC -PyInit__pbnj(void) { - PyObject *m; - - ConfigurationType.tp_new = PyType_GenericNew; - if (PyType_Ready(&ConfigurationType) < 0) - return NULL; - - CameraType.tp_new = PyType_GenericNew; - if (PyType_Ready(&CameraType) < 0) - return NULL; - - m = PyModule_Create(&pbnjmodule); - if (m == NULL) - return NULL; - - Py_INCREF(&ConfigurationType); - PyModule_AddObject(m, "Configuration", (PyObject *)&ConfigurationType); - - Py_INCREF(&CameraType); - PyModule_AddObject(m, "Camera", (PyObject *)&CameraType); - - return m; -} - -} /* extern "C" */ diff --git a/setup.py b/setup.py index 49ec099..bd62a37 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ 'pbnj', ], sources=[ - 'python/pbnjmodule.cpp', + 'pbnj_wrap.cxx', ], ) @@ -40,4 +40,7 @@ ext_modules=[ _pbnj, ], + py_modules=[ + 'python/pbnj', + ], ) From fe11686532ba320b2e0a1fa143c0361b19b87f9e Mon Sep 17 00:00:00 2001 From: Tanner Hobson Date: Sat, 14 Oct 2017 10:36:41 -0400 Subject: [PATCH 3/4] Namespace pbnj types to simplify SWIG wrapper --- include/Renderer.h | 6 +- include/TimeSeries.h | 2 +- pbnj.i | 179 ++----------------------------------------- src/DataFile.cpp | 2 +- 4 files changed, 13 insertions(+), 176 deletions(-) diff --git a/include/Renderer.h b/include/Renderer.h index b74c332..112e5d9 100644 --- a/include/Renderer.h +++ b/include/Renderer.h @@ -19,9 +19,9 @@ namespace pbnj { void setBackgroundColor(unsigned char r, unsigned char g, unsigned char b); void setBackgroundColor(std::vector bgColor); - void setVolume(Volume *v); - void setIsosurface(Volume *v, std::vector &isoValues); - void setCamera(Camera *c); + void setVolume(pbnj::Volume *v); + void setIsosurface(pbnj::Volume *v, std::vector &isoValues); + void setCamera(pbnj::Camera *c); void setSamples(unsigned int spp); void render(); diff --git a/include/TimeSeries.h b/include/TimeSeries.h index 87d8b56..08f865d 100644 --- a/include/TimeSeries.h +++ b/include/TimeSeries.h @@ -18,7 +18,7 @@ namespace pbnj { int x, int y, int z); ~TimeSeries(); - Volume *getVolume(unsigned int index); + pbnj::Volume *getVolume(unsigned int index); int getVolumeIndex(std::string filename); unsigned int getLength(); void setMaxMemory(unsigned int gigabytes); diff --git a/pbnj.i b/pbnj.i index 6676cdc..1b2c770 100644 --- a/pbnj.i +++ b/pbnj.i @@ -33,176 +33,13 @@ namespace pbnj { void init(void); -enum CONFSTATE {ERROR_NODATA, ERROR_MULTISET, SINGLE_NOVAR, SINGLE_VAR, - MULTI_NOVAR, MULTI_VAR}; - -class Configuration { -public: - Configuration(std::string filename); - ~Configuration(); - - CONFSTATE getConfigState(); - - std::string configFilename; - - std::string dataFilename; - std::vector globbedFilenames; - std::string dataVariable; - int dataXDim; - int dataYDim; - int dataZDim; - - int imageWidth; - int imageHeight; - std::string imageFilename; - std::vector bgColor; - - std::vector colorMap; - std::vector opacityMap; - float opacityAttenuation; - - unsigned int samples; - - float cameraX; - float cameraY; - float cameraZ; - - float cameraUpX; - float cameraUpY; - float cameraUpZ; - - std::vector isosurfaceValues; -}; - -class Camera { -public: - Camera(int width, int height); - ~Camera(); - - void setPosition(float x, float y, float z); - void setUpVector(float x, float y, float z); - void setOrbitRadius(float radius); - void centerView(); - - OSPCamera asOSPRayObject(); - - int imageWidth; - int imageHeight; - - std::string ID; }; -class ConfigReader { - public: - ConfigReader(); - ~ConfigReader(); - - void parseConfigFile(std::string filename, - rapidjson::Document& config); -}; - -enum FILETYPE {UNKNOWN, BINARY, NETCDF}; - - -class DataFile { - - public: - DataFile(int x, int y, int z); - ~DataFile(); - - void loadFromFile(std::string filename, std::string variable="", - bool memmap=false); - void calculateStatistics(); - void printStatistics(); - - // experimental - void bin(unsigned int num_bins); - - std::string filename; - FILETYPE filetype; - - int xDim; - int yDim; - int zDim; - long int numValues; - - float minVal; // these should - float maxVal; // - float avgVal; // eventually be - float stdDev; // - float *data; // template types - - bool statsCalculated; -}; - - -enum IMAGETYPE {INVALID, PIXMAP, PNG}; - - -class Renderer { - public: - Renderer(); - ~Renderer(); - - void setBackgroundColor(unsigned char r, unsigned char g, unsigned char b); - void setBackgroundColor(std::vector bgColor); - void setVolume(pbnj::Volume *v); - void setIsosurface(pbnj::Volume *v, std::vector &isoValues); - void setCamera(pbnj::Camera *c); - void setSamples(unsigned int spp); - - void render(); - void renderToBuffer(unsigned char **buffer); - void renderToPNGObject(std::vector &png); - void renderImage(std::string imageFilename); - - int cameraWidth; - int cameraHeight; -}; - - -class TimeSeries { - - public: - TimeSeries(std::vector filenames, int x, int y, int z); - TimeSeries(std::vector filenames, std::string varname, - int x, int y, int z); - ~TimeSeries(); - - pbnj::Volume *getVolume(unsigned int index); - int getVolumeIndex(std::string filename); - unsigned int getLength(); - void setMaxMemory(unsigned int gigabytes); - - // attributes for volumes to receive when loaded - std::vector colorMap; - std::vector opacityMap; - float opacityAttenuation; - bool doMemoryMap; - - void setColorMap(std::vector &map); - void setOpacityMap(std::vector &map); - void setOpacityAttenuation(float attenuation); - void setMemoryMapping(bool toMMap); -}; - -class Volume { - - public: - //Volume(DataFile *df); - Volume(std::string filename, int x, int y, int z, - bool memmap=false); - Volume(std::string filename, std::string var_name, int x, int y, - int z, bool memmap=false); - ~Volume(); - - void attenuateOpacity(float amount); - void setColorMap(std::vector &map); - void setOpacityMap(std::vector &map); - std::vector getBounds(); - OSPVolume asOSPRayObject(); - - std::string ID; -}; - -}; +%include "include/Configuration.h" +%include "include/Camera.h" +%include "include/ConfigReader.h" +%include "include/DataFile.h" +%include "include/Renderer.h" +%include "include/TimeSeries.h" +%include "include/TransferFunction.h" +%include "include/Volume.h" diff --git a/src/DataFile.cpp b/src/DataFile.cpp index 21d3bbe..81dde02 100644 --- a/src/DataFile.cpp +++ b/src/DataFile.cpp @@ -81,7 +81,7 @@ void DataFile::loadFromFile(std::string filename, std::string var_name, FILE *dataFile = fopen(filename.c_str(), "r"); if(dataFile == NULL) { - std::cerr << "Could not open file!" << std::endl; + std::cerr << "Could not open file! " << filename << std::endl; } else { if(memmap) { From 5012a03d2184ef19533e01868e43e2995e71676a Mon Sep 17 00:00:00 2001 From: Tanner Hobson Date: Sat, 14 Oct 2017 11:20:56 -0400 Subject: [PATCH 4/4] Streamline Python module installation --- .gitignore | 2 + Dockerfile | 141 ----------------------------------------------------- setup.py | 29 ++++++++--- 3 files changed, 24 insertions(+), 148 deletions(-) delete mode 100644 Dockerfile diff --git a/.gitignore b/.gitignore index 71726ac..9342593 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ install/ configs/ renders/ .*.swp +*~ +__pycache__ diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 3fc096f..0000000 --- a/Dockerfile +++ /dev/null @@ -1,141 +0,0 @@ -FROM ubuntu:latest AS rapidjson - -RUN apt-get update && \ - apt-get install -y \ - # build-essential $(: all : compile tool) \ - # Compilation tool for C/C++ programs - cmake $(: all : compile tool) \ - # python $(: pistache : running tests) \ - # libtbb-dev $(: embree ospray : threading framework) \ - # libglu1-mesa-dev $(: embree ospray : OpenGL requirements) \ - # freeglut3-dev $(: embree ospray : OpenGL requirements) \ - # mesa-common-dev $(: embree ospray : OpenGL requirements) \ - # libc6-dev $(: enchiladas : pthreads) \ - && \ - rm -rf /var/lib/apt/lists/* - -RUN apt-get update && \ - apt-get install -y \ - build-essential $(: all : compile tool) \ - # python $(: pistache : running tests) \ - # libtbb-dev $(: embree ospray : threading framework) \ - # libglu1-mesa-dev $(: embree ospray : OpenGL requirements) \ - # freeglut3-dev $(: embree ospray : OpenGL requirements) \ - # mesa-common-dev $(: embree ospray : OpenGL requirements) \ - # libc6-dev $(: enchiladas : pthreads) \ - && \ - rm -rf /var/lib/apt/lists/* - -WORKDIR /opt/ -COPY rapidjson /opt/rapidjson -WORKDIR /opt/rapidjson/build/ -RUN true && \ - cmake .. \ - -DRAPIDJSON_BUILD_EXAMPLES:BOOL=OFF \ - -DRAPIDJSON_BUILD_TESTS:BOOL=OFF \ - && \ - make && \ - make install DESTDIR=/stage - -FROM ubuntu:latest AS ispc -WORKDIR /opt/ -ADD ispc-v1.9.1-linux.tar.gz /opt/ -RUN mv ispc-v1.9.1-linux ispc -WORKDIR /opt/ispc/ -RUN mkdir -p /stage/usr/bin && \ - cp /opt/ispc/ispc /stage/usr/bin/ - -FROM ubuntu:latest AS embree -WORKDIR /opt/ -ADD embree-2.16.4.x86_64.linux.tar.gz /opt/ -RUN mv embree-2.16.4.x86_64.linux embree -WORKDIR /opt/embree/ - -FROM ubuntu:latest AS ospray - -RUN apt-get update && \ - apt-get install -y \ - build-essential \ - # Compilation tool for C/C++ programs - cmake \ - # python $(: pistache : running tests) \ - # libtbb-dev $(: embree ospray : threading framework) \ - # libglu1-mesa-dev $(: embree ospray : OpenGL requirements) \ - # freeglut3-dev $(: embree ospray : OpenGL requirements) \ - # mesa-common-dev $(: embree ospray : OpenGL requirements) \ - # libc6-dev $(: enchiladas : pthreads) \ - && \ - rm -rf /var/lib/apt/lists/* - -COPY --from=ispc /stage / -COPY --from=embree /opt/embree /opt/embree - -WORKDIR /opt/ -COPY ospray /opt/ospray -WORKDIR /opt/ospray/build -RUN true && \ - cmake .. \ - -Dembree_DIR=/opt/embree \ - -DOSPRAY_ENABLE_APPS:BOOL=OFF \ - -DOSPRAY_TASKING_SYSTEM=OpenMP \ - && \ - make && \ - make install DESTDIR=/stage - -FROM ubuntu:latest AS pbnj -COPY --from=rapidjson /stage / -COPY --from=embree /opt/embree /opt/embree -COPY --from=ospray /stage / - -RUN apt-get update && \ - apt-get install -y \ - python3-dev \ - && \ - rm -rf /var/lib/apt/lists/* - -RUN apt-get update && \ - apt-get install -y \ - cmake \ - && \ - rm -rf /var/lib/apt/lists/* - -RUN apt-get update && \ - apt-get install -y \ - build-essential \ - && \ - rm -rf /var/lib/apt/lists/* - -WORKDIR /opt/pbnj/ -COPY cmake ./cmake -COPY include ./include -COPY src ./src -COPY CMakeLists.txt ./CMakeLists.txt -WORKDIR /opt/pbnj/build -RUN true && \ - cmake .. \ - -DUSE_NETCDF:BOOL=OFF \ - -DBUILD_EXAMPLES:BOOL=OFF \ - -Dembree_DIR=/opt/embree \ - && \ - make && \ - make install - -RUN apt-get update && \ - apt-get install -y \ - python3-pip \ - && \ - rm -rf /var/lib/apt/lists/* - -WORKDIR /opt/pbnj/ -COPY pbnj.py ./pbnj.py -COPY pbnj_wrap.cxx ./pbnj_wrap.cxx -COPY setup.py ./setup.py -WORKDIR /opt/pbnj/ -RUN true && \ - python3 -m pip install virtualenv && \ - python3 -m virtualenv -p python3 venv - -RUN true && \ - env LD_RUN_PATH=/usr/local/lib:/opt/embree/lib venv/bin/pip install --verbose . -COPY test.py ./test.py -CMD ["venv/bin/python3", "test.py"] diff --git a/setup.py b/setup.py index bd62a37..18e161c 100644 --- a/setup.py +++ b/setup.py @@ -4,8 +4,30 @@ """ from distutils.core import setup, Extension +from os import environ +# Needed so that the extension can always find the modules, even if they aren't +# on your normal load path. e.g. /opt/embree/lib usually isn't in your +# ldconfig, so this hard codes /opt/embree/lib into your extension, so that it +# knows where to look for the libraries. +def patch_ld_run_path(): + if 'LD_RUN_PATH' in environ is not None: + ld_run_path += environ['LD_RUN_PATH'] + ':' + else: + ld_run_path = '' + + ld_run_path += ':'.join([ + '/opt/embree/lib', + '/usr/local/lib', + '/usr/local/lib64', + ]) + + environ['LD_RUN_PATH'] = ld_run_path + + +patch_ld_run_path() + _pbnj = Extension( '_pbnj', language='c++', @@ -30,17 +52,10 @@ 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6', ], - packages=[ - ], python_requires='>=3.5', - install_requires=[ - ], entry_points={ }, ext_modules=[ _pbnj, ], - py_modules=[ - 'python/pbnj', - ], )