Skip to content

Python bindings using pybind11

Dilawar Singh edited this page Apr 15, 2020 · 1 revision

New Python API using pybind11. This library has roughly the same syntax and boost::python but much more lightweight. I added it to MOOSE source code (removed docs and tests folder). The overall size of this library was 756 kb which is 120 Kb after compression. Till it becomes available everywhere, we keep it in the source.

Summary

Parameter Current API New API Comment
Binary Size 23 Mb 15 MB 65% of original, 8MB savings.
Source code size 8556 L, 28955 W, 288288 C 2002 L, 6134 W, 64017 C ~23% or original
Compilation No dependencies No dependencies, pybind11 is in source tree 800 Kb addition to source code. The package are not available in centos yet (https://repology.org/project/python:pybind11/versions)
Compiler Any c++11 compliant Any c++11 comliant No change, though c++17 features will make bindings even shorter.
PyRun Using Python-C API Same as before. Pybind11 does not have subiterpreter support yet.

TODO

  • CTRL+C should stop the simulation immediately.
  • Support num assignment on Finfo.

Changes in behaviour

What Current behaviour New Behaviour Comment
Stoch::path is deprecated. Replaced with Stoich::reacSystemPath finds object under the given path and assign them to Stoich Same. Collision with normal path attribute of object.
Field/Finfo can not be treated as vec without explicitly converting them to vec.
print(func.x.value)

xs = func.x.vec
print(xs.value)
This is used rarely but it used in places. This is a breaking change in API.
a = moose.Pool('a'); b = moose.Neutral('a') Allows with a warning Raises exception, asks user to use moose.element('a')
a=moose.Pool('a');b=moose.vec('a') Works Raises exception because ‘a’ already exists
a=moose.Pool('a'); b=moose.vec(a) Works Works
moose.melement Removed
Subclassing moose.Pool etc. Possible, dynamic attribute works. For example, declare a = MyPool('a') where MyPool subclasses moose.Pool now a.temperature = 12.3 is possible even though temperature is not an attribute of moose.Pool This is now not possible without some trickery Trying to resolve. Example script https://github.com/BhallaLab/moose-examples/blob/master/squid/squid.py

Micro benchmarks

Current bindings New bindings
/home1/dilawars/Work/GITHUB/DILAWAR/moose-core/_build/python/moose/__init__.py
- Timeit: import moose
10000000 loops, best of 3: 0.123 usec per loop
- Timeit: a=moose.Neutral(‘a’);moose.delete(a)
100000 loops, best of 3: 12.2 usec per loop
- Timeit: a=moose.Neutral(‘a’, 10000);moose.delete(a)
10000 loops, best of 3: 34.4 usec per loop
- Timeit: a1=moose.Neutral(‘a’);a2=moose.element(a1);a1==a2;moose.delete(a1)
100000 loops, best of 3: 18 usec per loop
/home1/dilawars/Work/GITLAB/moose-core/_build/python/moose/__init__.py
- Timeit: import moose
10000000 loops, best of 3: 0.128 usec per loop
- Timeit: a=moose.Neutral(‘a’);moose.delete(a)
100000 loops, best of 3: 12.3 usec per loop
- Timeit: a=moose.Neutral(‘a’, 10000);moose.delete(a)
10000 loops, best of 3: 31.6 usec per loop
- Timeit: a1=moose.Neutral(‘a’);a2=moose.element(a1);a1==a2;moose.delete(a1)
10000 loops, best of 3: 22.6 usec per loop

No change in the API but there are some extra goodies

The old API remains intact. No change is needed in any MOOSE scripts. Though there are extra goodies.

  1. Instaed of saying moose.connect(src, srcf, tgt, tgtf), one can also say src.connect(srcf, tgt, tgtf) and even src[srcf].connect(tgt, tgtf) and even src[srcf].connect(tgt[tgtf]). Last two are still experimental.

    • Helpful message when moose.connect fails due to type incpaitbility of src and target mismatch.
  2. Instead of saying moose.delete(a) one can also say del a.

del a acts are moose.delete(a). Note that semantic of del is different here (overridden by overloading __del__) (alpha).

MOOSE internal state can be pickled (alpha)

After loading a model, one can pickle it to a binary file and load it again into python. (In development).

Documentation is generated by pybind11

The documentation related code is gone from the new API. help(moose) generates are following by using the function signature and comments provided in the binding itself.

This is a work in progress.

Following examples shows the ability to generate docstring out of box. Note that I’ve not added a single line of documentation yet one can make quite a lot of sense out of it.

>>> help(moose)

Help on package moose:

NAME
    moose - # -*- coding: utf-8 -*-

PACKAGE CONTENTS
    SBML (package)
    _cmoose
    _moose
    chemMerge (package)
    chemUtil (package)
    constants
    fixXreacs
    genesis (package)
    hdfutil
    helper
    methods_utils
    model_utils
    moose
    moose_constants
    moose_test
    network_utils
    neuroml (package)
    neuroml2 (package)
    optimizer_interface
    plot_utils
    print_utils
    recording
    server
    streamer_utils
    utils
    wrapper

SUBMODULES
    mu

FUNCTIONS
    create(...) method of builtins.PyCapsule instance
        create(arg0: str, arg1: str, arg2: int) -> moose._moose._ObjId
    
    delete(...) method of builtins.PyCapsule instance
        delete(*args, **kwargs)
        Overloaded function.
        
        1. delete(arg0: moose._moose._ObjId) -> bool
        
        2. delete(arg0: str) -> bool
    
    exists(...) method of builtins.PyCapsule instance
        exists(arg0: str) -> bool
    
    getField(...) method of builtins.PyCapsule instance
        getField(el: moose._moose._ObjId, fieldname: str, ftype: str = '') -> object
    
    getFieldDict(...) method of builtins.PyCapsule instance
        getFieldDict(className: str, finfoType: str = '') -> Dict[str, str]
    
    getFieldNames(...) method of builtins.PyCapsule instance
        getFieldNames(arg0: str, arg1: str) -> List[str]
    
    getShell(...) method of builtins.PyCapsule instance
        getShell() -> Shell
    
    loadModelInternal(...) method of builtins.PyCapsule instance
        loadModelInternal(arg0: str, arg1: str, arg2: str) -> moose._moose._ObjId
    
    move(...) method of builtins.PyCapsule instance
        move(*args, **kwargs)
        Overloaded function.
        
        1. move(arg0: moose._moose._Id, arg1: moose._moose._ObjId) -> None
        
        2. move(arg0: moose._moose._ObjId, arg1: moose._moose._ObjId) -> None
    
    objid(...) method of builtins.PyCapsule instance
        objid(arg0: str) -> moose._moose._ObjId
    
    rand(...) method of builtins.PyCapsule instance
        rand(a: float = 0, b: float = 1) -> float
    
    reinit(...) method of builtins.PyCapsule instance
        reinit() -> None
    
    seed(...) method of builtins.PyCapsule instance
        seed(arg0: int) -> None
    
    setClock(...) method of builtins.PyCapsule instance
        setClock(arg0: int, arg1: float) -> None
    
    setCwe(...) method of builtins.PyCapsule instance
        setCwe(arg0: moose._moose._ObjId) -> None
    
    start(...) method of builtins.PyCapsule instance
        start(runtime: float, notify: bool = False) -> None
    
    stop(...) method of builtins.PyCapsule instance
        stop() -> None
    
    useClock(...) method of builtins.PyCapsule instance
        useClock(arg0: int, arg1: str, arg2: str) -> None

DATA
    FaradayConst = 96485.3415
    GasConst = 8.3144621
    NA = 6.0221415e+23
    PI = 3.141592653589793
    absolute_import = _Feature((2, 5, 0, 'alpha', 1), (3, 0, 0, 'alpha', 0...
    chemError_ = ''
    chemImport_ = True
    division = _Feature((2, 2, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 8192...
    finfotypes = [('valueFinfo', 'value field'), ('srcFinfo', 'source mess...
    kkitImport_ = True
    kkitImport_error_ = ''
    logger_ = <Logger moose.model (INFO)>
    mergechemError_ = ''
    mergechemImport_ = True
    nml2ImportError_ = ''
    nml2Import_ = True
    p = <moose.Cinfo id=131 dataIndex=0 path=/classes[0]/testSched[0]>
    print_function = _Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0)...
    sbmlError_ = ''
    sbmlImport_ = True

VERSION
    3.2.1.dev20200405

FILE
    /home/dilawars/Work/GITLAB/moose-core/_build/python/moose/__init__.py

Another example:

>>> help(moose.Pool)

Help on class Pool in moose:

moose.Pool = class Pool(PyObjId)
 |  Method resolution order:
 |      Pool
 |      PyObjId
 |      moose._moose._ObjId
 |      pybind11_builtins.pybind11_object
 |      builtins.object
 |  
 |  Data and other attributes defined here:
 |  
 |  __class__ = <class 'pybind11_builtins.pybind11_type'>
 |      type(object_or_name, bases, dict)
 |      type(object) -> the object's type
 |      type(name, bases, dict) -> a new type
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from PyObjId:
 |  
 |  __init__(self, x, ndata=1, **kwargs)
 |      __init__(*args, **kwargs)
 |      Overloaded function.
 |      
 |      1. __init__(self: moose._moose._ObjId) -> None
 |      
 |      2. __init__(self: moose._moose._ObjId, arg0: moose._moose._Id) -> None
 |      
 |      3. __init__(self: moose._moose._ObjId, arg0: moose._moose._Id, arg1: int) -> None
 |      
 |      4. __init__(self: moose._moose._ObjId, arg0: moose._moose._Id, arg1: int, arg2: int) -> None
 |      
 |      5. __init__(self: moose._moose._ObjId, arg0: str) -> None
 |  
 |  ----------------------------------------------------------------------
 |  Class methods inherited from PyObjId:
 |  
 |  toMooseClass(obj) from pybind11_builtins.pybind11_type
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from PyObjId:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from moose._moose._ObjId:
 |  
 |  __eq__(...)
 |      __eq__(self: moose._moose._ObjId, arg0: moose._moose._ObjId) -> bool
 |  
 |  __getattr__(...)
 |      __getattr__(self: moose._moose._ObjId, arg0: str) -> object
 |  
 |  __ne__(...)
 |      __ne__(self: moose._moose._ObjId, arg0: moose._moose._ObjId) -> bool
 |  
 |  __repr__(...)
 |      __repr__(self: moose._moose._ObjId) -> str
 |  
 |  __setattr__(...)
 |      __setattr__(self: moose._moose._ObjId, arg0: str, arg1: object) -> bool
 |  
 |  connect(...)
 |      connect(*args, **kwargs)
 |      Overloaded function.
 |      
 |      1. connect(self: moose._moose._ObjId, arg0: str, arg1: moose._moose._ObjId, arg2: str, arg3: str) -> moose._moose._ObjId
 |      
 |      2. connect(self: moose._moose._ObjId, arg0: str, arg1: MooseVec, arg2: str, arg3: str) -> moose._moose._ObjId
 |  
 |  getField(...)
 |      getField(self: moose._moose._ObjId, arg0: str) -> object
 |  
 |  setField(...)
 |      setField(self: moose._moose._ObjId, arg0: str, arg1: object) -> bool
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from moose._moose._ObjId:
 |  
 |  className
 |  
 |  dataIndex
 |  
 |  id
 |  
 |  name
 |  
 |  parent
 |  
 |  path
 |  
 |  type
 |  
 |  vec
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from pybind11_builtins.pybind11_object:
 |  
 |  __new__(*args, **kwargs) from pybind11_builtins.pybind11_type
 |      Create and return a new object.  See help(type) for accurate signature.

Now the focus is on to improve this documentation by adding helpful hints and docstrings here and there.

Maintainability

The new bindings are much more maintainable than the previous one. The simplest measure is the line of code. The new binding are 1/4 of size by that measure.

Current bindings New bindings
[dilawars@chamcham _build (pybind11)]$ wc …/pymoose/*
380 1245 14341 …/pymoose/CMakeCache.txt
wc: …/pymoose/CMakeFiles: Is a directory
0 0 0 …/pymoose/CMakeFiles
141 387 4869 …/pymoose/CMakeLists.txt
2173 7403 75394 …/pymoose/melement.cpp
16 38 462 …/pymoose/melement.h
1101 3300 36651 …/pymoose/mfield.cpp
16 38 460 …/pymoose/mfield.h
2683 9375 90593 …/pymoose/moosemodule.cpp
734 2824 25888 …/pymoose/moosemodule.h
101 285 2912 …/pymoose/pymooseinit.cpp
16 38 465 …/pymoose/pymooseinit.h
347 937 9750 …/pymoose/PyRun.cpp
88 274 2260 …/pymoose/PyRun.h
101 275 2526 …/pymoose/test_moosemodule.cpp
1056 3836 36724 …/pymoose/vec.cpp
8953 30255 303295 total
[dilawars@chamcham _build (pybind11)]$ wc …/pybind11/*
48 96 1576 …/pybind11/CMakeLists.txt
311 1041 10687 …/pybind11/Finfo.cpp
105 332 3855 …/pybind11/Finfo.h
409 1307 12488 …/pybind11/helper.cpp
79 230 2265 …/pybind11/helper.h
3 4 44 …/pybind11/__init__.py
132 350 3183 …/pybind11/MooseVec.cpp
61 150 1353 …/pybind11/MooseVec.h
368 1256 15135 …/pybind11/pymoose.cpp
51 157 1421 …/pybind11/pymoose.h
347 937 9750 …/pybind11/PyRun.cpp
88 274 2260 …/pybind11/PyRun.h
2002 6134 64017 total

Test suite

Whole test suite passes. On gulgula, Centos-9. GCC-9.1. We managed to save 6 secs on the test-suite. Yay!

Current bindings New bindings/tr>
Test project /home1/dilawars/Work/GITHUB/DILAWAR/moose-core/_build
Start 1: core_test_GraupnerBrunel2012_STDPfromCaPlasticity
1/65 Test #1: core_test_GraupnerBrunel2012_STDPfromCaPlasticity … Passed 8.16 sec
Start 2: core_test_Xchan1
2/65 Test #2: core_test_Xchan1 … Passed 0.72 sec
Start 3: core_test_Xdiff1
3/65 Test #3: core_test_Xdiff1 … Passed 0.80 sec
Start 4: core_test_Xenz1
4/65 Test #4: core_test_Xenz1 … Passed 1.07 sec
Start 5: core_test_Xreacs2
5/65 Test #5: core_test_Xreacs2 … Passed 1.18 sec
Start 6: core_test_Xreacs3
6/65 Test #6: core_test_Xreacs3 … Passed 0.74 sec
Start 7: core_test_Xreacs4
7/65 Test #7: core_test_Xreacs4 … Passed 0.59 sec
Start 8: core_test_Xreacs4a
8/65 Test #8: core_test_Xreacs4a … Passed 0.63 sec
Start 9: core_test_Xreacs5
9/65 Test #9: core_test_Xreacs5 … Passed 0.83 sec
Start 10: core_test_Xreacs5a
10/65 Test #10: core_test_Xreacs5a … Passed 0.59 sec
Start 11: core_test_Xreacs6
11/65 Test #11: core_test_Xreacs6 … Passed 0.60 sec
Start 12: core_test_Xreacs7
12/65 Test #12: core_test_Xreacs7 … Passed 0.59 sec
Start 13: core_test_Xreacs8
13/65 Test #13: core_test_Xreacs8 … Passed 0.75 sec
Start 14: core_test_accessing_existing_paths
14/65 Test #14: core_test_accessing_existing_paths … Passed 0.80 sec
Start 15: core_test_connectionLists
15/65 Test #15: core_test_connectionLists … Passed 1.02 sec
Start 16: core_test_cylinder_diffusion_gsolve+dsolve
16/65 Test #16: core_test_cylinder_diffusion_gsolve+dsolve … Passed 11.59 sec
Start 17: core_test_difshells
17/65 Test #17: core_test_difshells … Passed 1.16 sec
Start 18: core_test_docs
18/65 Test #18: core_test_docs … Passed 0.74 sec
Start 19: core_test_dose_response
19/65 Test #19: core_test_dose_response … Passed 2.72 sec
Start 20: core_test_expr_parser
20/65 Test #20: core_test_expr_parser … Passed 1.00 sec
Start 21: core_test_function
21/65 Test #21: core_test_function … Passed 0.61 sec
Start 22: core_test_function_chemsys
22/65 Test #22: core_test_function_chemsys … Passed 0.80 sec
Start 23: core_test_function_controls_reac_rate
23/65 Test #23: core_test_function_controls_reac_rate … Passed 0.64 sec
Start 24: core_test_function_namedvars
24/65 Test #24: core_test_function_namedvars … Passed 0.63 sec
Start 25: core_test_gsolve_parallel
25/65 Test #25: core_test_gsolve_parallel … Passed 10.60 sec
Start 26: core_test_hsolve_externalCalcium
26/65 Test #26: core_test_hsolve_externalCalcium … Passed 3.21 sec
Start 27: core_test_kkit
27/65 Test #27: core_test_kkit … Passed 0.72 sec
Start 28: core_test_ksolve
28/65 Test #28: core_test_ksolve … Passed 0.76 sec
Start 29: core_test_ksolve_parallel
29/65 Test #29: core_test_ksolve_parallel … Passed 9.66 sec
Start 30: core_test_moose_attribs
30/65 Test #30: core_test_moose_attribs … Passed 0.63 sec
Start 31: core_test_moose_paths
31/65 Test #31: core_test_moose_paths … Passed 0.76 sec
Start 32: core_test_negative_value_flag
32/65 Test #32: core_test_negative_value_flag … Passed 0.99 sec
Start 33: core_test_pymoose_1
33/65 Test #33: core_test_pymoose_1 … Passed 0.68 sec
Start 34: core_test_pymoose_2
34/65 Test #34: core_test_pymoose_2 … Passed 0.75 sec
Start 35: core_test_random_num
35/65 Test #35: core_test_random_num … Passed 0.81 sec
Start 36: core_test_rdesigneur
36/65 Test #36: core_test_rdesigneur … Passed 0.81 sec
Start 37: core_test_rdesigneur_random_syn_input
37/65 Test #37: core_test_rdesigneur_random_syn_input … Passed 0.84 sec
Start 38: core_test_steady_state_solver
38/65 Test #38: core_test_steady_state_solver … Passed 1.35 sec
Start 39: core_test_streamer
39/65 Test #39: core_test_streamer … Passed 1.26 sec
Start 40: core_test_switch_solvers
40/65 Test #40: core_test_switch_solvers … Passed 0.82 sec
Start 41: core_test_synchan
41/65 Test #41: core_test_synchan … Passed 0.78 sec
Start 42: core_test_table_streaming_support
42/65 Test #42: core_test_table_streaming_support … Passed 1.75 sec
Start 43: core_test_vec
43/65 Test #43: core_test_vec … Passed 0.74 sec
Start 44: core_test_wrapper
44/65 Test #44: core_test_wrapper … Passed 0.75 sec
Start 45: support_test_hhfit
45/65 Test #45: support_test_hhfit … Passed 3.28 sec
Start 46: support_test_neuroml
46/65 Test #46: support_test_neuroml … Passed 2.90 sec
Start 47: support_test_neuroml2
47/65 Test #47: support_test_neuroml2 … Passed 0.74 sec
Start 48: support_test_nsdf
48/65 Test #48: support_test_nsdf … Passed 0.75 sec
Start 49: support_test_sbml
49/65 Test #49: support_test_sbml … Passed 0.68 sec
Start 50: rdes_test_1_minimalModel
50/65 Test #50: rdes_test_1_minimalModel … Passed 0.78 sec
Start 51: rdes_test_20_currentPulse
51/65 Test #51: rdes_test_20_currentPulse … Passed 0.77 sec
Start 52: rdes_test_21_vclamp
52/65 Test #52: rdes_test_21_vclamp … Passed 0.78 sec
Start 53: rdes_test_30_squid_currentPulse
53/65 Test #53: rdes_test_30_squid_currentPulse … Passed 0.60 sec
Start 54: rdes_test_32_squid_axon_propgn
54/65 Test #54: rdes_test_32_squid_axon_propgn … Passed 0.92 sec
Start 55: rdes_test_41_ballAndStick
55/65 Test #55: rdes_test_41_ballAndStick … Passed 0.82 sec
Start 56: rdes_test_51_periodic_syn_input
56/65 Test #56: rdes_test_51_periodic_syn_input … Passed 0.60 sec
Start 57: rdes_test_6_chem_osc
57/65 Test #57: rdes_test_6_chem_osc … Passed 0.59 sec
Start 58: rdes_test_72_CICR
58/65 Test #58: rdes_test_72_CICR … Passed 1.83 sec
Start 59: rdes_test_74_travelling_osc
59/65 Test #59: rdes_test_74_travelling_osc … Passed 3.90 sec
Start 60: rdes_test_76_func_func_control_reac_rates
60/65 Test #60: rdes_test_76_func_func_control_reac_rates … Passed 0.59 sec
Start 61: rdes_test_rdes_with_func_proto
61/65 Test #61: rdes_test_rdes_with_func_proto … Passed 0.67 sec
Start 62: cpp_test_normal_dist
62/65 Test #62: cpp_test_normal_dist … Passed 0.01 sec
Start 63: cpp_test_cnpy
63/65 Test #63: cpp_test_cnpy … Passed 0.00 sec
Start 64: cpp_test_lsoda
64/65 Test #64: cpp_test_lsoda … Passed 0.00 sec
Start 65: cpp_test_benchmark
65/65 Test #65: cpp_test_benchmark … Passed 4.43 sec

100% tests passed, 0 tests failed out of 65

Total Test time (real) = 103.31 sec
Test project /home1/dilawars/Work/GITLAB/moose-core/_build
Start 1: core_test_GraupnerBrunel2012_STDPfromCaPlasticity
1/64 Test #1: core_test_GraupnerBrunel2012_STDPfromCaPlasticity … Passed 7.73 sec
Start 2: core_test_Xchan1
2/64 Test #2: core_test_Xchan1 … Passed 0.77 sec
Start 3: core_test_Xdiff1
3/64 Test #3: core_test_Xdiff1 … Passed 0.65 sec
Start 4: core_test_Xenz1
4/64 Test #4: core_test_Xenz1 … Passed 0.83 sec
Start 5: core_test_Xreacs2
5/64 Test #5: core_test_Xreacs2 … Passed 0.95 sec
Start 6: core_test_Xreacs3
6/64 Test #6: core_test_Xreacs3 … Passed 0.57 sec
Start 7: core_test_Xreacs4
7/64 Test #7: core_test_Xreacs4 … Passed 0.56 sec
Start 8: core_test_Xreacs4a
8/64 Test #8: core_test_Xreacs4a … Passed 0.57 sec
Start 9: core_test_Xreacs5
9/64 Test #9: core_test_Xreacs5 … Passed 0.82 sec
Start 10: core_test_Xreacs5a
10/64 Test #10: core_test_Xreacs5a … Passed 0.57 sec
Start 11: core_test_Xreacs6
11/64 Test #11: core_test_Xreacs6 … Passed 0.58 sec
Start 12: core_test_Xreacs7
12/64 Test #12: core_test_Xreacs7 … Passed 0.59 sec
Start 13: core_test_Xreacs8
13/64 Test #13: core_test_Xreacs8 … Passed 0.61 sec
Start 14: core_test_accessing_existing_paths
14/64 Test #14: core_test_accessing_existing_paths … Passed 0.72 sec
Start 15: core_test_api
15/64 Test #15: core_test_api … Passed 0.82 sec
Start 16: core_test_connectionLists
16/64 Test #16: core_test_connectionLists … Passed 1.12 sec
Start 17: core_test_cylinder_diffusion_gsolve+dsolve
17/64 Test #17: core_test_cylinder_diffusion_gsolve+dsolve … Passed 11.98 sec
Start 18: core_test_difshells
18/64 Test #18: core_test_difshells … Passed 1.07 sec
Start 19: core_test_docs
19/64 Test #19: core_test_docs … Passed 0.56 sec
Start 20: core_test_dose_response
20/64 Test #20: core_test_dose_response … Passed 2.16 sec
Start 21: core_test_expr_parser
21/64 Test #21: core_test_expr_parser … Passed 0.78 sec
Start 22: core_test_function
22/64 Test #22: core_test_function … Passed 0.59 sec
Start 23: core_test_function_chemsys
23/64 Test #23: core_test_function_chemsys … Passed 0.82 sec
Start 24: core_test_function_controls_reac_rate
24/64 Test #24: core_test_function_controls_reac_rate … Passed 0.63 sec
Start 25: core_test_gsolve_parallel
25/64 Test #25: core_test_gsolve_parallel … Passed 4.96 sec
Start 26: core_test_hsolve_externalCalcium
26/64 Test #26: core_test_hsolve_externalCalcium … Passed 3.17 sec
Start 27: core_test_kkit
27/64 Test #27: core_test_kkit … Passed 0.60 sec
Start 28: core_test_ksolve
28/64 Test #28: core_test_ksolve … Passed 0.70 sec
Start 29: core_test_ksolve_parallel
29/64 Test #29: core_test_ksolve_parallel … Passed 9.73 sec
Start 30: core_test_moose_attribs
30/64 Test #30: core_test_moose_attribs … Passed 0.64 sec
Start 31: core_test_moose_paths
31/64 Test #31: core_test_moose_paths … Passed 0.73 sec
Start 32: core_test_negative_value_flag
32/64 Test #32: core_test_negative_value_flag … Passed 0.79 sec
Start 33: core_test_random_num
33/64 Test #33: core_test_random_num … Passed 0.56 sec
Start 34: core_test_rdesigneur
34/64 Test #34: core_test_rdesigneur … Passed 0.58 sec
Start 35: core_test_rdesigneur_random_syn_input
35/64 Test #35: core_test_rdesigneur_random_syn_input … Passed 0.62 sec
Start 36: core_test_steady_state_solver
36/64 Test #36: core_test_steady_state_solver … Passed 1.38 sec
Start 37: core_test_streamer
37/64 Test #37: core_test_streamer … Passed 1.26 sec
Start 38: core_test_suit1
38/64 Test #38: core_test_suit1 … Passed 0.68 sec
Start 39: core_test_switch_solvers
39/64 Test #39: core_test_switch_solvers … Passed 0.75 sec
Start 40: core_test_synchan
40/64 Test #40: core_test_synchan … Passed 0.70 sec
Start 41: core_test_table_streaming_support
41/64 Test #41: core_test_table_streaming_support … Passed 1.71 sec
Start 42: core_test_vec
42/64 Test #42: core_test_vec … Passed 0.70 sec
Start 43: support_test_hhfit
43/64 Test #43: support_test_hhfit … Passed 3.12 sec
Start 44: support_test_neuroml
44/64 Test #44: support_test_neuroml … Passed 2.90 sec
Start 45: support_test_neuroml2
45/64 Test #45: support_test_neuroml2 … Passed 0.78 sec
Start 46: support_test_nsdf
46/64 Test #46: support_test_nsdf … Passed 0.75 sec
Start 47: support_test_sbml
47/64 Test #47: support_test_sbml … Passed 0.79 sec
Start 48: rdes_test_1_minimalModel
48/64 Test #48: rdes_test_1_minimalModel … Passed 0.80 sec
Start 49: rdes_test_20_currentPulse
49/64 Test #49: rdes_test_20_currentPulse … Passed 0.67 sec
Start 50: rdes_test_21_vclamp
50/64 Test #50: rdes_test_21_vclamp … Passed 0.66 sec
Start 51: rdes_test_30_squid_currentPulse
51/64 Test #51: rdes_test_30_squid_currentPulse … Passed 0.59 sec
Start 52: rdes_test_32_squid_axon_propgn
52/64 Test #52: rdes_test_32_squid_axon_propgn … Passed 0.95 sec
Start 53: rdes_test_41_ballAndStick
53/64 Test #53: rdes_test_41_ballAndStick … Passed 1.06 sec
Start 54: rdes_test_51_periodic_syn_input
54/64 Test #54: rdes_test_51_periodic_syn_input … Passed 0.78 sec
Start 55: rdes_test_6_chem_osc
55/64 Test #55: rdes_test_6_chem_osc … Passed 0.62 sec
Start 56: rdes_test_72_CICR
56/64 Test #56: rdes_test_72_CICR … Passed 1.90 sec
Start 57: rdes_test_74_travelling_osc
57/64 Test #57: rdes_test_74_travelling_osc … Passed 4.34 sec
Start 58: rdes_test_76_func_func_control_reac_rates
58/64 Test #58: rdes_test_76_func_func_control_reac_rates … Passed 0.68 sec
Start 59: rdes_test_rdes_with_func_proto
59/64 Test #59: rdes_test_rdes_with_func_proto … Passed 0.83 sec
Start 60: cpp_test_globals
60/64 Test #60: cpp_test_globals … Passed 0.00 sec
Start 61: cpp_test_normal_dist
61/64 Test #61: cpp_test_normal_dist … Passed 0.01 sec
Start 62: cpp_test_cnpy
62/64 Test #62: cpp_test_cnpy … Passed 0.00 sec
Start 63: cpp_test_lsoda
63/64 Test #63: cpp_test_lsoda … Passed 0.00 sec
Start 64: cpp_test_benchmark
64/64 Test #64: cpp_test_benchmark … Passed 5.11 sec

100% tests passed, 0 tests failed out of 64

Total Test time (real) = 94.68 sec

Technical details

Expose ObjId and Finfo

ObjId is the base class for everything else. obj->element()->cinfo() provides the Type info of this object. Finfo class is also exposed to python. Rest of the api is built over using these two.

Benchmarks

Loading moose

  • CURRENT: 10 loops, best of 3: 0.219 usec per loop
  • NEW: 128 ns ± 0.0837 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

There is a difference in size of module (23 MB old vs 15 MB new incomplete).

Create new elements

>>> %timeit a=moose.Neutral('/a'); moose.delete(a)

CURRENT: 2.14 ms ± 270 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) NEW: 9.38 µs ± 42.7 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

>>> %timeit a = moose.Neutral('/a', 1000); moose.delete(a)

CURRENT: 1.92 ms ± 251 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) NEW: 11.4 µs ± 42.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)