diff --git a/.gitignore b/.gitignore index 72b0ae9..51549b6 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,6 @@ make.inc /.project /.pydevproject /.settings + +# DASPK3.1 source files +daspk31/* \ No newline at end of file diff --git a/Makefile b/Makefile index cc3a8db..a856651 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ daspk: DASPK31 cython-daspk cython-daspk: python setup.py build_ext daspk $(CYTHON_FLAGS) -cython: DASSL DASPK DASKR pydas.pyx +cython: DASSL DASPK DASKR python setup.py build_ext $(CYTHON_FLAGS) install: DASSL DASPK DASKR cython @@ -54,7 +54,7 @@ clean-DASKR: clean-cython: python setup.py clean $(CLEAN_FLAGS) - rm -f *.so *.pyc *.c + rm -f pydas/*.so pydas/*.pyc pydas/*.c help: @echo "" diff --git a/README.rst b/README.rst index b564c64..ea4f848 100644 --- a/README.rst +++ b/README.rst @@ -13,6 +13,12 @@ provides a Python extension type for each solver, which in turn provides a Pythonic means of setting the solver options, providing residual and jacobian functions, and running the solver. +In addition, PyDAS also provides a wrapper to the DASPK3.1 solver, which +has native sensitivity analysis. The source code for DASPK3.1 is subject to +copyright restrictions but is available for research purposes. Due to these +restrictions, it is up to the user to download these source files manually. +Please see the README file inside the daspk31/ folder for more details. + The DASSL, DASPK, and DASKR solvers are all substantially more robust than VODE, the solver used within the ODE solver functionality provided by `SciPy `_. @@ -71,31 +77,44 @@ Installation .. note:: - Currently only the DASSL solver has been wrapped. The installation - scripts therefore only build and install the DASSL wrapper by default. + Currently only the DASSL and DASPK3.1 solvers have been wrapped. + The installation scripts only build and install the DASSL wrapper + by default. The DASPK wrapper must be installed with additional arguments. Windows ------- -The provided batch scripts will compile all of the solvers and the PyDAS -wrapper code. These scripts presume that you have the 32-bit version of the +The provided make.bat batch script will compile the DASSL solver and the PyDAS +wrapper code. Use the make_daspk.bat script to compile the DASPK3.1 solver and the +DASPK wrapper code. Make sure you have manually downloaded the DASPK3.1 source +files into the daspk31 folder. See the daspk31/README file for more details. +These scripts presume that you have the 32-bit version of the MinGW C and Fortran compilers installed. Once you have run the batch script, you can install PyDAS into your Python packages if you desire by running the following command from the base package directory: > python setup.py install + Linux ----- -A Makefile has been provided that can be used to compile all of the solvers -and the PyDAS wrapper code. To use, invoke the following command from the +A Makefile has been provided that can be used to compile the DASSL solver and +DASSL wrapper code. To use, invoke the following command from the base package directory:: $ make This command will build PyDAS in-place, rather than installing it to your -Python package directory. If you wish to formall install PyDAS, run the +Python package directory. + +If you wish to compile the DASPK3.1 solver and wrapper, use the command +(Make sure you have already downloaded the fortran source files. See the +daspk/README file for more details):: + + $ make daspk + + If you wish to formall install PyDAS, run the following command from the base package directory after the ``make`` command (you may need root privileges for this):: @@ -106,6 +125,7 @@ the Makefiles (e.g. the Fortran compiler). An example of such a file, `make.inc.example`, has been provided. + Mac OS X -------- diff --git a/daspk31/Makefile b/daspk31/Makefile index aaacd3a..4a33cac 100644 --- a/daspk31/Makefile +++ b/daspk31/Makefile @@ -8,7 +8,7 @@ F77=gfortran CFLAGS=-fPIC -O3 -DOBJ=adf_dummy.o daux.o ddaskr.o ddaspk.o dlinpk.o dsensd.o mpi_dummy.o +DOBJ=solver/adf_dummy.o solver/daux.o solver/ddaskr.o solver/ddaspk.o solver/dlinpk.o solver/dsensd.o solver/mpi_dummy.o DLIB=libddaspk31.a diff --git a/daspk31/README b/daspk31/README index 845dfcc..1390a6a 100644 --- a/daspk31/README +++ b/daspk31/README @@ -1,9 +1,11 @@ DASPK 3.1 Large Scale Differential Algebraic Equation Solver with Sensitivity Analysis -Before using, dump the source files of the DASPK 3.1 solver folder into this folder. -The fortran solver can be downloaded here: http://www.engineering.ucsb.edu/~cse/software.html -The files present should be as follows: +Before using, dump the files from the DASPK 3.1 source code into this folder. +You can use the script download_daspk31.sh to automatically download and unpack the source files +or download it manually from the web here: http://www.engineering.ucsb.edu/~cse/software.html + +The following files should be present in the 'solver' folder: adf_dummy.f daux.f ddaskr.f diff --git a/daspk31/download_daspk31.sh b/daspk31/download_daspk31.sh new file mode 100644 index 0000000..3077603 --- /dev/null +++ b/daspk31/download_daspk31.sh @@ -0,0 +1,5 @@ +echo 'Downloading and unpacking DASPK 3.1 fortran source files...' +wget http://www.cs.ucsb.edu/~cse/Software/daspk31.tgz +tar zxvf daspk31.tgz -C ../ +rm daspk31.tgz + diff --git a/documentation/source/users/installation.rst b/documentation/source/users/installation.rst index 9907d8b..f7929b1 100644 --- a/documentation/source/users/installation.rst +++ b/documentation/source/users/installation.rst @@ -24,6 +24,11 @@ provides these compilers. The DASSL, DASPK, and DASKR solvers are provided with the PyDAS package; you do not need to download them separately. +The DASPK3.1 solver is subject to copyright restrictions and therefore +must be downloaded separately either using the ``daspk31/download_daspk31.sh`` +script or by manually unpacking the files from the daspk31 source code +found on `Linda Petzold's software page `_ into the ``daspk31`` folder. + .. [#f1] The Fortran interfaces are exposed to Python via C, so the installer needs to be able to link object files from Fortran and C for this to work. @@ -48,6 +53,12 @@ Python package directory. At this point you can optionally run the unit test script ``test.py`` and/or any of the provided examples to confirm that PyDAS was compiled successfully. +If you wish to compile the DASPK3.1 solver and wrapper, use the command. +Make sure you have already downloaded the fortran source files. See the +``daspk/README`` file for where to download the files.:: + + $ make daspk + If you wish to formally install PyDAS, run the following command from the root package directory after the ``make`` command (you may need root privileges for this):: @@ -70,9 +81,11 @@ Windows from the ``cython-dev`` mailing list for more information. A batch script ``make.bat`` has been provided in the root package directory. -Double-clicking this script will cause all of the solvers -- DASSL, DASPK, and -DASKR -- to be compiled into static libraries and the PyDAS wrapper code to be -compiled. +Double-clicking this script will compile the DASSL solver into a static library and also compile the PyDAS wrapper code. + +The batch script ``make_daspk.bat`` has been provided to compile the DASPK3.1 +solver and the DASPK wrapper code. Make sure the source code for the DASPK3.1 +have been manually downloaded and stored inside the daspk31 folder. See ``daspk31/README`` for details on where to download the files. .. note:: diff --git a/make_daspk.bat b/make_daspk.bat new file mode 100644 index 0000000..b1d80dc --- /dev/null +++ b/make_daspk.bat @@ -0,0 +1,22 @@ +@echo off + +:: Set the Fortran compiler and compiler flags +set f77=gfortran +set cflags=-O3 + +echo Compiling DASPK3.1... +CALL %f77% %cflags% -c daspk31/solver/adf_dummy.f -o daspk/solver/adf_dummy.o +CALL %f77% %cflags% -c daspk31/solver/daux.f -o daspk/solver/daux.o +CALL %f77% %cflags% -c daspk31/solver/ddaskr.f -o daspk/solver/ddaskr.o +CALL %f77% %cflags% -c daspk31/solver/ddaspk.f -o daspk/solver/ddaspk.o +CALL %f77% %cflags% -c daspk31/solver/dlinpk.f -o daspk/solver/dlinpk.o +CALL %f77% %cflags% -c daspk31/solver/dsensd.f -o daspk/solver/dsensd.o +CALL %f77% %cflags% -c daspk31/solver/mpi_dummy.f -o daspk/solver/mpi_dummy.o + +CALL ar rcs dassl/libddaspk31.a daspk31/solver/adf_dummy.o daspk31/solver/daux.o daspk31/solver/ddaskr.o daspk31/solver/ddaspk.o daspk31/solver/dlinpk.o daspk31/solver/dsensd.o daspk31/solver/mpi_dummy.o + +echo Compiling PyDAS DASPK wrapper... +CALL python setup.py build_ext daspk --compiler=mingw32 --inplace + +:end +pause diff --git a/pydas/__init__.py b/pydas/__init__.py new file mode 100644 index 0000000..42b1b24 --- /dev/null +++ b/pydas/__init__.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +################################################################################ +# +# PyDAS - A Python wrapper to several differential algebraic system solvers +# +# Copyright (c) 2010-2014 by Joshua W. Allen (joshua.w.allen@gmail.com) +# extended by Connie W. Gao (connieg@mit.edu) +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the 'Software'), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +################################################################################ + +import os + +def get_include(): + """ + Return the PyDAS include directory. + """ + return os.path.dirname(os.path.abspath(__file__)) diff --git a/daspk.h b/pydas/daspk.h similarity index 100% rename from daspk.h rename to pydas/daspk.h diff --git a/pydaspk.pxd b/pydas/daspk.pxd similarity index 100% rename from pydaspk.pxd rename to pydas/daspk.pxd diff --git a/pydaspk.pyx b/pydas/daspk.pyx similarity index 100% rename from pydaspk.pyx rename to pydas/daspk.pyx diff --git a/das.h b/pydas/dassl.h similarity index 100% rename from das.h rename to pydas/dassl.h diff --git a/pydas.pxd b/pydas/dassl.pxd similarity index 100% rename from pydas.pxd rename to pydas/dassl.pxd diff --git a/pydas.pyx b/pydas/dassl.pyx similarity index 98% rename from pydas.pyx rename to pydas/dassl.pyx index 92d2312..622a613 100644 --- a/pydas.pyx +++ b/pydas/dassl.pyx @@ -55,7 +55,7 @@ cimport cython ################################################################################ # Expose the (double-precision) DASSL function -cdef extern from "das.h": +cdef extern from "dassl.h": int ddassl_( void* res, # The residual function that defines the ODE/DAE system int* neq, # The number of equations to be solved @@ -185,8 +185,7 @@ cdef class DASSL: else: self.info[3] = 0 rwork[0] = 0 - - self.senpar = senpar # this is a dummy variable so that PyDAS and PyDASK can be used interchangeably + # Set whether or not jacobian function is provided # This is determined by whether or not you have implemented a # jacobian method @@ -391,7 +390,7 @@ cdef DASSL dasslObject cdef void residual(double* t, double* y, double* yprime, double* delta, int* ires, double* rpar, int* ipar): cdef np.ndarray[np.float64_t,ndim=1] res cdef int i - res, ires[0] = dasslObject.residual(dasslObject.t, dasslObject.y, dasslObject.dydt, dasslObject.senpar) + res, ires[0] = dasslObject.residual(dasslObject.t, dasslObject.y, dasslObject.dydt) for i in range(res.shape[0]): delta[i] = res[i] @@ -399,7 +398,7 @@ cdef void residual(double* t, double* y, double* yprime, double* delta, int* ire cdef void jacobian(double* t, double* y, double* yprime, double* pd, double* cj, double* rpar, int* ipar): cdef np.ndarray[np.float64_t,ndim=2] jac cdef int i, j - jac = dasslObject.jacobian(dasslObject.t, dasslObject.y, dasslObject.dydt, cj[0], dasslObject.senpar) + jac = dasslObject.jacobian(dasslObject.t, dasslObject.y, dasslObject.dydt, cj[0]) N = jac.shape[0] for i in range(N): for j in range(N): diff --git a/setup.py b/setup.py index 172080e..73c4ca4 100644 --- a/setup.py +++ b/setup.py @@ -50,28 +50,28 @@ # The Cython extension modules to compile pydas_ext = Extension( - 'pydas', - ['pydas.pyx'], - include_dirs=['.', numpy.get_include()], + 'pydas.dassl', + ['pydas/dassl.pyx'], + include_dirs=['pydas', numpy.get_include()], libraries=['gfortran'], extra_objects=['dassl/daux.o','dassl/ddassl.o','dassl/dlinpk.o'], ) pydaspk_ext = Extension( - 'pydaspk', - ['pydaspk.pyx'], - include_dirs=['.', numpy.get_include()], + 'pydas.daspk', + ['pydas/daspk.pyx'], + include_dirs=['pydas', numpy.get_include()], libraries=['gfortran'], - extra_objects=['daspk31/adf_dummy.o','daspk31/daux.o','daspk31/ddaspk.o','daspk31/dlinpk.o','daspk31/dsensd.o','daspk31/mpi_dummy.o'], + extra_objects=['daspk31/solver/adf_dummy.o','daspk31/solver/daux.o','daspk31/solver/ddaspk.o','daspk31/solver/dlinpk.o','daspk31/solver/dsensd.o','daspk31/solver/mpi_dummy.o'], ) - modules = ['pydas'] + modules = ['pydas.dassl'] extensions = [pydas_ext] if 'daspk' in sys.argv: # Optionally compile and make pydaspk if the user requests it sys.argv.remove('daspk') - modules.append('pydaspk') + modules.append('pydas.daspk') extensions.append(pydaspk_ext) # Run the setup command @@ -82,6 +82,8 @@ author_email='joshua.w.allen@gmail.com', url='http://github.com/jwallen/PyDAS', py_modules= modules, + packages = ['pydas'], + package_data = {'pydas': ['*.pxd']}, cmdclass = {'build_ext': build_ext}, ext_modules = extensions ) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..0be6831 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +################################################################################ +# +# PyDAS - A Python wrapper to several differential algebraic system solvers +# +# Copyright (c) 2010-2014 by Joshua W. Allen (joshua.w.allen@gmail.com) +# extended by Connie W. Gao (connieg@mit.edu) +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the 'Software'), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +################################################################################ diff --git a/pydaspkTest.py b/tests/daspkTest.py similarity index 99% rename from pydaspkTest.py rename to tests/daspkTest.py index fc7e61f..3547a65 100644 --- a/pydaspkTest.py +++ b/tests/daspkTest.py @@ -7,7 +7,7 @@ import unittest -from pydaspk import DASPK +from pydas.daspk import DASPK import math import numpy import matplotlib.pyplot as plt diff --git a/pydasTest.py b/tests/dasslTest.py similarity index 95% rename from pydasTest.py rename to tests/dasslTest.py index d80fc1f..4346cdd 100644 --- a/pydasTest.py +++ b/tests/dasslTest.py @@ -7,7 +7,7 @@ import unittest -from pydas import DASSL +from pydas.dassl import DASSL import math import numpy @@ -30,14 +30,14 @@ def __init__(self, k1=0.0, k2=0.0): self.k1 = k1 self.k2 = k2 - def residual(self, t, y, dydt, senpar): + def residual(self, t, y, dydt): delta = numpy.zeros(y.shape[0], numpy.float64) delta[0] = -self.k1 * y[0] - dydt[0] delta[1] = self.k1 * y[0] - self.k2 * y[1] - dydt[1] delta[2] = self.k2 * y[1] - dydt[2] return delta, 0 - def jacobian(self, t, y, dydt, cj, senpar): + def jacobian(self, t, y, dydt, cj): pd = -cj * numpy.identity(y.shape[0], numpy.float64) pd[0,0] += -self.k1 pd[1,0] += self.k1 @@ -82,7 +82,7 @@ def testSimple(self): k1 = 1.0; k2 = 0.25 model = SimpleModel(k1, k2) t0 = 0.0; y0 = numpy.array([1.0, 0.0, 0.0], numpy.float64) - dydt0 = model.residual(t0, y0, numpy.zeros(3, numpy.float64),numpy.zeros(3, numpy.float64))[0] + dydt0 = model.residual(t0, y0, numpy.zeros(3, numpy.float64))[0] model.initialize(t0, y0, dydt0, atol=1e-16, rtol=1e-8) tmax = 100; iter = 0; maxiter = 1000