Skip to content

Commit

Permalink
#58 : add support for lyap task
Browse files Browse the repository at this point in the history
  • Loading branch information
fbergmann committed Aug 28, 2024
1 parent e98edc9 commit 122e975
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 0 deletions.
1 change: 1 addition & 0 deletions basico/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .task_optimization import *
from .task_sensitivities import *
from .task_mca import *
from .task_lyapunov import *

from .compartment_array_tools import *

Expand Down
118 changes: 118 additions & 0 deletions basico/task_lyapunov.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
""" Utility methods for working with the Lyapunov task
"""

import logging
from math import e
import basico
import COPASI

from . import model_io

logger = logging.getLogger(__name__)


def run_lyapunov(**kwargs):
"""Runs the lyapunov task, the result is obtained
by calling:
* `get_lyapunov_exponents`
:param kwargs: optional arguments
- | `model`: to specify the data model to be used (if not specified
| the one from :func:`.get_current_model` will be taken)
- | `num_exponents`: number of exponents to calculate (default: 3)
- | `calculate_convergence`: boolean flag indicating whether the divergence should be calculated (default: True)
- | `start_averaging_after`: time after which the averaging should start (default: disabled = 0)
- | `settings`: a dictionary with the settings to apply first
- | `use_initial_values`: boolean flag indicating whether initial values should be used (true by default)
Example:
.. code-block:: python
>>> load_example('brusselator')
>>> exponents, sums, divergence = run_lyapunov(num_exponents=2)
>>> print(exponents)
[-0.0007025645113957691, -2.6051942604518477]
:return: tuple of exponents, sum of exponents and average divergence
"""
model = model_io.get_model_from_dict_or_default(kwargs)
assert (isinstance(model, COPASI.CDataModel))

model.getModel().compileIfNecessary()

if 'settings' in kwargs:
basico.set_task_settings(basico.T.LYAPUNOV_EXPONENTS, kwargs['settings'], model=model)

task = model.getTask(basico.T.LYAPUNOV_EXPONENTS)
assert (isinstance(task, COPASI.CLyapTask))

problem = task.getProblem()
assert (isinstance(problem, COPASI.CLyapProblem))

if 'num_exponents' in kwargs:
problem.setExponentNumber(int(kwargs['num_exponents']))

if 'calculate_convergence' in kwargs:
problem.setDivergenceRequested(bool(kwargs['calculate_convergence']))

if 'start_averaging_after' in kwargs:
problem.setTransientTime(float(kwargs['start_averaging_after']))

if not task.initializeRaw(COPASI.CCopasiTask.OUTPUT_UI):
logger.error('Could not initialize Lyapunov Task: {0}'.format(COPASI.CCopasiMessage.getAllMessageText()))
return

use_initial_values = kwargs.get('use_initial_values', True)

if not task.processRaw(use_initial_values):
logger.error('Could not run Lyapunov Task: {0}'.format(COPASI.CCopasiMessage.getAllMessageText()))
return

task.restore()

return get_lyapunov_exponents(model=model)


def get_lyapunov_exponents(**kwargs):
"""Returns the lyapunov exponents calclated last time `run_lyapunov` was called
:param kwargs: optional arguments
- | `model`: to specify the data model to be used (if not specified
| the one from :func:`.get_current_model` will be taken)
:return: a tuple of exponent, sum of exponents and average divergence
"""
model = model_io.get_model_from_dict_or_default(kwargs)

assert (isinstance(model, COPASI.CDataModel))

task = model.getTask(basico.T.LYAPUNOV_EXPONENTS)
assert (isinstance(task, COPASI.CLyapTask))


problem = task.getProblem()
assert (isinstance(problem, COPASI.CLyapProblem))

num_exponents = task.numberOfExponentsCalculated()
exponent_vec = task.exponents()
exponents = []

for i in range(num_exponents):
exponents.append(exponent_vec.get(i))

sum_exponents = task.sumOfExponents()

average_divergence = task.averageDivergence()

return exponents, sum_exponents, average_divergence
15 changes: 15 additions & 0 deletions tests/test_lyap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from math import exp
import unittest
import basico

class TestLyap(unittest.TestCase):
def test_lyap(self):
dm = basico.load_example('brusselator')
self.assertIsNotNone(dm)
exponents, sums, divergence = basico.run_lyapunov(num_exponents=2)
self.assertIsNotNone(len(exponents), 2)
self.assertAlmostEqual(sums, (exponents[0] + exponents[1]))
basico.remove_datamodel(dm)

if __name__ == '__main__':
unittest.main()

0 comments on commit 122e975

Please sign in to comment.