Exemple #1
0
 def _import_python(self):
     """Import Python module with right-hand-side for this model."""
     py_file = os.path.join(self.packagedir, "py.py")
     try:
         self.model = import_module(".py", self.package)
     except ImportError:
         with write_if_not_exists(os.path.join(self.packagedir, 
                                               "__init__.py")) as f:
             pass  # just create empty __init__.py to make a package
         with write_if_not_exists(os.path.join(self.packagedir, 
             self.url.rsplit("/", 1)[-1])) as f:
             f.write(urlcache(self.url))
         with write_if_not_exists(py_file) as f:
             if self.localfile:
                 f.write(urlcache(
                     "http://bebiservice.umb.no/bottle/cellml2py", 
                     data=urllib.urlencode(dict(cellml=self.cellml))))
             else:
                 f.write(
                     urlcache("http://bebiservice.umb.no/bottle/cellml2py/" 
                     + self.url))
         self.model = import_module(".py", self.package)
     try:
         with open(py_file, "rU") as f:
             self.py_code = f.read()
     except IOError:
         self.py_code = "Source file open failed"
Exemple #2
0
 def cythonize(self):
     """
     Return Cython code for this model (further hand-tweaking may be needed).
     
     This just imports and calls 
     :func:`cgp.physmod.cythonize.cythonize_model`.
     """
     modulename_cython = self.package + ".cy"
     modelname = self.hash
     modelfilename = os.path.join(self.packagedir, "cy.pyx")
     try:
         __import__(modulename_cython)
         return sys.modules[modulename_cython]
     except ImportError:
         pyx, setup = cythonize_model(self.py_code, modelname)
         pyx = urlcache("http://bebiservice.umb.no/bottle/cellml2cy", 
             data=urllib.urlencode(dict(cellml=self.cellml)))
         pyxname = modelfilename.replace("%s.py" % modelname, 
             "cython/%s/m.pyx" % modelname)
         dirname, _ = os.path.split(pyxname)
         setupname = os.path.join(dirname, "setup.py")
         # make the cython and model directories "packages"
         cyinitname = os.path.join(dirname, os.pardir, "__init__.py")
         modelinitname = os.path.join(dirname, "__init__.py")
         with write_if_not_exists(cyinitname):
             pass # just create an empty __init__.py file
         with write_if_not_exists(modelinitname):
             pass # just create an empty __init__.py file
         with open(pyxname, "w") as f:
             f.write(pyx)
         with open(setupname, "w") as f:
             f.write(setup)
         cmd = "python setup.py build_ext --inplace"
         status, output = getstatusoutput(cmd, cwd=dirname)
         # Apparently, errors fail to cause status != 0.
         # However, output does include any error messages.
         if "cannot find -lsundials_cvode" in output:
             raise OSError("Cython-compilation of ODE right-hand side "
                 "failed because SUNDIALS was not found.\n"
                 "Status code: %s\nCommand: %s\n"
                 "Output (including errors):\n%s" % (status, cmd, output))
         if status != 0:
             raise RuntimeError("'%s'\nreturned status %s:\n%s" % 
                 (cmd, status, output))
         try:
             __import__(modulename_cython)
             return sys.modules[modulename_cython]
         except StandardError, exc:
             raise ImportError("Exception raised: %s: %s\n\n"
                 "Cython compilation may have failed. "
                 "The compilation command was:\n%s\n\n"
                 "The output of the compilation command was:\n%s"
                 % (exc.__class__.__name__, exc, cmd, output))
Exemple #3
0
    def __init__(self,  # pylint: disable=W0102,E1002,R
        url=None,
        workspace=None, exposure=None, changeset=None, variant=None,
        localfile=None,  
        t=[0, 1], y=None, p=None, rename={}, use_cython=True, purge=False, 
        **kwargs):
        """
        Wrap autogenerated CellML->Python for use with pysundials
        
        M = Cellmlmodel(workspace, exposure, variant) downloads and caches 
        Python code autogenerated for the CellML model identified by the 
        (workspace, exposure, variant) triple,  and wraps it in a class with 
        convenience attributes and functions for use with pysundials.
        
        Defaults are the latest *exposure* and the first *variant* listed at 
        the cellml.org site. 

        If the non-wrapped Python code is in a local file, 
        e.g. exported from OpenCell, http://www.cellml.org/tools/opencell/ 
        use the "file://" protocol.
        
        >>> newmodel = Cellmlmodel("/newmodel", "file:c:/temp/exported.py")
        ... # doctest: +SKIP
        
        Here, "newmodel" is whatever name you'd like for the wrapper module, 
        and "exported.py" is whatever name you saved the exported code under.
        (Strictly speaking, the URL should be "file:///c:/temp/exported.py", 
        but the simpler version is also accepted by urllib.urlopen().)
        
        The constructor arguments are as follows:
        
        TODO: Update this to use (workspace, exposure, variant) as identifiers.
        
        exposure_workspace: identifiers in the repository at cellml.org,
        e.g. "732c32162c845016250f234416415bfc7601f41c/vanderpol_vandermark_1928_version01"
        for http://models.cellml.org/exposure/2224a49c6b39087dad8682648658775d.
        If only the workspace is given, will try to obtain the latest 
        workspace from the repository.
        
        urlpattern : URL to non-wrapped Python code for model, with
        %(workspace)s and %(exposure)s placeholders for e.g.
        732c32162c845016250f234416415bfc7601f41c
        vanderpol_vandermark_1928_version01
        
        t, y : as for Cvodeint
        
        p : optional parameter vector
        
        purge : (re-)download model even if the file is already present?
        
        rename : e.g. dict with possible keys "y", "p", "a", whose values are 
        mappings for renaming variables. You should rarely need this, but it is 
        useful to standardize names of parameters to be manipulated, see e.g. 
        ap_cvode.Tentusscher.__init__().
        
        use_cython: if True, wrap the model for Cython and compile.
        Cython files are placed in 
        ``$HOME/_cgptoolbox/_cellml2py/cython/modulename/``, 
        and _cellml2py.cython.modulename.modulename is used 
        in place of _cellml2py.modulename.
        
        >>> Cellmlmodel().dtype
        Dotdict({'a': None,
         'p': dtype([('epsilon', '<f8')]),
         'y': dtype([('x', '<f8'), ('y', '<f8')])})
        >>> Cellmlmodel(rename={"y": {"x": "V"}, "p": {"epsilon": "newname"}}).dtype
        Dotdict({'a': None,
         'p': dtype([('newname', '<f8')]),
         'y': dtype([('V', '<f8'), ('y', '<f8')])})
        
        See class docstring: ?Cellmlmodel for details.
        """
        if not any([url, workspace, exposure, changeset, variant, localfile]):
            url = ("http://models.cellml.org/workspace/"
                "vanderpol_vandermark_1928/@@rawfile/"
                "371151b156888430521cbf15a9cfa5e8d854cf37/"
                "vanderpol_vandermark_1928.cellml")
        self.workspace = workspace
        self.exposure = exposure
        self.changeset = changeset
        self.variant = variant
        self.localfile = localfile
        if localfile :
            self.url = guess_url(self)
        else:
            self.url = url or guess_url(self)
        self.cellml = urlcache(self.url)
        self.tree = etree.parse(StringIO(self.cellml), parser)
        try:
            self.name = etree.ETXPath("//{%s}model/@name" % cml)(self.tree)[0]
        except IndexError:
            self.name = etree.ETXPath("//{%s}model/@name" % cml.replace(
                "1.0", "1.1"))(self.tree)[0]
        self.hash = "_" + hashlib.sha1(self.cellml).hexdigest()[:6]
        self.package = "_cellml2py." + self.hash
        self.packagedir = os.path.join(cgp_tempdir, "_cellml2py", self.hash)
        if purge:
            # Won't work if this model has already been loaded
            # because files in self.packagedir will be in use.
            try:
                shutil.rmtree(self.packagedir)
            except OSError:
                pass
        _head, tail = os.path.split(self.url.strip("/"))
        with write_if_not_exists(os.path.join(self.packagedir, tail)) as f:
            f.write(self.cellml)
        if use_cython:
            self._import_cython()
        else:
            self._import_python()
        if y is None:
            y = self.model.y0
        self.legend = legend(self.model)
        dtype = dtypes(self.legend)
        # Rename fields if requested
        for i in "a", "y", "p":
            if i in rename:
                L = eval(str(dtype[i]))
                for j, (nam, typ) in enumerate(L):
                    if nam in rename[i]:
                        L[j] = (rename[i][nam], typ)
                dtype[i] = np.dtype(L)
        # if there are no parameters or algebraic variables, make empty recarray
        try:
            pr = self.model.p.view(dtype.p, np.recarray)
        except TypeError:
            pr = np.array([]).view(np.recarray)
        try:
            self.algebraic = self.model.algebraic.view(dtype.a, np.recarray)
        except TypeError:
            self.algebraic = np.array([]).view(np.recarray)
        self.y0r = self.model.y0.view(dtype.y, np.recarray)
        super(Cellmlmodel, self).__init__(self.model.ode, t, 
            y.view(dtype.y), pr, **kwargs)
        assert all(dtype[k] == self.dtype[k] for k in self.dtype)
        self.dtype.update(dtype)
        self.originals["y0r"] = self.y0r
        if p:
            self.model.p[:] = p
Exemple #4
0
mem = joblib.Memory(os.path.join(gettempdir(), "cellmlmodel"), verbose=0)

@mem.cache
def urlcache(url, data=None):
    """Cache download from URL."""
    with closing(urllib.urlopen(url, data)) as f:
        return f.read()

# Ensure that $HOME/_cgptoolbox/_cellml2py/ is a valid package directory
# This makes it easy to force re-generation of code by renaming _cellml2py/
try:
    import _cellml2py  # @UnusedImport pylint: disable=W0611,W0403
except ImportError:
    initfile = os.path.join(cgp_tempdir, "_cellml2py", "__init__.py")
    with write_if_not_exists(initfile):
        pass  # just create an empty __init__.py file

# This must be done *after* creating cgp_tempdir, 
# otherwise it gets silently ignored, cf.
# http://docs.python.org/2/using/cmdline.html#envvar-PYTHONPATH
if cgp_tempdir not in sys.path:
    sys.path.append(cgp_tempdir)

@mem.cache
def generate_code(url_or_cellml, language="python"):
    """
    Generate Python code for CellML model at url. Wraps cellml-api/testCeLEDS.
    
    Written as a replacement for the code generation at models.cellml.org, 
    which was broken at the time of writing: