1
2
3
4
5 from __future__ import division
6
7 import copy
8 import sets
9 import types
10 import time
11 import os
12 import sys
13 import operator
14
15 import logging
16 logger = logging.getLogger('ReactionNetworks.Network_mod')
17
18 import scipy
19 import math
20
21 import SloppyCell
22 import SloppyCell.Utility as Utility
23 import SloppyCell.KeyedList_mod
24 KeyedList = SloppyCell.KeyedList_mod.KeyedList
25
26 import SloppyCell.ExprManip as ExprManip
27
28 ExprManip.load_derivs(os.path.join(SloppyCell._TEMP_DIR, 'diff.pickle'))
29
30
31 if SloppyCell.my_rank == 0:
32 import atexit
33 atexit.register(ExprManip.save_derivs, os.path.join(SloppyCell._TEMP_DIR,
34 'diff.pickle'))
35
36 import Reactions
37 from Components import *
38 import Dynamics
39 import Trajectory_mod
40
41 _double_max_ = scipy.finfo(scipy.float_).max
42 _double_tiny_ = scipy.finfo(scipy.float_).tiny
43
45
46
47
48
49 _dynamic_structure_methods = ['_make_res_function',
50 '_make_alg_deriv_func',
51 '_make_alg_res_func',
52 '_make_dres_dc_function',
53 '_make_dres_dcdot_function',
54 '_make_ddaskr_jac',
55 '_make_dres_dsinglep',
56 '_make_sens_rhs',
57 '_make_log_funcs',
58 '_make_integrate_stochastic_tidbit'
59 ]
60 _dynamic_event_methods = ['_make_root_func']
61
62
63 _common_namespace = {'log': scipy.log,
64 'log10': scipy.log10,
65 'exp': math.exp,
66 'cos': math.cos,
67 'sin': math.sin,
68 'tan': math.tan,
69 'acos': math.acos,
70 'asin': math.asin,
71 'atan': math.atan,
72 'cosh': math.cosh,
73 'sinh': math.sinh,
74 'tanh': math.tanh,
75
76
77
78
79
80 'pow': math.pow,
81 'sqrt': math.sqrt,
82 'exponentiale': math.e,
83 'pi': math.pi,
84 'scipy': scipy,
85 'operator': operator,
86 }
87
88 _standard_func_defs = [('root', ['n', 'x'], 'x**(1./n)'),
89 ('cot', ['x'], '1./tan(x)'),
90 ('arccot', ['x'], 'atan(1/x)'),
91 ('coth', ['x'], '1./tanh(x)'),
92
93 ('csc', ['x'], '1./sin(x)'),
94 ('arccsc', ['x'], 'asin(1./x)'),
95 ('csch', ['x'], '1./sinh(x)'),
96
97 ('sec', ['x'], '1./cos(x)'),
98 ('arcsec', ['x'], 'acos(1./x)'),
99 ('sech', ['x'], '1./cosh(x)'),
100
101 ]
102
103 _logical_comp_func_defs = [('gt', ['x', 'y'], 'x > y'),
104 ('geq', ['x', 'y'], 'x >= y'),
105 ('lt', ['x', 'y'], 'x < y'),
106 ('leq', ['x', 'y'], 'x <= y'),
107 ('eq', ['x', 'y'], 'y == x'),
108 ('not_func', ['x'], 'not x'),
109 ('and_func', '*', 'x and y'),
110 ('or_func', '*', 'x or y'),
111 ]
112
113
114
115
116
117
118
119 _common_func_strs = KeyedList()
120 for id, vars, math in _standard_func_defs:
121 var_str = ','.join(vars)
122 func = 'lambda %s: %s' % (var_str, math)
123 _common_func_strs.set(id, func)
124
125 for ii, wrt in enumerate(vars):
126 deriv_id = '%s_%i' % (id, ii)
127 diff_math = ExprManip.diff_expr(math, wrt)
128 func = 'lambda %s: %s' % (var_str, diff_math)
129 _common_func_strs.set(deriv_id, func)
130
131
132 _common_func_strs_c = KeyedList()
133 _common_prototypes_c = KeyedList()
134 for id, vars, math in _standard_func_defs:
135 vars_c = ['double %s' % var for var in vars]
136 var_str_c = ','.join(vars_c)
137 c_body = []
138 c_body.append('double %s(%s){' % (id, var_str_c))
139 c_body.append('return %s;' % ExprManip.make_c_compatible(math))
140 c_body.append('}')
141 c_body = os.linesep.join(c_body)
142 _common_prototypes_c.set(id, 'double %s(%s);' % (id, var_str_c))
143 _common_func_strs_c.set(id, c_body)
144 for ii, wrt in enumerate(vars):
145 deriv_id = '%s_%i' % (id, ii)
146 diff_math = ExprManip.diff_expr(math, wrt)
147 c_body = []
148 c_body.append('double %s(%s){' % (deriv_id, var_str_c))
149 c_body.append('return %s;' % ExprManip.make_c_compatible(diff_math))
150 c_body.append('}')
151 c_body = os.linesep.join(c_body)
152 _common_prototypes_c.set(deriv_id,'double %s(%s);' % (deriv_id,
153 var_str_c))
154 _common_func_strs_c.set(deriv_id, c_body)
155
156
157 for id, vars, math in _logical_comp_func_defs:
158
159
160 if id == 'and_func':
161 func = 'lambda *x: reduce(operator.and_, x)'
162 elif id == 'or_func':
163 func = 'lambda *x: reduce(operator.or_, x)'
164 else:
165 var_str = ','.join(vars)
166 func = 'lambda %s: %s' % (var_str, math)
167 _common_func_strs.set(id, func)
168
169
170
171
172 for func_id, func_str in _common_func_strs.items():
173 _common_namespace[func_id] = eval(func_str, _common_namespace, {})
174
222
223 add_int_times, add_tail_times = True, True
225 """
226 Do not add timepoints to returned trajectories.
227 """
228 cls.add_int_times, cls.add_tail_times = False, False
229 full_speed = classmethod(full_speed)
231 """
232 Allow the integrator to automatically add timepoints to the interior of
233 a trajectory.
234
235 This is slower, but may capture the dynamics better.
236 """
237 cls.add_int_times, cls.add_tail_times = True, False
238 fill_traj = classmethod(fill_traj)
240 """
241 Add timepoints to the interior of a trajectory, plus 5% past the last
242 timepoint requested.
243
244 This produces the prettiest plots.
245 """
246 cls.add_int_times, cls.add_tail_times = True, True
247 pretty_plotting = classmethod(pretty_plotting)
248
249
250
251
256
257 - def add_compartment(self, id, initial_size=1.0, name='',
258 typical_value=None,
259 is_constant=True, is_optimizable=False):
260 """
261 Add a compartment to the Network.
262
263 All species must reside within a compartment.
264 """
265 compartment = Compartment(id, initial_size, name, typical_value,
266 is_constant, is_optimizable)
267 self._add_variable(compartment)
268
269 - def add_species(self, id, compartment, initial_conc=0,
270 name='', typical_value=None,
271 is_boundary_condition=False, is_constant=False,
272 is_optimizable=False, uniprot_ids=set()):
273 """
274 Add a species to the Network.
275 """
276 species = Species(id, compartment, initial_conc, name, typical_value,
277 is_boundary_condition, is_constant, is_optimizable,
278 uniprot_ids)
279 self._add_variable(species)
280
281 - def add_parameter(self, id, initial_value=1.0, name='',
282 typical_value=None,
283 is_constant=True, is_optimizable=True):
284 """
285 Add a parameter to the Network.
286 """
287 parameter = Parameter(id, initial_value, name, is_constant,
288 typical_value, is_optimizable)
289 self._add_variable(parameter)
290
291 - def add_event(self, id, trigger, event_assignments={}, delay=0, name='',
292 buffer=0):
293 """
294 Add an event to the Network.
295
296 id - id for this event
297 trigger - The event firest when trigger passes from False to True.
298 Examples: To fire when time becomes greater than 5.0:
299 trigger = 'gt(time, 5.0)'
300 To fire when A becomes less than sin(B/C):
301 trigger = 'lt(A, sin(B/C))'
302 event_assignments - A dictionary or KeyedList of assignments to make
303 when the event executes.
304 Example: To set A to 4.3 and D to B/C
305 event_assignments = {'A': 4.3,
306 'D': 'B/C'}
307 delay - Optionally, assignments may take effect some time after the
308 event fires. delay may be a number or math expression
309 name - A more detailed name for the event, not restricted to the id
310 format
311 """
312 event = Event(id, trigger, event_assignments, delay, name,
313 buffer)
314 self._checkIdUniqueness(event.id)
315 self.events.set(event.id, event)
316
318 """
319 Add a constraint to the Network.
320
321 id - id for this constraint
322 trigger - We treat constraints as events that correspond to an
323 invalid solution whenever the trigger is True.
324 Example: To have an invalid solution when species A is > 5.0:
325 trigger = 'gt('A', 5.0)'
326 name - A more detailed name for the constraint, not restricted to the id
327 format
328 """
329 constraint = ConstraintEvent(id, trigger, message, name)
330 self._checkIdUniqueness(constraint.id)
331 self.constraints.set(constraint.id, constraint)
332
333
335 """
336 Add a function definition to the Network.
337
338 id - id for the function definition
339 variables - The variables used in the math expression whose
340 values should be subsituted.
341 math - The math expression the function definition represents
342 name - A more extended name for the definition
343
344 Example:
345 To define f(x, y, z) = y**2 - cos(x/z)
346 net.add_func_def('my_func', ('x', 'y', 'z'), 'y**2 - cos(x/z)')
347 """
348 func = FunctionDefinition(id, variables, math, name)
349 self._checkIdUniqueness(func.id)
350 self.functionDefinitions.set(func.id, func)
351
352
353
354 var_str = ','.join(variables)
355 func_str = 'lambda %s: %s' % (var_str, math)
356 self._func_strs.set(id, func_str)
357 self.namespace[id] = eval(func_str, self.namespace)
358
360 self.namespace = copy.copy(self._common_namespace)
361 for id, func in self.functionDefinitions.items():
362 variables = func.variables
363 math = func.math
364
365 var_str = ','.join(variables)
366 func_str = 'lambda %s: %s' % (var_str, math)
367 self._func_strs.set(id, func_str)
368 logger.debug('Adding function to namespace: %s, %s' % (id, func_str))
369 self.namespace[id] = eval(func_str, self.namespace)
370
371
372 c_vars = ['double %s' % var for var in variables]
373 c_var_str = ','.join(c_vars)
374 self._prototypes_c.set(id,'double %s(%s);' % (id, c_var_str))
375 c_math = ExprManip.make_c_compatible(math)
376 c_body = 'double %s(%s){return %s;}' % (id, c_var_str, c_math)
377 self._func_defs_c.set(id, c_body)
378
379 for ii, wrt in enumerate(variables):
380
381 diff_id = '%s_%i' % (id, ii)
382 diff_math = ExprManip.diff_expr(math, wrt)
383 func_str = 'lambda %s: %s' % (var_str, diff_math)
384 self._func_strs.set(diff_id, func_str)
385 self.namespace[diff_id] = eval(func_str, self.namespace)
386
387
388 self._prototypes_c.set(diff_id,
389 'double %s(%s);' % (diff_id,c_var_str))
390 c_math = ExprManip.make_c_compatible(diff_math)
391 c_body = 'double %s(%s){return %s;}' % (diff_id, c_var_str,
392 c_math)
393 self._func_defs_c.set(diff_id, c_body)
394
396
397
398
399
400
401 if isinstance(id, str):
402 rxn = apply(Reactions.Reaction, (id,) + args, kwargs)
403 else:
404 rxn = apply(id, args, kwargs)
405
406 self._checkIdUniqueness(rxn.id)
407 self.reactions.set(rxn.id, rxn)
408
422
424 """
425 Add a rate rule to the Network.
426
427 A rate rules species that d <var_id>/dt = rhs.
428 """
429 self.set_var_constant(var_id, False)
430 self.rateRules.set(var_id, rhs)
431 self._makeCrossReferences()
432
434 """
435 Add an algebraic rule to the Network.
436
437 An algebraic rule specifies that 0 = rhs.
438 """
439 self.algebraicRules.set(rhs, rhs)
440 self._makeCrossReferences()
441
443 """
444 Remove the component with the given id from the Network.
445
446 Components that can be removed are variables, reactions, events,
447 function definitions, assignment rules, rate rules, and constraints.
448 """
449 complists = [self.variables, self.reactions, self.functionDefinitions,
450 self.events, self.constraints, self.assignmentRules, self.rateRules,
451 self.algebraicRules]
452 for complist in complists:
453
454 if complist.has_key(id):
455 complist.remove_by_key(id)
456
457 self._makeCrossReferences()
458
460 """
461 Check whether a given id is already in use by this Network.
462 """
463 if id == 'time':
464 logger.warn("Specifying 'time' as a variable is dangerous! Are you "
465 "sure you know what you're doing?")
466 elif id == 'default':
467 logger.warn("'default' is a reserved keyword in C. This will cause "
468 "problems using the C-based integrator.")
469 elif id[0].isdigit():
470 raise ValueError("The id %s is invalid. ids must not start with a "
471 "number." % id)
472 if id in self.variables.keys()\
473 or id in self.reactions.keys()\
474 or id in self.functionDefinitions.keys()\
475 or id in self.events.keys()\
476 or id in self.constraints.keys()\
477 or id == self.id:
478 raise ValueError, ('The id %s is already in use!' % id)
479
481 """
482 Set the id of this Network
483 """
484 if id != self.id:
485 self._checkIdUniqueness(id)
486 self.id = id
487
489 """
490 Get the id of this Network.
491 """
492 return self.id
493
495 """
496 Set the name of this Network
497 """
498 self.name = name
499
501 """
502 Get the name of this Network.
503 """
504 return self.name
505
507 """
508 Disables the stochastic simulation of network dynamics
509 """
510 if hasattr(self, 'stochastic'): delattr(self, 'stochastic')
511
513 """
514 set_stochastic enables the stochastic simulation of the network
515 dynamics (instead of deterministic integration). This will discretize
516 the dynamic variables in the model (making them integers). This
517 simulation has only limited support for events*, and does not
518 implement algebraic rules** or rates rules**. We use a kinetic MC
519 algorithm (aka Gillespie algorithm). The complementary function
520 'set_deterministic' may be used to disable stochastic simulations of
521 network dynamics. Please note the results returned for exactly the
522 times asked are interpolations between the surrounding points, thus
523 concentrations may be floats instead of integers.
524
525 * Since there is no exact way to implement events in a stochastic
526 simulation, only a very primative method is present. This algorithm
527 currently only supports time triggered events (more complex triggers
528 may be added in the future) and fires them as soon after that time
529 is passed as possible. Please note that it is the users
530 responsibility to ensure the events are firing in a sensible
531 way. Non-sensible output will arise when the time steps are too
532 large and events are not fired near their target trigger times. The
533 fired times are logged in the logger at the debug level.
534
535 ** Possible future implementation, although parsing rate rules have the
536 possible issue of creating negative reaction rates (which have no
537 physical meaning). Add reactions instead of rate rules for stochastic
538 simulations.
539
540 Inputs:
541 (seed=None, fill_dt=None, rmsd=None)
542 seed -- RNG seed used in the simulation. If none, generated from the
543 system time and os.urandom (if available).
544 fill_dt -- Fill in the trajectory at the requested time interval. This
545 is the simplest way to fill in a trajectory.
546 rmsd -- Maximum root mean squared distance in the dynamic variable
547 space before taking a data point (a better trajectory filler).
548
549 Outputs: None
550 """
551 if seed==None:
552 def rehash(key):
553 key += ~(key << 15)
554 key ^= (key >> 10)
555 key += (key << 3)
556 key ^= (key >> 6)
557 key += ~(key << 11)
558 key ^= (key >> 16)
559 return key
560
561 t = time.time()
562 ts = int(t)
563 tms = int((t-float(ts))*1000000.0)
564 seed = rehash(ts)^rehash(tms)
565
566 try:
567 import struct
568 seed ^= rehash(
569 struct.unpack('i', os.urandom(struct.calcsize('i')))[0])
570 except: pass
571
572 seed = int(seed % sys.maxint)
573
574 if rmsd==None:
575 rmsd = _double_max_
576
577 self.stochastic = {'seed':seed, 'reseed':True,
578 'fill_dt':fill_dt, 'rmsd':rmsd}
579
580 if hasattr(self, 'periodic'):
581 logger.warn('Cannot find periodic solutions with a stochastic solution, disabling periodic solution finding')
582 delattr(self, 'periodic')
583 self.remove_component('_tau')
584
585 - def set_periodic(self, period, xtol=0.001, maxfun=100, phase=None,
586 minVel=None, level=2, log=False, rel=False):
587 """
588 set_periodic ensures that a period solution has satisfactorily
589 approached a limit cycle before returning the solution. Please note that
590 this has not been implemented for sensitivity calculations.
591
592 Inputs:
593 (period, xtol=0.001, maxfun=100, phase=None, minVel=None, level=2,
594 log=False, rel=False)
595 period -- initial guess of the period (required)
596 xtol -- tolerance required for convergence (all chemicals). If set too
597 high, numerical (in)precision may cause no stable limit cycle.
598 maxfun -- maximum number of iterations (one trajectory found in each)
599 phase -- set to a ('name', value) tuple to set the t=0 solution to a
600 particular state in systems which no forcing. Value may be
601 'max','min', or a float concentration (careful with the later).
602 minVel -- used to detect fixed points:
603 when the (max IC velocity)**2 < minVel the integration
604 is halted, the stability set to True, and the period set to
605 0.0 (indicating nonperiodic, fixed point soln).
606 level -- correlation level (>=1) to use to find the period. For example,
607 if level=2, the difference between x(0)-x(1*tau) and
608 x(0)-x(2*tau) is used.
609 log -- Set to True to use logarithms of state variables, constraining
610 the solution to non-zero values
611 rel -- Set to True to use relative differences (x1-x0)/min(x0,x1) in
612 the limit cycle period search.
613
614 Outputs: (stored in net.periodic dictionary)
615 tol -- tolerance of the solution (rmsd of ic1 to ic0 for each level)
616 period -- actual period of oscillation
617 stable -- whether a stable solution was found
618 feval -- number of iterations
619 stableIC -- stable initial condition
620
621 Additionally, the period is accessible during the calculation and
622 afterwards via the '_tau' variable (useful for assignments which
623 rely on the period).
624 """
625 self.periodic = {'xtol': xtol, 'maxfun':maxfun, 'phase':phase,
626 'level':int(level), 'log':log, 'rel':rel,
627 'feval': 0, 'period': period, 'minVel': minVel,
628 'stable': False, 'stableIC': {}}
629 if hasattr(self, 'stochastic'):
630 logger.warn('Cannot find periodic solutions with a stochastic solution, switching to dynamic solution')
631 self.set_deterministic()
632 self.add_parameter('_tau', period, is_constant=True,
633 is_optimizable=False)
634
636 """
637 Internal function used to integrate a trajectory and find the point
638 nearest the initial point (defined as the root sum squared distance)
639 in the period range of [0.475*tau, 1.5*tau]. The point found and period
640 (tau) is returned.
641
642 Inputs:
643 (params, varNames, s0)
644 params -- Network parameters
645 varNames -- Names corresponding to the values in ln_x0
646 s0 -- Initial state (period and conditions) where s0[0]=period and
647 s0[1:]=initial conditions
648
649 Outputs:
650 (s1)
651 s1 -- New state found (period and conditions defined same as input)
652 """
653 if self.periodic['rel']:
654 rmsd = lambda _s1, _s2: \
655 scipy.sqrt(scipy.average(((_s1-_s2) / \
656 scipy.minimum(_s1,_s2))**2))
657 elif self.periodic['log']:
658 rmsd = lambda _s1, _s2: \
659 scipy.sqrt(scipy.average((scipy.log(_s1/_s2)**2)))
660 else:
661 rmsd = lambda _s1, _s2: scipy.sqrt(scipy.average((_s1-_s2)**2))
662
663
664 s0 = scipy.array(s0)
665 tau0, x0 = s0[0], s0[1:]
666 for name, value in zip(varNames, x0):
667 self.set_var_ic(name, value)
668
669
670
671
672
673 a = 0.475
674 b = a + (1.0-a)/(0.5*(3.0-scipy.sqrt(5.0)))
675
676
677 max_time = b * tau0 * float(self.periodic['level'])
678 self.trajectory = self.integrate([0.,max_time], params, addTimes = True)
679 self.trajectory.build_interpolated_traj()
680 ev_inter_traj = self.trajectory.evaluate_interpolated_traj
681
682
683
684
685 s = lambda t: scipy.array([scipy.squeeze(t)] + \
686 [ev_inter_traj(name, t) for name in varNames])
687
688 def __iter_cost(t):
689 t = scipy.squeeze(abs(t))
690 res = scipy.array([t], scipy.float_)
691 for lvl in range(1, self.periodic['level']+1):
692 res = scipy.concatenate((res, s(t*float(lvl))[1:]))
693 res0 = scipy.concatenate(([tau0], list(x0)*self.periodic['level']))
694 return rmsd(res, res0)
695
696 tau1 = scipy.optimize.fminbound(__iter_cost, a * tau0, b * tau0)
697 tau1 = abs(tau1)
698 s1 = s(tau1)
699
700
701 self.periodic['feval'] += 1
702 self.periodic['period'] = tau1
703 self.set_var_val('_tau', tau1)
704 self.periodic['tol'] = __iter_cost(tau1)
705 if self.periodic['tol'] < self.periodic['xtol']:
706 self.periodic['stable']=True
707
708 logger.debug('Limit Cycle Iteration #%i: period = %f, tol = %f, %s'% \
709 (self.periodic['feval'], self.periodic['period'],
710 self.periodic['tol'],
711 '%sstable'%('un'*(not self.periodic['stable']))))
712
713 return s1
714
716 """
717 Internal function which finds and eliminates the slowest decaying
718 mode in the approach to a limit cycle:
719 si = [tau_i, x0_0, .., x0_i]
720 F0 = s_star + vector_1 + ...
721 F1 = s_star + lambda_1 * vector_1 + ...
722 F2 = s_star + lambda_1^2 * vector_1 + ...
723
724 lambda_1 = (F2-F1)*(F1-F0)/|F1-F0|^2
725 vector_1 = (F2-F1)/(lambda_1 * (lambda_1 - 1.0))
726
727 Inputs: (s0, s1, s2)
728 Three vectors representing three consecutive steps towards a limit cycle
729
730 Ouptuts: (s_star)
731 s_star = s2 - lambda_1^2 * vector_1
732 """
733 x0, x1, x2 = s0[1:], s1[1:], s2[1:]
734 lambda_1 = sum( (x2-x1) * (x1-x0) ) / sum( (x1-x0)**2 )
735 vector_1 = (x2-x1)/(lambda_1 * (lambda_1-1.))
736 s = scipy.array(s2)
737 s[1:] -= lambda_1*lambda_1*vector_1
738 return s
739
741 """
742 Internal function to find a stable limit cycle (if one exists), given a
743 parameter set, an estimated period, and a set of initial conditions.
744 This function calculates two iterations (which are hopefully approaching
745 a limit cycle), and use this to estimate a point on the limit cycle - an
746 estimation which is kept if it is closer to the limit cycle.
747
748 Inputs:
749 (params,)
750 params -- model parameters
751
752 Outputs: None
753 """
754 self.periodic['stable'] = False
755 self.periodic['feval'] = 0
756
757
758 varNames = [name for name in self.dynamicVars.keys()
759 if name in self.species.keys()]
760
761
762 tau0 = self.periodic['period']
763 x0 = [self.periodic['stableIC'].get(name, self.get_var_ic(name))
764 for name in varNames]
765 s0 = scipy.array([tau0]+x0)
766
767 while not self.periodic['stable'] and \
768 self.periodic['feval'] < self.periodic['maxfun']:
769
770
771 s1 = self._iter_limit_cycle(params, varNames, s0)
772 if self.periodic['stable']:
773 s0 = s1
774 break
775
776 s2 = self._iter_limit_cycle(params, varNames, s1)
777 tol2 = self.periodic['tol']
778 if self.periodic['stable']:
779 s0 = s2
780 break
781
782 if self.periodic['log']:
783 ls0, ls1, ls2 = scipy.log(s0), scipy.log(s1), scipy.log(s2)
784 s_star = scipy.exp(self._eliminate_slowest_mode(ls0, ls1, ls2))
785 else:
786 s_star = self._eliminate_slowest_mode(s0, s1, s2)
787
788
789
790
791 try:
792 s3 = self._iter_limit_cycle(params, varNames, s_star)
793
794
795 if self.periodic['tol'] < tol2: s0 = s3
796 else: s0 = s2
797 except:
798 s0 = s2
799
800
801 if scipy.any(scipy.isnan(s0)):
802 self.periodic['stable'] = False
803 break
804
805
806 if self.periodic['minVel'] is not None:
807 for name, val in zip(varNames, s0[1:]):
808 self.set_var_ic(name, val)
809
810 maxVel = max(
811 [iV**2 for name, iV in zip(self.dynamicVars.keys(),
812 self.get_initial_velocities())
813 if name in varNames])
814
815 if maxVel < self.periodic['minVel']:
816 self.periodic['period']=0.0
817 self.set_var_val('_tau', 0.0)
818 self.periodic['stable']=True
819 break
820
821
822 if self.periodic['stable']:
823
824 for name, value in zip(varNames, s0[1:]):
825 self.periodic['stableIC'][name] = value
826 self.set_var_ic(name, value)
827
828
829 if self.periodic['phase'] is not None:
830
831 pN, pV = self.periodic['phase']
832 _eit = self.trajectory.evaluate_interpolated_traj
833
834 if pV=='min': cost = lambda t: _eit(pN, t)
835 elif pV=='max': cost = lambda t: 1.0 / _eit(pN, t)
836 else: cost = lambda t: (pV - _eit(pN, t))**2
837
838
839 tau = self.periodic['period']
840 lowerB = float(self.periodic['level'] - 1) * tau
841 upperB = float(self.periodic['level']) * tau
842 t0 = scipy.optimize.fminbound(cost, lowerB, upperB)
843
844
845 for name in varNames:
846 self.periodic['stableIC'][name] = _eit(name, t0)
847 self.set_var_ic(name, _eit(name, t0))
848
849
850
851
852
856
858
859
860
861 t = sets.Set([0])
862 ret_full_traj=False
863 for var, times in vars.items():
864 if var == 'full trajectory':
865 ret_full_traj = True
866 t.union_update(sets.Set(times))
867 elif var.endswith('_maximum') or var.endswith('_minimum'):
868 t1,t2 = times
869 if t1 is not None:
870 t.add(t1)
871 if t2 is not None:
872 t.add(t2)
873 elif self.variables.has_key(var):
874 t.union_update(sets.Set(times))
875 else:
876 raise ValueError('Unknown variable %s requested from network %s'
877 % (var, self.get_id()))
878
879
880 t = list(t)
881 t.sort()
882
883 if hasattr(self, 'periodic'):
884 self._find_limit_cycle(params)
885 if self.periodic['period'] > max(t):
886 t.append(self.periodic['period'])
887 elif hasattr(self, 'stochastic'):
888 self.trajectory = self.integrateStochastic(t, params=params)
889 return
890
891 self.trajectory = self.integrate(t, params=params,
892 addTimes=ret_full_traj)
893
895 t = sets.Set([0])
896
897 for var,times in vars.items():
898 t.union_update(sets.Set(times))
899
900 t = list(t)
901 t.sort()
902
903 self.ddv_dpTrajectory = self.integrateSensitivity(t,params=params,
904 addTimes=True)
905 self.trajectory = self.ddv_dpTrajectory
906
909
911 return KeyedList([(var.id, var.value) for var in
912 self.optimizableVars.values()])
913
915 return KeyedList([(var.id, var.typicalValue) for var in
916 self.optimizableVars.values()])
917
919 result = {}
920 times = self.trajectory.timepoints
921 for id in vars:
922 if id == 'full trajectory':
923 self.trajectory.build_interpolated_traj()
924 result[id] = self.trajectory
925 if id.endswith('_maximum') or id.endswith('_minimum'):
926
927
928 var = '_'.join(id.split('_')[:-1])
929 minTime, maxTime = vars[id]
930
931
932
933 t = self.trajectory.get_times()
934
935 if minTime is not None:
936 min_t_ii = t.searchsorted(minTime)
937 else:
938 min_t_ii = 0
939 if maxTime is not None:
940 max_t_ii = t.searchsorted(maxTime)-1
941 else:
942 max_t_ii = len(t)
943 vartraj = self.trajectory.get_var_traj(var)
944 if id.endswith('_maximum'):
945 var_val_ii = vartraj[min_t_ii:max_t_ii+1].argmax()\
946 + min_t_ii
947 elif id.endswith('_minimum'):
948 var_val_ii = vartraj[min_t_ii:max_t_ii+1].argmin()\
949 + min_t_ii
950 var_val = vartraj[var_val_ii]
951 t_val = t[var_val_ii]
952
953
954
955
956 curr_vals = self.get_var_vals()
957 event_info = self.trajectory.event_info
958 for ii in range(len(event_info[0])):
959 time,dynVarVals = event_info[0][ii], event_info[1][ii]
960 self.updateVariablesFromDynamicVars(dynVarVals, time)
961 eval = self.get_var_val(var)
962 if id.endswith('_maximum') and eval > var_val\
963 and time >= minTime and time <= maxTime:
964 var_val = eval
965 t_val = time
966 elif id.endswith('_minimum') and eval < var_val\
967 and time >= minTime and time <= maxTime:
968 var_val = eval
969 t_val = time
970 self.set_var_vals(curr_vals)
971
972 result[id] = {(minTime, maxTime):(t_val,var_val)}
973 elif self.variables.has_key(id):
974 traj = self.trajectory.getVariableTrajectory(id)
975 result[id] = dict(zip(times, traj))
976
977 return result
978
980
981
982
983 result = {}
984 times = self.ddv_dpTrajectory.get_times()
985 for id in vars.keys():
986 result[id] = {}
987 for tIndex, t in enumerate(times):
988 result[id][t] = {}
989 for optparam in self.optimizableVars.keys():
990 result[id][t][optparam] = \
991 self.ddv_dpTrajectory.get_var_traj((id,optparam))[tIndex]
992 return result
993
994 - def integrate(self, times, params=None, returnEvents=False, addTimes=True,
995 rtol = None):
996 if self.add_tail_times or addTimes:
997 times = scipy.concatenate((times, [1.05*times[-1]]))
998 return Dynamics.integrate(self, times, params=params,
999 fill_traj=(self.add_int_times or addTimes))
1000
1001 - def integrateSensitivity(self, times, params = None,
1002 returnEvents = False, addTimes = True,
1003 rtol=None):
1004 if self.add_tail_times:
1005 times = scipy.concatenate((times, [1.05*times[-1]]))
1006 return Dynamics.integrate_sensitivity(self, times, params, rtol,
1007 fill_traj=self.add_int_times)
1008
1010 if self.stochastic['fill_dt'] is not None:
1011 times = sets.Set(times)
1012 times.union_update(scipy.arange(min(times), max(times),
1013 self.stochastic['fill_dt']))
1014 times = list(times)
1015 times.sort()
1016
1017 if times[0]==0.:
1018 self.resetDynamicVariables()
1019
1020
1021 times = sets.Set(times)
1022 times.union_update([_.triggeringTime for _ in self.events
1023 if _.triggeringTime<max(times)])
1024 times = list(times)
1025 times.sort()
1026
1027 if times[0]==0.:
1028 times = times[1:]
1029
1030 if params is not None: self.update_optimizable_vars(params)
1031
1032 self.compile()
1033
1034
1035 body = self._dynamic_funcs_python.get('integrate_stochastic_tidbit')
1036 if 'pass' in body.split('\n')[-1]:
1037 err_body = '\n'.join(
1038 ['Integrate stochastic failed due to the problem(s):']+
1039 body.split('\n')[1:-1])
1040 raise RuntimeError(err_body)
1041
1042 dv=scipy.array([self.get_var_val(_) for _ in self.dynamicVars.keys()])
1043 cv = self.constantVarValues
1044
1045 trajectory = Trajectory_mod.Trajectory(self, holds_dt=0, const_vals=cv)
1046 trajectory.appendFromODEINT(scipy.array([0.0]), scipy.array([dv]))
1047
1048
1049 events_occurred = []
1050 pendingEvents = {}
1051 for event in self.events.values():
1052 pendingEvents.setdefault(event.triggeringTime, [])
1053 pendingEvents[event.triggeringTime].append(event)
1054
1055 t, tInd = 0.0, 0
1056 while t < times[-1]:
1057
1058 t, dv, tout, dvout = self.integrate_stochastic_tidbit(
1059 self.stochastic['seed'], self.stochastic['reseed'],
1060 t, dv, cv, self.stochastic['rmsd'], times[tInd])
1061 self.stochastic['reseed']=False
1062
1063
1064 while tInd<len(times) and t >= times[tInd]:
1065
1066 if times[tInd]!=tout:
1067 dt = t - trajectory.timepoints[-1]
1068 dvout = trajectory.values[-1]+(dv-trajectory.values[-1])/\
1069 dt*(times[tInd] - trajectory.timepoints[-1])
1070
1071 trajectory.appendFromODEINT(scipy.array([times[tInd]]),
1072 scipy.array([dvout]))
1073
1074
1075 if times[tInd] in pendingEvents.keys():
1076 events = pendingEvents.pop(times[tInd])
1077 for event in events:
1078
1079
1080
1081
1082
1083 dvout = self.executeEvent(event, times[tInd], dvout, \
1084 dvout, times[tInd])
1085 dv = self.executeEvent(event, times[tInd], dvout, dv, t)
1086 events_occurred.append(event)
1087 logger.debug('Executed event %s in net %s at t=%s'%\
1088 (event.id, self.id, t))
1089 trajectory.appendFromODEINT(scipy.array([times[tInd]]),
1090 scipy.array([dvout]))
1091
1092 tInd += 1
1093
1094 if trajectory.timepoints[-1]<t:
1095 trajectory.appendFromODEINT(scipy.array([t]),
1096 scipy.array([dv]))
1097
1098 return trajectory
1099
1101 """
1102 Runs through expr and replaces all piecewise expressions by the
1103 clause that is currently active.
1104 """
1105 if not expr.count('piecewise('):
1106 return expr
1107 funcs_used = ExprManip.extract_funcs(expr)
1108 for func, args in funcs_used:
1109 if func == 'piecewise':
1110 ast = ExprManip.strip_parse(expr)
1111 ast = self._sub_for_piecewise_ast(ast, time)
1112 return ExprManip.ast2str(ast)
1113 return expr
1114
1116 if isinstance(ast, ExprManip.AST.CallFunc)\
1117 and ExprManip.ast2str(ast.node) == 'piecewise':
1118
1119 conditions = [cond for cond in ast.args[1::2]]
1120 clauses = [clause for clause in ast.args[:-1:2]]
1121 if len(ast.args)%2 == 1:
1122
1123 otherwise = ast.args[-1]
1124 else:
1125 otherwise = None
1126
1127 for cond_ast, expr_ast in zip(conditions, clauses):
1128
1129
1130 subbed_cond = self._sub_for_piecewise_ast(cond_ast, time=time)
1131 cond_str = ExprManip.ast2str(subbed_cond)
1132 if self.evaluate_expr(cond_str, time):
1133 return self._sub_for_piecewise_ast(expr_ast, time=time)
1134 else:
1135
1136
1137 if otherwise is not None:
1138 return self._sub_for_piecewise_ast(otherwise, time=time)
1139 else:
1140 raise ValueError('No True condition and no otherwise '
1141 " clause in '%s'."
1142 % ExprManip.ast2str(ast))
1143 return ExprManip.AST.recurse_down_tree(ast, self._sub_for_piecewise_ast,
1144 (time,))
1145
1147 """
1148 Evaluate the given expression using the current values of the network
1149 variables.
1150 """
1151 try:
1152 return float(expr)
1153 except ValueError:
1154
1155
1156 expr = self._sub_for_piecewise(expr, time)
1157 if var_vals is None:
1158 vars_used = ExprManip.extract_vars(expr)
1159 var_vals = [(id, self.get_var_val(id)) for id in vars_used
1160 if id != 'time']
1161 var_vals = dict(var_vals)
1162 var_vals['time'] = time
1163 local_namespace = var_vals
1164 local_namespace.update(self.namespace)
1165
1166 return eval(expr.strip(), local_namespace, {})
1167
1168
1169
1170
1172 """
1173 Set the typical value for a variable.
1174 """
1175 var = self.get_variable(id)
1176 var.typicalValue = value
1177
1179 """
1180 Return the typical value for a variable.
1181 """
1182 return self.get_variable(id).typicalValue
1183
1185 """
1186 Return the variable typical values as a KeyedList.
1187 """
1188 return KeyedList([(id, self.get_var_typical_val(id)) for id in
1189 self.variables.keys()])
1190
1191 - def set_var_ic(self, id, value, warn=True, update_constants=True):
1192 """
1193 Set the initial condition of the variable with the given id.
1194 """
1195 if warn and id in self.assignedVars.keys():
1196 logger.warn('WARNING! Attempt to assign an initial condition to '
1197 'the variable %s, which is determined by an assignment '
1198 'rule. This is a meaningless operation. Instead, '
1199 'change the initial condition of one or more of the '
1200 'components in the rule: %s' %
1201 (id, self.assignmentRules.get(id)))
1202
1203 var = self.get_variable(id)
1204 var.initialValue = value
1205 if var.is_constant:
1206 var.value = value
1207 if update_constants:
1208 self.constantVarValues = [self.evaluate_expr(var.value) for var
1209 in self.constantVars.values()]
1210 self.constantVarValues = scipy.array(self.constantVarValues)
1211
1213 """
1214 Return the initial condition for a variable
1215 """
1216 return self.get_variable(id).initialValue
1217
1219 """
1220 Return the variable initial conditions as a KeyedList
1221 """
1222 return KeyedList([(id, self.get_var_ic(id)) for id in
1223 self.variables.keys()])
1224
1226 """
1227 Set current variable values from a KeyedList or dictionary.
1228 """
1229 for id, value in kl.items():
1230 self.set_var_val(id, value, time, warn=False, do_assignments=False)
1231 self.updateAssignedVars(time)
1232
1234 """
1235 Return the current value of a variable
1236 """
1237 val = self.get_variable(id).value
1238 return self.evaluate_expr(val)
1239
1241 """
1242 Return the current variable values as a KeyedList
1243
1244 ids -- List o variable ids to return values for. If None, all variables
1245 are used.
1246 """
1247 if ids is None:
1248 ids = self.variables.keys()
1249 return KeyedList([(id, self.get_var_val(id)) for id in ids])
1250
1252 """
1253 Returns the vector field evaluated at the initial conditions
1254 """
1255 ics = [self.evaluate_expr(self.getInitialVariableValue(dvid))
1256 for dvid in self.dynamicVars.keys()]
1257
1258 y0, initialv = Dynamics.find_ics(y=ics, yp=scipy.ones(len(ics)),
1259 time=0,
1260 var_types=self._dynamic_var_algebraic,
1261 rtol=[1e-6]*len(ics),
1262 atol=[1e-6]*len(ics),
1263 constants=self.constantVarValues,
1264 net=self)
1265 return initialv
1266
1268 """
1269 Set variable initial conditions from a KeyedList or dictionary.
1270 """
1271 for id, value in kl.items():
1272 if id in self.variables.keys():
1273 self.set_var_ic(id, value, warn=False)
1274
1275 - def set_var_val(self, id, val, time=0, warn=True, do_assignments=True):
1276 """
1277 Set the current stored value of the variable with the given id.
1278 """
1279
1280 if warn and self.assignedVars.has_key(id):
1281 logger.warn('WARNING! Attempt to assign a value to the variable '
1282 '%s, which is determined by an assignment rule. This '
1283 'is a meaningless operation. Instead, change the value '
1284 'of one or more of the components in the rule: %s'
1285 % (id, self.assignmentRules.get(id)))
1286
1287 var = self.get_variable(id)
1288 var.value = val
1289 if do_assignments:
1290 self.updateAssignedVars(time)
1291
1292 setTypicalVariableValue = set_var_typical_val
1293
1295 """
1296 Return the class instance with a given variable id.
1297 """
1298 var = self.variables.get(id)
1299 if var:
1300 return var
1301 else:
1302 raise KeyError('Variable %s not found in network %s!'
1303 % (id, self.get_id()))
1304
1306 """
1307 Update the net's optimizable vars from a passed-in KeyedList,
1308 dictionary, or sequence.
1309
1310 Only those variables that intersect between the net and params are
1311 changed if a KeyedList or dict is passed in.
1312 """
1313 if hasattr(params, 'get'):
1314 inBoth = sets.Set(self.optimizableVars.keys())
1315 inBoth = inBoth.intersection(sets.Set(params.keys()))
1316 for id in inBoth:
1317 self.set_var_ic(id, params.get(id), update_constants=False)
1318 elif len(params) == len(self.optimizableVars):
1319 for ii, id in enumerate(self.optimizableVars.keys()):
1320 self.set_var_ic(id, params[ii], update_constants=False)
1321 else:
1322 raise ValueError('Passed in parameter set does not have the proper '
1323 'length!')
1324
1325 self.constantVarValues = [self.evaluate_expr(var.value) for var in
1326 self.constantVars.values()]
1327 self.constantVarValues = scipy.array(self.constantVarValues)
1328
1329 getInitialVariableValue = get_var_ic
1330
1332
1333
1334 return scipy.array([self.evaluate_expr(var.value)
1335 for var in self.dynamicVars.values()])
1336
1338
1339
1340
1341 pending = []
1342 for id, var in self.dynamicVars.items():
1343 if isinstance(var.initialValue, str):
1344 pending.append((id, var))
1345 else:
1346 var.value = var.initialValue
1347
1348
1349
1350 self.updateAssignedVars(time = 0)
1351
1352 for id, var in pending:
1353 self.dynamicVars.getByKey(id).value = \
1354 self.evaluate_expr(var.initialValue, 0)
1355
1356 self.updateAssignedVars(time = 0)
1357
1364
1366 for ii in range(len(self.dynamicVars)):
1367 self.dynamicVars[ii].value = values[ii]
1368 self.updateAssignedVars(time)
1369
1371 to_get = sets.Set(self.variables.keys())
1372 to_get.difference_update(sets.Set(self.assignedVars.keys()))
1373 var_vals = [(id, self.get_var_val(id)) for id in to_get]
1374 var_vals = dict(var_vals)
1375 var_vals['time'] = time
1376 for id, rhs in self.assignmentRules.items():
1377 assigned_val = self.evaluate_expr(rhs, time, var_vals=var_vals)
1378 self.assignedVars.getByKey(id).value = assigned_val
1379 var_vals[id] = assigned_val
1380
1384
1388
1391
1392
1393
1394
1395
1397 logger.debug('Making diff equation rhs')
1398 diff_eq_terms = {}
1399
1400 for rxn_id, rxn in self.reactions.items():
1401 rateExpr = rxn.kineticLaw
1402 logger.debug('Parsing reaction %s.' % rxn_id)
1403
1404 for reactantId, dReactant in rxn.stoichiometry.items():
1405 if self.get_variable(reactantId).is_boundary_condition or\
1406 self.get_variable(reactantId).is_constant or\
1407 self.assignmentRules.has_key(reactantId):
1408
1409
1410
1411 continue
1412
1413 term = '(%s) * (%s)' % (dReactant, rateExpr)
1414 diff_eq_terms.setdefault(reactantId, [])
1415 diff_eq_terms[reactantId].append(term)
1416
1417 self.diff_eq_rhs = KeyedList()
1418 for id in self.dynamicVars.keys():
1419 if self.rateRules.has_key(id):
1420 self.diff_eq_rhs.set(id, self.rateRules.get(id))
1421 else:
1422
1423 rhs = '+'.join(diff_eq_terms.get(id, ['0']))
1424 self.diff_eq_rhs.set(id, ExprManip.simplify_expr(rhs))
1425
1427 py_body = []
1428 py_body.append('def res_function(time, dynamicVars, yprime, '
1429 'constants):')
1430 py_body.append('dynamicVars = scipy.asarray(dynamicVars)')
1431 py_body.append('yprime = scipy.asarray(yprime)')
1432 py_body.append('constants = scipy.asarray(constants)')
1433 py_body.append('')
1434 py_body.append('residual = scipy.empty(%i, scipy.float_)'
1435 % len(self.dynamicVars))
1436 py_body.append('')
1437 self._add_assignments_to_function_body(py_body)
1438 py_body.append('')
1439
1440 c_body = []
1441
1442
1443
1444
1445 c_args = 'double *time_ptr, double *dynamicVars, double *yprime, '\
1446 'double *cj_ptr, double *residual, int *ires_ptr, '\
1447 'double *constants, int *ipar'
1448 c_body.append('void res_function_(%s){' % c_args)
1449 self._prototypes_c.set('res_function',
1450 'void res_function_(%s);' % c_args)
1451 c_body.append('double time = *time_ptr;')
1452 c_body.append('')
1453 self._add_assignments_to_function_body(c_body, in_c=True)
1454 c_body.append('')
1455
1456
1457 algebraicRuleList = self.algebraicRules.values()
1458
1459
1460
1461 self._residual_terms = []
1462
1463
1464 self._dynamic_var_algebraic = []
1465
1466
1467 for ii, (id, var) in enumerate(self.dynamicVars.items()):
1468 if self.algebraicVars.has_key(id):
1469
1470
1471 rhs = algebraicRuleList.pop(0)
1472 py_body.append('# Residual function corresponding to an '
1473 'algebraic equation')
1474 py_body.append('residual[%i] = %s' % (ii, rhs))
1475 c_rhs = ExprManip.make_c_compatible(rhs)
1476 c_body.append('residual[%i] = %s;' % (ii, c_rhs))
1477 self._residual_terms.append((rhs, None))
1478 self._dynamic_var_algebraic.append(-1)
1479 else:
1480 rhs = self.diff_eq_rhs.getByKey(id)
1481 c_rhs = ExprManip.make_c_compatible(rhs)
1482 self._dynamic_var_algebraic.append(+1)
1483 py_body.append('# Residual function for %s' % id)
1484 if rhs != '0':
1485 py_body.append('residual[%i] = %s - yprime.item(%i)' %
1486 (ii, rhs, ii))
1487 c_body.append('residual[%i] = %s - yprime[%i];' %
1488 (ii, c_rhs, ii))
1489 self._residual_terms.append((rhs, id))
1490 else:
1491 py_body.append('residual[%i] = -yprime.item(%i)' % (ii, ii))
1492 c_body.append('residual[%i] = -yprime[%i];' % (ii, ii))
1493 self._residual_terms.append((None, id))
1494
1495 py_body.append('')
1496 py_body.append('return residual')
1497 py_body = '\n '.join(py_body)
1498
1499 c_body.append('}')
1500 c_body = os.linesep.join(c_body)
1501
1502 self._dynamic_funcs_python.set('res_function', py_body)
1503 self._dynamic_funcs_c.set('res_function', c_body)
1504
1505 return py_body
1506
1508 len_root_func = 0
1509
1510 py_body = []
1511 py_body.append('def root_func(time, dynamicVars, yprime, constants):')
1512 py_body.append('dynamicVars = scipy.asarray(dynamicVars)')
1513 py_body.append('yprime = scipy.asarray(yprime)')
1514 py_body.append('constants = scipy.asarray(constants)')
1515 py_body.append('')
1516
1517
1518 py_body.append('root_devs = scipy.empty(NEED_TO_FIX, scipy.float_)')
1519 py_body.append('')
1520 self._add_assignments_to_function_body(py_body, include_dts=True)
1521 py_body.append('')
1522
1523 c_body = []
1524 c_args = 'int *neq_ptr, double *time_ptr, double *dynamicVars, '\
1525 'double *yprime, int *nrt_ptr, double *root_devs, '\
1526 'double *constants, int *ipar'
1527 c_body.append('void root_func_(%s){' % c_args)
1528 c_body.append('double time = *time_ptr;')
1529 c_body.append('')
1530 self._add_assignments_to_function_body(c_body, in_c=True,
1531 include_dts=True)
1532 self._prototypes_c.set('root_func',
1533 'void root_func_(%s);' % c_args)
1534 c_body.append('')
1535
1536 self.event_clauses = []
1537 for ii, event in enumerate(self.events.values()+self.constraints.values()):
1538 trigger = event.trigger
1539 for func_name, func_vars, func_expr in self._logical_comp_func_defs:
1540 trigger = ExprManip.sub_for_func(trigger, func_name, func_vars,
1541 func_expr)
1542
1543 py_body.append('root_devs[%i] = (%s) - 0.5' % (len_root_func,
1544 trigger))
1545 c_trigger = ExprManip.make_c_compatible(trigger)
1546 c_body.append('root_devs[%i] = (%s) - 0.5;' % (len_root_func,
1547 c_trigger))
1548 self.event_clauses.append(trigger)
1549 len_root_func += 1
1550
1551 for ii, event in enumerate(self.events.values()+self.constraints.values()):
1552 event.sub_clause_indices = []
1553 trigger = event.trigger
1554 for func_name, func_vars, func_expr in self._logical_comp_func_defs:
1555 trigger = ExprManip.sub_for_func(trigger, func_name, func_vars,
1556 func_expr)
1557 comparisons = ExprManip.extract_comps(trigger)
1558 if len(comparisons) > 1:
1559 for comp in comparisons:
1560 py_body.append('root_devs[%i] = (%s) - 0.5\n\t'
1561 % (len_root_func, comp))
1562 c_comp = ExprManip.make_c_compatible(comp)
1563 c_body.append('root_devs[%i] = (%s) - 0.5;\n\t'
1564 % (len_root_func, c_comp))
1565 self.event_clauses.append(comp)
1566 event.sub_clause_indices.append(len_root_func)
1567 len_root_func += 1
1568
1569 self.len_root_func = len_root_func
1570
1571
1572 py_body[5] = ('root_devs = scipy.empty(%i, scipy.float_)'
1573 % len_root_func)
1574 py_body.append('')
1575 py_body.append('return root_devs')
1576 py_body = '\n\t'.join(py_body)
1577
1578 c_body.append('}')
1579 c_body = os.linesep.join(c_body)
1580
1581 self._dynamic_funcs_python.set('root_func', py_body)
1582 self._dynamic_funcs_c.set('root_func', c_body)
1583
1584 return py_body
1585
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597 py_body = []
1598 py_body.append('def alg_deriv_func(alg_yp, dynamicVars, yp, time, '
1599 'constants):')
1600 py_body.append('alg_yp = scipy.asarray(alg_yp)')
1601 py_body.append('dynamicVars = scipy.asarray(dynamicVars)')
1602 py_body.append('yp = scipy.asarray(yp)')
1603 py_body.append('constants = scipy.asarray(constants)')
1604 py_body.append('')
1605 py_body.append('alg_derivs_res = scipy.empty(%i, scipy.float_)'
1606 % len(self.algebraicRules))
1607 py_body.append('')
1608 self._add_assignments_to_function_body(py_body)
1609 py_body.append('')
1610
1611 c_body = []
1612 c_args = 'double *alg_yp, double *dynamicVars, double *yp, '\
1613 'double *time_ptr, double *constants, double *alg_derivs_res'
1614 c_body.append('void alg_deriv_func_(%s){' % c_args)
1615 c_body.append('double time = *time_ptr;')
1616 c_body.append('')
1617 self._add_assignments_to_function_body(c_body, in_c=True)
1618 self._prototypes_c.set('alg_deriv_func',
1619 'void alg_deriv_func_(%s);' % c_args)
1620 c_body.append('')
1621
1622 for rule_ii, rule in enumerate(self.algebraicRules.values()):
1623
1624 rhs_terms = []
1625 rhs_terms_c = []
1626 rule_vars = ExprManip.extract_vars(rule)
1627 deriv_wrt_time = self.takeDerivative(rule, 'time', rule_vars)
1628 rhs_terms.append(deriv_wrt_time)
1629 rhs_terms_c.append(deriv_wrt_time)
1630 for dyn_id in self.dynamicVars.keys():
1631 deriv = self.takeDerivative(rule, dyn_id, rule_vars)
1632 if deriv != '0':
1633 if self.algebraicVars.has_key(dyn_id):
1634 index = self.algebraicVars.index_by_key(dyn_id)
1635 rhs_terms.append('(%s)*alg_yp.item(%i)' % (deriv,index))
1636 rhs_terms_c.append('(%s)*alg_yp[%i]' % (deriv,index))
1637 else:
1638 index = self.dynamicVars.index_by_key(dyn_id)
1639 rhs_terms.append('(%s)*yp.item(%i)' % (deriv, index))
1640 rhs_terms_c.append('(%s)*yp[%i]' % (deriv, index))
1641 rhs = ' + '.join(rhs_terms)
1642 rhs_c = ' + '.join(rhs_terms_c)
1643 rhs_c = ExprManip.make_c_compatible(rhs_c)
1644 py_body.append('alg_derivs_res[%i] = %s' % (rule_ii, rhs))
1645 c_body.append('alg_derivs_res[%i] = %s;' % (rule_ii, rhs_c))
1646
1647 py_body.append('')
1648 py_body.append('return alg_derivs_res')
1649 py_body = '\n\t'.join(py_body)
1650
1651 c_body.append('}')
1652 c_body = os.linesep.join(c_body)
1653
1654 self._dynamic_funcs_python.set('alg_deriv_func', py_body)
1655 self._dynamic_funcs_c.set('alg_deriv_func', c_body)
1656
1657 return py_body
1658
1660 py_body = []
1661 py_body.append('def alg_res_func(alg_vals, dynamicVars, '
1662 'time, constants):')
1663 py_body.append('alg_vals = scipy.asarray(alg_vals)')
1664 py_body.append('dynamicVars = scipy.asarray(dynamicVars)')
1665 py_body.append('constants = scipy.asarray(constants)')
1666 py_body.append('')
1667 py_body.append('residual = scipy.zeros(%i, scipy.float_)'
1668 % len(self.algebraicVars))
1669
1670 c_body = []
1671 c_args = 'double *alg_vals, double *dynamicVars, double *time_ptr, '\
1672 'double *constants, double *residual'
1673 self._prototypes_c.set('alg_res_func',
1674 'void alg_res_func_(%s);' % c_args)
1675 c_body.append('void alg_res_func_(%s){' % c_args)
1676 c_body.append('double time = *time_ptr;')
1677 c_body.append('')
1678
1679
1680
1681 for ii, key in enumerate(self.algebraicVars.keys()):
1682 var_index = self.dynamicVars.index_by_key(key)
1683 py_body.append('dynamicVars[%i] = alg_vals[%i]'
1684 % (var_index, ii))
1685 c_body.append('dynamicVars[%i] = alg_vals[%i];'
1686 % (var_index, ii))
1687
1688
1689 py_body.append('')
1690 self._add_assignments_to_function_body(py_body)
1691 py_body.append('')
1692 c_body.append('')
1693 self._add_assignments_to_function_body(c_body, in_c=True)
1694 c_body.append('')
1695
1696
1697 for ii, rhs in enumerate(self.algebraicRules.values()):
1698 py_body.append('residual[%i] = %s' % (ii, rhs))
1699 c_rhs = ExprManip.make_c_compatible(rhs)
1700 c_body.append('residual[%i] = %s;' % (ii, c_rhs))
1701
1702 py_body.append('')
1703 py_body.append('return residual')
1704 py_body = '\n '.join(py_body)
1705
1706 c_body.append('}')
1707 c_body = os.linesep.join(c_body)
1708
1709 self._dynamic_funcs_python.set('alg_res_func', py_body)
1710 self._dynamic_funcs_c.set('alg_res_func', c_body)
1711
1713 py_body = []
1714 py_body.append('def dres_dc_function(time, dynamicVars, yprime, '
1715 'constants):')
1716 py_body.append('dynamicVars = scipy.asarray(dynamicVars)')
1717 py_body.append('yprime = scipy.asarray(yprime)')
1718 py_body.append('constants = scipy.asarray(constants)')
1719 py_body.append('')
1720 py_body.append('pd = scipy.zeros((%i, %i), scipy.float_)'
1721 %(len(self.dynamicVars), len(self.dynamicVars)))
1722 py_body.append('')
1723 self._add_assignments_to_function_body(py_body)
1724 py_body.append('')
1725
1726 c_body = []
1727 c_args = 'double *time_ptr, double *dynamicVars, double *yprime, '\
1728 'double *constants, double *pd'
1729 c_body.append('void dres_dc_function_(%s){' % c_args)
1730 self._prototypes_c.set('dres_dc_function',
1731 'void dres_dc_function_(%s);' % c_args)
1732 c_body.append('double time = *time_ptr;')
1733 c_body.append('')
1734 self._add_assignments_to_function_body(c_body, in_c=True)
1735 c_body.append('')
1736
1737 N_dyn = len(self.dynamicVars)
1738
1739 for res_ii, (rhs, dt) in enumerate(self._residual_terms):
1740 if rhs is None:
1741 rhs = '0'
1742 rhs_vars_used = ExprManip.extract_vars(rhs)
1743 for wrt_ii, wrt in enumerate(self.dynamicVars.keys()):
1744 pd_terms = []
1745 deriv = self.takeDerivative(rhs, wrt, rhs_vars_used)
1746 if (deriv != '0' and deriv != '0.0'):
1747 py_body.append('# Residual %i wrt %s' % (res_ii, wrt))
1748 py_body.append('pd[%i, %i] = %s' % (res_ii, wrt_ii, deriv))
1749 deriv_c = ExprManip.make_c_compatible(deriv)
1750 c_body.append('pd[%i] = %s;'
1751 % (res_ii+wrt_ii*N_dyn, deriv_c))
1752
1753 py_body.append('')
1754 py_body.append('return pd')
1755 py_body = '\n '.join(py_body)
1756
1757 c_body.append('}')
1758 c_body = os.linesep.join(c_body)
1759
1760 self._dynamic_funcs_python.set('dres_dc_function', py_body)
1761 self._dynamic_funcs_c.set('dres_dc_function', c_body)
1762
1764 py_body = []
1765 py_body.append('def dres_dcdot_function(time, dynamicVars, yprime, '
1766 'constants):')
1767 py_body.append('dynamicVars = scipy.asarray(dynamicVars)')
1768 py_body.append('yprime = scipy.asarray(yprime)')
1769 py_body.append('constants = scipy.asarray(constants)')
1770 py_body.append('')
1771 py_body.append('pd = scipy.zeros((%i, %i), scipy.float_)'
1772 %(len(self.dynamicVars), len(self.dynamicVars)))
1773 py_body.append('')
1774 self._add_assignments_to_function_body(py_body)
1775 py_body.append('')
1776
1777 c_body = []
1778 c_args = 'double *time_ptr, double *dynamicVars, double *yprime, '\
1779 'double *constants, double *pd'
1780 c_body.append('void dres_dcdot_function_(%s){' % c_args)
1781 self._prototypes_c.set('dres_dcdot_function',
1782 'void dres_dcdot_function_(%s);' % c_args)
1783 c_body.append('double time = *time_ptr;')
1784 c_body.append('')
1785 self._add_assignments_to_function_body(c_body, in_c=True)
1786 c_body.append('')
1787
1788 N_dyn = len(self.dynamicVars)
1789 for res_ii, (rhs, dt) in enumerate(self._residual_terms):
1790 for wrt_ii, wrt in enumerate(self.dynamicVars.keys()):
1791 if dt == wrt:
1792 py_body.append('# Derivative of residual term %i wrt '
1793 '%s_dot' % (res_ii, wrt))
1794 py_body.append('pd[%i, %i] = -1'
1795 % (res_ii, wrt_ii))
1796 c_body.append('pd[%i] = -1;' % (res_ii+wrt_ii*N_dyn))
1797
1798 py_body.append('')
1799 py_body.append('return pd')
1800 py_body = '\n '.join(py_body)
1801
1802 c_body.append('}')
1803 c_body = os.linesep.join(c_body)
1804
1805 self._dynamic_funcs_python.set('dres_dcdot_function', py_body)
1806 self._dynamic_funcs_c.set('dres_dcdot_function', c_body)
1807
1809 py_body = []
1810 py_body.append('def ddaskr_jac(time, dynamicVars, yprime, cj, '
1811 'constants):')
1812 py_body.append('dynamicVars = scipy.asarray(dynamicVars)')
1813 py_body.append('yprime = scipy.asarray(yprime)')
1814 py_body.append('constants = scipy.asarray(constants)')
1815 py_body.append('')
1816 py_body.append('dres_dc = dres_dc_function(time, dynamicVars, yprime, '
1817 'constants)')
1818 py_body.append('dres_dcdot = dres_dcdot_function(time, dynamicVars, '
1819 'yprime, constants)')
1820 py_body.append('return dres_dc + cj * dres_dcdot')
1821 py_body = '\n '.join(py_body)
1822
1823 N_dyn = len(self.dynamicVars)
1824 c_body = []
1825 c_args = 'double *time_ptr, double *dynamicVars, double *yprime, '\
1826 'double *pd, double *cj_ptr, double *constants, int *intpar'
1827 c_body.append('void ddaskr_jac_(%s){' % c_args)
1828 self._prototypes_c.set('ddaskr_jac',
1829 'void ddaskr_jac_(%s);' % c_args)
1830 c_body.append('double cj = *cj_ptr;')
1831 c_body.append('')
1832 c_body.append('dres_dc_function_(time_ptr, dynamicVars, yprime, '
1833 'constants, pd);')
1834 c_body.append('')
1835
1836 c_body.append('double dres_dcdot[%i*%i] = {0};' % (N_dyn, N_dyn))
1837 c_body.append('dres_dcdot_function_(time_ptr, dynamicVars, yprime, '
1838 'constants, dres_dcdot);')
1839 c_body.append('')
1840 c_body.append('int ii;')
1841 c_body.append('for(ii=0; ii < %i; ii++){' % N_dyn**2)
1842 c_body.append(' pd[ii] += cj*dres_dcdot[ii];}')
1843 c_body.append('}')
1844 c_body = os.linesep.join(c_body)
1845
1846 self._dynamic_funcs_python.set('ddaskr_jac', py_body)
1847 self._dynamic_funcs_c.set('ddaskr_jac', c_body)
1848
1850
1851
1852 for wrt_ii, wrt in enumerate(self.optimizableVars.keys()):
1853
1854 func_name = 'dres_d' + wrt
1855
1856 py_body = []
1857 py_body.append('def ' + func_name + '(time, dynamicVars, '
1858 'yprime, constants):')
1859 py_body.append('dynamicVars = scipy.asarray(dynamicVars)')
1860 py_body.append('constants = scipy.asarray(constants)')
1861 py_body.append('')
1862 py_body.append('pd = scipy.zeros(%i, scipy.float_)'
1863 % len(self.dynamicVars))
1864 py_body.append('')
1865
1866 self._add_assignments_to_function_body(py_body)
1867 py_body.append('')
1868
1869 c_body = []
1870 c_args = 'double *time_ptr, double *dynamicVars, double *yprime, '\
1871 'double *constants, double *pd'
1872 c_body.append('void ' + func_name + '_(%s){' % c_args)
1873 self._prototypes_c.set(func_name,
1874 'void ' + func_name + '_(%s);' % c_args)
1875
1876 c_body.append('double time = *time_ptr;')
1877 c_body.append('')
1878 self._add_assignments_to_function_body(c_body, in_c=True)
1879 c_body.append('')
1880
1881 N_dyn = len(self.dynamicVars)
1882 N_opt = len(self.optimizableVars)
1883
1884
1885
1886
1887 rhs_vars = {}
1888 for (rhs, dt) in self._residual_terms:
1889 if rhs is None:
1890 rhs = '0'
1891 rhs_vars[rhs] = ExprManip.extract_vars(rhs)
1892
1893 for res_ii, (rhs, dt) in enumerate(self._residual_terms):
1894 if rhs is None:
1895 rhs = '0'
1896 rhs_vars_used = rhs_vars[rhs]
1897 deriv = self.takeDerivative(rhs, wrt, rhs_vars_used)
1898 if (deriv != '0' and deriv != '0.0'):
1899 py_body.append('pd[%i] = %s' % (res_ii, deriv))
1900 c_deriv = ExprManip.make_c_compatible(deriv)
1901 c_body.append('pd[%i] = %s;' % (res_ii, c_deriv))
1902
1903 py_body.append('')
1904 py_body.append('return pd')
1905 py_body = '\n '.join(py_body)
1906
1907 c_body.append('}')
1908 c_body = os.linesep.join(c_body)
1909
1910 self._dynamic_funcs_python.set(func_name, py_body)
1911 self._dynamic_funcs_c.set(func_name, c_body)
1912
1914
1915 py_body = []
1916 py_body.append('def sens_rhs(time, sens_y, sens_yp, constants):')
1917 py_body.append('sens_y = scipy.asarray(sens_y)')
1918 py_body.append('sens_yp = scipy.asarray(sens_yp)')
1919 py_body.append('constants = scipy.asarray(constants)')
1920 py_body.append('')
1921 py_body.append('sens_res = scipy.zeros(%i, scipy.float_)'
1922 % (2*len(self.dynamicVars)))
1923 py_body.append('')
1924
1925 c_body = []
1926 c_args = 'double *time_ptr, double *sens_y, double *sens_yp, '\
1927 'double *cj_ptr, double *sens_res, int *ires_ptr, '\
1928 'double *constants, int *ipar'
1929 c_body.append('void sens_rhs_(%s){' % c_args)
1930 self._prototypes_c.set('sens_rhs',
1931 'void sens_rhs_(%s);' % c_args)
1932 c_body.append('')
1933
1934 N_dyn = len(self.dynamicVars)
1935 N_const = len(self.constantVars)
1936 py_body.append('sens_res[:%(N_dyn)i] = res_function(time, '
1937 'sens_y, sens_yp, constants)'
1938 % {'N_dyn': N_dyn})
1939 py_body.append('')
1940
1941
1942
1943 py_body.append('func_dict = {}')
1944 for wrt_ii, wrt in enumerate(self.optimizableVars.keys()):
1945 py_body.append('func_dict[' + str(wrt_ii) + '] = dres_d' + wrt)
1946
1947 py_body.append('')
1948
1949 py_body.append('p_index = int(constants[%i])' % N_const)
1950
1951
1952
1953 py_body.append('dres_dp_func = func_dict[p_index]')
1954
1955 py_body.append('')
1956
1957 py_body.append('dc_dp = sens_y[%i:]' % N_dyn)
1958 py_body.append('dcdot_dp = sens_yp[%i:]' % N_dyn)
1959 py_body.append('dres_dp = dres_dp_func(time, sens_y, sens_yp, constants)'
1960 % {'N_dyn': N_dyn, 'N_const': N_const})
1961
1962 py_body.append('dres_dc = dres_dc_function(time, '
1963 'sens_y, sens_yp, constants)'
1964 % {'N_dyn': N_dyn, 'N_const': N_const})
1965 py_body.append('dres_dcdot = dres_dcdot_function(time, '
1966 'sens_y, sens_yp, constants)'
1967 % {'N_dyn': N_dyn, 'N_const': N_const})
1968 py_body.append('sens_res[%i:] = dres_dp '
1969 '+ scipy.dot(dres_dc, dc_dp) '
1970 '+ scipy.dot(dres_dcdot, dcdot_dp)' % N_dyn)
1971
1972
1973 c_body.append('res_function_(time_ptr, sens_y, sens_yp, cj_ptr, '
1974 'sens_res, ires_ptr, constants, ipar);')
1975 c_body.append('')
1976 c_body.append('int p_index = (int)constants[%i];' % N_const)
1977
1978
1979
1980 c_body.append('double constants_only[%i];' % N_const)
1981 c_body.append('int jj;')
1982 c_body.append('for (jj = 0; jj < %s; jj++){' % N_const)
1983 c_body.append('constants_only[jj] = constants[jj];}')
1984 c_body.append('double *dc_dp = &sens_y[%i];' % N_dyn)
1985 c_body.append('double *dcdot_dp = &sens_yp[%i];' % N_dyn)
1986
1987 c_body.append('double *dres_dp = &sens_res[%i];' % N_dyn)
1988 c_body.append('int ii;')
1989
1990
1991 c_body.append('for(ii = 0; ii < %s; ii++){' % N_dyn)
1992 c_body.append('dres_dp[ii] = 0;}')
1993
1994
1995
1996 c_body.append('switch(p_index)')
1997 c_body.append('{')
1998 for wrt_ii, wrt in enumerate(self.optimizableVars.keys()):
1999 c_body.append('case ' + str(wrt_ii) + ' : dres_d' + wrt + '_(time_ptr, sens_y, sens_yp, constants_only, '
2000 'dres_dp);')
2001 c_body.append('break;'),
2002 c_body.append('}')
2003
2004 c_body.append('double dres_dc[%i] = {0};' % N_dyn**2)
2005 c_body.append('dres_dc_function_(time_ptr, sens_y, sens_yp, constants, '
2006 'dres_dc);')
2007 c_body.append('int row, col;')
2008 c_body.append('for(row = 0; row < %i; row++){' % N_dyn)
2009 c_body.append('for(col = 0; col < %i; col++){' % N_dyn)
2010 c_body.append('sens_res[row+%i] += dres_dc[row + col*%i]*dc_dp[col];}}'
2011 % (N_dyn, N_dyn))
2012
2013 c_body.append('double dres_dcdot[%i] = {0};' % N_dyn**2)
2014 c_body.append('dres_dcdot_function_(time_ptr, sens_y, sens_yp, '
2015 'constants, dres_dcdot);')
2016 c_body.append('for(row = 0; row < %i; row++){' % N_dyn)
2017 c_body.append('for(col = 0; col < %i; col++){' % N_dyn)
2018 c_body.append('sens_res[row+%i] += dres_dcdot[row + col*%i]'
2019 '*dcdot_dp[col];}}' % (N_dyn, N_dyn))
2020
2021 py_body.append('')
2022 py_body.append('return sens_res')
2023 py_body = '\n '.join(py_body)
2024
2025 c_body.append('}')
2026 c_body = os.linesep.join(c_body)
2027
2028 self._dynamic_funcs_python.set('sens_rhs', py_body)
2029 self._dynamic_funcs_c.set('sens_rhs', c_body)
2030
2032 N_dyn = len(self.dynamicVars)
2033
2034 py_body = []
2035 py_body.append('def res_function_logdv(time, log_dv, log_yp, '
2036 'constants):')
2037 py_body.append('log_dv = scipy.asarray(log_dv)')
2038 py_body.append('log_yp = scipy.asarray(log_yp)')
2039 py_body.append('dynamicVars = scipy.exp(log_dv)')
2040 py_body.append('dynamicVars = scipy.maximum(dynamicVars, %g)'
2041 % _double_tiny_)
2042 py_body.append('yprime = log_yp * dynamicVars')
2043 py_body.append('return res_function(time, dynamicVars, yprime, '
2044 'constants)')
2045 py_body = '\n '.join(py_body)
2046 self._dynamic_funcs_python.set('res_function_logdv', py_body)
2047
2048 c_body = []
2049 c_args = 'double *time_ptr, double *log_dv, double *log_yp, '\
2050 'double *cj_ptr, double *residual, int *ires_ptr, '\
2051 'double *constants, int *ipar'
2052 c_body.append('void res_function_logdv_(%s){' % c_args)
2053 self._prototypes_c.set('res_function_logdv',
2054 'void res_function_logdv_(%s);' % c_args)
2055 c_body.append('double dynamicVars[%i];' % N_dyn)
2056 c_body.append('double yprime[%i];' % N_dyn)
2057 c_body.append('int ii;')
2058 c_body.append('for(ii = 0; ii < %i; ii++){' % N_dyn)
2059 c_body.append('dynamicVars[ii] = max(exp(log_dv[ii]), DBL_MIN);')
2060 c_body.append('yprime[ii] = log_yp[ii] * dynamicVars[ii];}')
2061 c_body.append('res_function_(time_ptr, dynamicVars, yprime, cj_ptr, '
2062 'residual, ires_ptr, constants, ipar);')
2063 c_body.append('}')
2064 c_body = os.linesep.join(c_body)
2065 self._dynamic_funcs_c.set('res_function_logdv', c_body)
2066
2067 py_body = []
2068 py_body.append('def root_func_logdv(time, log_dv, log_yp, constants):')
2069 py_body.append('log_dv = scipy.asarray(log_dv)')
2070 py_body.append('log_yp = scipy.asarray(log_yp)')
2071 py_body.append('dynamicVars = scipy.exp(log_dv)')
2072 py_body.append('dynamicVars = scipy.maximum(dynamicVars, %g)'
2073 % _double_tiny_)
2074 py_body.append('yprime = log_yp * dynamicVars')
2075 py_body.append('return root_func(time, dynamicVars, yprime, '
2076 'constants)')
2077 py_body = '\n '.join(py_body)
2078 self._dynamic_funcs_python.set('root_func_logdv', py_body)
2079
2080 c_body = []
2081 c_args = 'int *neq_ptr, double *time_ptr, double *log_dv, '\
2082 'double *log_yp, int *nrt_ptr, double *root_devs, '\
2083 'double *constants, int *ipar'
2084 c_body.append('void root_func_logdv_(%s){' % c_args)
2085 self._prototypes_c.set('root_func_logdv',
2086 'void root_func_logdv_(%s);' % c_args)
2087 c_body.append('double dynamicVars[%i];' % N_dyn)
2088 c_body.append('double yprime[%i];' % N_dyn)
2089 c_body.append('int ii;')
2090 c_body.append('for(ii = 0; ii < %i; ii++){' % N_dyn)
2091 c_body.append('dynamicVars[ii] = max(exp(log_dv[ii]), DBL_MIN);')
2092 c_body.append('yprime[ii] = log_yp[ii] * dynamicVars[ii];}')
2093 c_body.append('root_func_(neq_ptr, time_ptr, dynamicVars, yprime, '
2094 'nrt_ptr, root_devs, constants, ipar);')
2095 c_body.append('}')
2096 c_body = os.linesep.join(c_body)
2097 self._dynamic_funcs_c.set('root_func_logdv', c_body)
2098
2099
2100 py_body = []
2101 py_body.append('def sens_rhs_logdv(time, sens_y, sens_yp, constants):')
2102
2103
2104 py_body.append('sens_y = scipy.array(sens_y)')
2105 py_body.append('sens_yp = scipy.array(sens_yp)')
2106 py_body.append('sens_y[:%i] = scipy.exp(sens_y[:%i])' % (N_dyn, N_dyn))
2107 py_body.append('sens_y[:%i] = scipy.maximum(sens_y[:%i], %g)'
2108 % (N_dyn, N_dyn, _double_tiny_))
2109 py_body.append('sens_yp[:%i] = sens_yp[:%i] * sens_y[:%i]'
2110 % (N_dyn, N_dyn, N_dyn))
2111 py_body.append('return sens_rhs(time, sens_y, sens_yp, constants)')
2112 py_body = '\n '.join(py_body)
2113 self._dynamic_funcs_python.set('sens_rhs_logdv', py_body)
2114
2115 c_body = []
2116 c_args = 'double *time_ptr, double *sens_y_log, double *sens_yp_log, '\
2117 'double *cj_ptr, double *sens_res, int *ires_ptr, '\
2118 'double *constants, int *ipar'
2119 c_body.append('void sens_rhs_logdv_(%s){' % c_args)
2120 self._prototypes_c.set('sens_rhs_logdv_',
2121 'void sens_rhs_logdv_(%s);' % c_args)
2122 c_body.append('double sens_y[%i];' % (N_dyn*2))
2123 c_body.append('double sens_yp[%i];' % (N_dyn*2))
2124 c_body.append('int ii;')
2125 c_body.append('for(ii = 0; ii < %i; ii++){' % N_dyn)
2126 c_body.append('sens_y[ii] = max(exp(sens_y_log[ii]), DBL_MIN);')
2127 c_body.append('sens_yp[ii] = sens_yp_log[ii] * sens_y[ii];}')
2128 c_body.append('for(ii = %i; ii < %i; ii++){' % (N_dyn, 2*N_dyn))
2129 c_body.append('sens_y[ii] = sens_y_log[ii];')
2130 c_body.append('sens_yp[ii] = sens_yp_log[ii];}')
2131 c_body.append('sens_rhs_(time_ptr, sens_y, sens_yp, cj_ptr, sens_res, '
2132 'ires_ptr, constants, ipar);')
2133 c_body.append('}')
2134 c_body = os.linesep.join(c_body)
2135 self._dynamic_funcs_c.set('sens_rhs_logdv', c_body)
2136
2137
2139
2140 py_body = []
2141 py_body.append('def integrate_stochastic_tidbit'
2142 '(seed, reseed, time, dv, cv, rmsd, stop_time):')
2143
2144 c_args = 'unsigned long* seed_ptr, int* reseed, double* time_ptr, '\
2145 'int* dv, double* cv, '\
2146 'double* rmsd_ptr, double* stop_time_ptr, double* trajectory'
2147 c_body = []
2148 c_body.append('void integrate_stochastic_tidbit_(%s) {'%c_args)
2149
2150
2151 err_body = []
2152 if len(self.reactions) == 0:
2153 err_body.append('# No reactions present.')
2154 if len(self.rateRules) > 0:
2155 err_body.append('# %i rate rules are present'%len(self.rateRules))
2156 if len([_ for _ in self.events if not _.timeTriggered]) > 0:
2157 err_body.append('# %i non-time-triggered events are present'%\
2158 len([_ for _ in self.events \
2159 if not _.timeTriggered]))
2160 if len(self.algebraicRules) > 0:
2161 err_body.append('# %i algebraic rules are present'%
2162 len(self.algebraicRules))
2163 if len(self.algebraicVars) > 0:
2164 err_body.append('# %i algebraic variables are present'%
2165 len(self.algebraicRules))
2166 for rxn in self.reactions.values():
2167 for val in rxn.stoichiometry.values():
2168 try: intVal = int(val)
2169 except: intVal = None
2170 if intVal is None:
2171 err_body.append('# Noncastable stoichiometry for %s: %s'%
2172 (rxn.id, repr(val)))
2173 elif intVal != val:
2174 err_body.append('# Reaction stoichiometry for %s: %s!=%s'%
2175 (rxn.id, repr(val), repr(intVal)))
2176
2177 if err_body!=[]:
2178 py_body = py_body + err_body
2179 py_body.append('pass')
2180 py_body = '\n '.join(py_body)
2181 self._dynamic_funcs_python.set('integrate_stochastic_tidbit',
2182 py_body)
2183
2184 c_body.append('return;}')
2185 c_body = os.linesep.join(c_body)
2186 self._prototypes_c.set('integrate_stochastic_tidbit',
2187 'void integrate_stochatic_tidbit_(%s);' %
2188 c_args)
2189 self._dynamic_funcs_c.set('integrate_stochastic_tidbit', c_body)
2190
2191 return
2192
2193 N_CON = len(self.constantVars)
2194 N_DYN = len(self.dynamicVars)
2195 N_ASN = len(self.assignedVars)
2196 N_RXN = len(self.reactions)
2197
2198
2199 mapping = {}
2200 for index, name in enumerate(self.constantVars.keys()):
2201 mapping[name] = 'cv[%i]'%index
2202 for index, name in enumerate(self.dynamicVars.keys()):
2203 mapping[name] = 'dv[%i]'%index
2204 for index, name in enumerate(self.assignedVars.keys()):
2205 mapping[name] = 'av[%i]'%index
2206
2207 class Parse(ExprManip.AST.compiler.visitor.ASTVisitor):
2208 def __call__(slf,s,c=True):
2209 if c: s = ExprManip.make_c_compatible(s)
2210 ast = ExprManip.strip_parse(s)
2211 ExprManip.AST.compiler.walk(ast, slf)
2212 return ExprManip.ast2str(ast)
2213
2214 def visitName(slf,node,*args):
2215 if mapping.has_key(node.name): node.name=mapping[node.name]
2216 parse = Parse()
2217
2218
2219 asnKeys = self.assignedVars.keys()
2220 evars = []
2221 for rxnInd, rxn in enumerate(self.reactions.values()):
2222 evar = ExprManip.Extraction.extract_vars(rxn.kineticLaw)
2223 evar = sets.Set(evar)
2224 while len(evar.intersection(asnKeys)):
2225 for asnName in evar.intersection(asnKeys):
2226 rule = self.assignmentRules.get(asnName)
2227 evar.remove(asnName)
2228 evar.union_update( \
2229 ExprManip.Extraction.extract_vars(rule))
2230 evars.append(evar)
2231
2232 stch_body = []
2233 depd_body = []
2234 for rxnInd, (rxn_id, rxn) in enumerate(self.reactions.items()):
2235 stch_body.append(repr([int(rxn.stoichiometry.get(_,0))
2236 for _ in self.dynamicVars.keys()])[1:-1])
2237 varNames = sets.Set([n
2238 for n,v in rxn.stoichiometry.items() if v!=0])
2239 depd = [int(len(evar.intersection(varNames))>0) for evar in evars]
2240 depd_body.append(repr(depd)[1:-1])
2241 if N_RXN>0: depd_body.append(repr([1]*N_RXN)[1:-1])
2242
2243
2244 py_body.append('import numpy.random')
2245 py_body.append('if reseed: rs = numpy.random.seed(seed)')
2246 py_body.append('')
2247 if N_RXN > 0:
2248 py_body.append('stch = [[%s]]' % '],\n ['.join(stch_body))
2249 py_body.append('depd = [[%s]]' % '],\n ['.join(depd_body))
2250 else:
2251 py_body.append('stch = [[]]')
2252 py_body.append('depd = [[]]')
2253 py_body.append('')
2254 py_body.append('av = [0.0]*%i'%N_ASN)
2255 py_body.append('dv0 = [_ for _ in dv]')
2256 py_body.append('props = [0.0]*%i'%N_RXN)
2257 py_body.append('rxnInd = %i'%N_RXN)
2258 py_body.append('while time < stop_time:')
2259 for index, rule in enumerate(self.assignmentRules.values()):
2260 py_body.append(' av[%i]=%s;'%(index, parse(rule, False)))
2261 py_body.append('')
2262 for index, rxn in enumerate(self.reactions.values()):
2263 py_body.append(' if depd[rxnInd][%i]: props[%i]=%s'%
2264 (index, index, parse(rxn.kineticLaw, False)))
2265 py_body.append(' propensity=sum(props)')
2266 py_body.append(' if propensity==0.0:')
2267 py_body.append(' dt = stop_time - time')
2268 py_body.append(' time=stop_time')
2269 py_body.append(' break')
2270 py_body.append(' ')
2271 py_body.append(' dt = -log(1.0-numpy.random.rand())/propensity')
2272 py_body.append(' time += dt')
2273 py_body.append(' ')
2274 py_body.append(' selection=propensity*numpy.random.rand()')
2275 py_body.append(' for rxnInd in range(%i):'%N_RXN)
2276 py_body.append(' if selection<props[rxnInd]: break')
2277 py_body.append(' else: selection-=props[rxnInd]')
2278 py_body.append(' ')
2279 py_body.append(' for index, st in enumerate(stch[rxnInd]):')
2280 py_body.append(' dv[index] += st')
2281 py_body.append(' ')
2282 py_body.append(' _rmsd = sum([(_-__)**2 for _, __ in zip(dv,dv0)])')
2283 py_body.append(' _rmsd = (_rmsd/%i.)**0.5'%N_DYN)
2284 py_body.append(' if _rmsd>rmsd: break')
2285 py_body.append('')
2286 py_body.append('if time > stop_time: # Back interpolate')
2287 py_body.append(' trajectory = ['
2288 'float(_)+float(stch[rxnInd][ii])/dt*(stop_time-time) '
2289 'for ii, _ in enumerate(dv)]')
2290 py_body.append('else:')
2291 py_body.append(' stop_time = time')
2292 py_body.append(' trajectory = [float(_) for _ in dv]')
2293 py_body.append('return time, dv, stop_time, trajectory')
2294 py_body = '\n '.join(py_body)
2295
2296
2297 c_body.append(' int i; /* Temp variables */')
2298 c_body.append('')
2299 c_body.append(' unsigned long seed = *seed_ptr;')
2300 c_body.append(' if (*reseed) {init_genrand(seed);}')
2301 c_body.append('')
2302 if N_RXN > 0:
2303 c_body.append(' short stch[%i][%i] = {{%s}};' %
2304 (N_RXN, N_DYN,
2305 '},\n {'.join(stch_body)))
2306 c_body.append(' short depd[%i+1][%i] = {{%s}};' %
2307 (N_RXN, N_RXN,
2308 '},\n {'.join(depd_body)))
2309 else:
2310 c_body.append(' short stch[0][0];')
2311 c_body.append('')
2312 c_body.append(' double time = *time_ptr;')
2313 c_body.append(' double sd = (*rmsd_ptr)*(*rmsd_ptr)*%i.;'%N_DYN)
2314 c_body.append(' double stop_time = *stop_time_ptr;')
2315 c_body.append(' double dt=0.0;')
2316 c_body.append('')
2317 c_body.append(' double dv0[%i];'%N_DYN)
2318 c_body.append(' for (i=0;i<%i;i++) {dv0[i]=dv[i];}'%N_DYN)
2319 c_body.append('')
2320 c_body.append(' int rxnInd = %i;'%N_RXN)
2321 c_body.append(' double propensity, selection, props[%i], av[%i];'%
2322 (N_RXN, N_ASN))
2323 c_body.append(' while (time < stop_time) {')
2324 for index, rule in enumerate(self.assignmentRules.values()):
2325 c_body.append(' av[%i]=%s;'%(index, parse(rule)))
2326 c_body.append('')
2327 for index, rxn in enumerate(self.reactions.values()):
2328 c_body.append(" if (depd[rxnInd][%i]) {props[%i]=%s;}"% \
2329 (index, index, parse(rxn.kineticLaw)))
2330 c_body.append('')
2331 c_body.append(' propensity = 0.0;')
2332 c_body.append(' for (i=0;i<%i;i++) {'%N_RXN)
2333 c_body.append(' propensity += props[i];}')
2334 c_body.append(' if (propensity<=0.0) {')
2335 c_body.append(' dt = stop_time-time;')
2336 c_body.append(' time = stop_time;')
2337 c_body.append(' break;')
2338 c_body.append(' }')
2339 c_body.append('')
2340 c_body.append(' dt = -log(1.0-genrand_real32())/propensity;')
2341 c_body.append(' time += dt;')
2342 c_body.append('')
2343 c_body.append(' selection = propensity * genrand_real32();')
2344 c_body.append('')
2345 c_body.append(' for (rxnInd=0; rxnInd<%i; rxnInd++) {'%N_RXN)
2346 c_body.append(' if (selection < props[rxnInd]) {break;}')
2347 c_body.append(' else {selection -= props[rxnInd];}}')
2348 c_body.append('')
2349 c_body.append(' for (i=0;i<%i;i++) {dv[i]+=stch[rxnInd][i];}'%N_DYN)
2350 c_body.append('')
2351 c_body.append(' double _sd = 0.0;')
2352 c_body.append(' for (i=0;i<%i;i++) {'%N_DYN)
2353 c_body.append(' _sd += (dv0[i]-dv[i])*(dv0[i]-dv[i]);')
2354 c_body.append(' }')
2355 c_body.append(' if (_sd > sd) {break;}')
2356 c_body.append(' }')
2357 c_body.append('')
2358 c_body.append(' for (i=0;i<%i;i++) {'%N_DYN)
2359 c_body.append(' trajectory[i]=(double)dv[i];')
2360 c_body.append(' if (time > stop_time) {')
2361 c_body.append(' trajectory[i] += (double)stch[rxnInd][i]/dt*'
2362 '(stop_time - time);')
2363 c_body.append(' }')
2364 c_body.append(' }')
2365 c_body.append(' if (time>stop_time) {(*stop_time_ptr) = stop_time;}')
2366 c_body.append(' else {(*stop_time_ptr) = time;}')
2367 c_body.append('')
2368 c_body.append(' (*time_ptr) = time;')
2369 c_body.append('}')
2370 c_body.append('')
2371 c_body = os.linesep.join(c_body)
2372
2373 self._prototypes_c.set('integrate_stochastic_tidbit',
2374 'void integrate_stochatic_tidbit_(%s);' % c_args)
2375
2376 self._dynamic_funcs_python.set('integrate_stochastic_tidbit', py_body)
2377 self._dynamic_funcs_c.set('integrate_stochastic_tidbit', c_body)
2378
2379
2380 - def _add_assignments_to_function_body(self, body, in_c = False,
2381 include_dts=False):
2382 """
2383 Adds the assignment rules for this Network to the list of lines that
2384 are in body.
2385 """
2386
2387
2388
2389
2390
2391 for arg, var_names in zip(['constants', 'dynamicVars'],
2392 [self.constantVars.keys(),
2393 self.dynamicVars.keys()]):
2394 for ii, id in enumerate(var_names):
2395 if not in_c:
2396 body.append('%s = %s.item(%i)' % (id, arg, ii))
2397 if include_dts and arg != 'constants':
2398 body.append('%s_deriv_wrt_time = yprime.item(%i)'
2399 % (id,ii))
2400 else:
2401 body.append('double %s = %s[%i];' % (id, arg, ii))
2402 if include_dts and arg != 'constants':
2403 body.append('double %s_deriv_wrt_time = yprime[%i];'
2404 % (id,ii))
2405 body.append('')
2406
2407 for variable, math in self.assignmentRules.items():
2408 if not in_c:
2409 body.append('%s = %s' % (variable, math))
2410 else:
2411 c_math = ExprManip.make_c_compatible(math)
2412 body.append('double %s = %s;' % (variable, c_math))
2413 if include_dts:
2414
2415
2416
2417 rhs_terms = ['0']
2418
2419 dep_vars = ExprManip.extract_vars(math)
2420
2421
2422 for dynvar in dep_vars.intersection(self.dynamicVars.keys()):
2423 dmath_dvar = ExprManip.diff_expr(math, dynvar)
2424 rhs_terms.append('%s * %s_deriv_wrt_time'
2425 % (dmath_dvar, dynvar))
2426
2427 if 'time' in dep_vars:
2428 dmath_dtime = ExprManip.diff_expr(math, 'time')
2429 rhs_terms.append(dmath_dtime)
2430
2431 rhs = ' + '.join(rhs_terms)
2432 rhs = ExprManip.simplify_expr(rhs)
2433 if not in_c:
2434 body.append('%s_deriv_wrt_time = %s' % (variable, rhs))
2435 else:
2436 c_rhs = ExprManip.make_c_compatible(rhs)
2437 body.append('double %s_deriv_wrt_time = %s;'
2438 % (variable, c_rhs))
2439
2440 return body
2441
2442
2443
2444
2445 - def fireEvent(self, event, dynamicVarValues, time):
2450
2451 - def executeEvent(self, event, time_fired, y_fired, y_current, time_current):
2452
2453
2454 self.updateVariablesFromDynamicVars(y_fired, time_fired)
2455 new_values = {}
2456 var_vals = [(id, self.get_var_val(id)) for id in self.variables.keys()]
2457 var_vals = dict(var_vals)
2458 var_vals['time'] = time_fired
2459
2460 for id, rhs in event.event_assignments.items():
2461 new_values[id] = self.evaluate_expr(rhs, time_fired, var_vals)
2462
2463
2464 for id, value in new_values.items():
2465 y_current[self.dynamicVars.indexByKey(id)] = value
2466
2467 self.updateVariablesFromDynamicVars(y_current, time_current)
2468
2469 return y_current
2470
2472 ast = ExprManip.strip_parse(trigger)
2473 if len(ast.ops) != 1:
2474 raise ValueError('Comparison has more than one operation in '
2475 'clause %s!' % trigger)
2476 lhs = ExprManip.ast2str(ast.expr)
2477 rhs = ExprManip.ast2str(ast.ops[0][1])
2478 if ast.ops[0][0] in ['>', '>=']:
2479 return '%s - %s' % (lhs, rhs)
2480 elif ast.ops[0][0] in ['<', '<=']:
2481 return '-%s + %s' % (lhs, rhs)
2482 else:
2483 raise ValueError('Comparison %s in triggering clause is not '
2484 '<, <=, >, or >=!')
2485
2486
2487
2488
2489
2490
2491
2492 _sens_event_derivs_cache = []
2494 curr_struct = self._get_structure()
2495 curr_events = copy.deepcopy(self.events)
2496
2497
2498 for struct, events, derivs_cache in self._sens_event_derivs_cache:
2499 if curr_struct == struct and curr_events == events:
2500 break
2501 else:
2502 derivs_cache = {}
2503 self._sens_event_derivs_cache.append((curr_struct, curr_events,
2504 derivs_cache))
2505
2506
2507 event = holder.event
2508 time_fired = holder.time_fired
2509 ysens_fired = holder.ysens_fired
2510 yp_fired = holder.yp_fired
2511 clause_index = holder.clause_index
2512 time_exec = holder.time_exec
2513 yp_pre_exec = holder.yp_pre_exec
2514 y_post_exec = holder.y_post_exec
2515 yp_post_exec = holder.yp_post_exec
2516
2517
2518
2519
2520
2521
2522
2523 dtf_dp = None
2524 link = holder
2525 while link.chained_off_of is not None:
2526 dtf_dp = link.chained_off_of.dte_dp
2527 link = link.chained_off_of
2528
2529 ysens_post_exec = copy.copy(ysens_pre_exec)
2530
2531 N_dv = len(self.dynamicVars)
2532 ysens_post_exec[:N_dv] = y_post_exec
2533
2534
2535
2536 self.updateVariablesFromDynamicVars(ysens_fired, time_fired)
2537 var_vals_fired = [(id, self.get_var_val(id)) for id
2538 in self.variables.keys()]
2539 var_vals_fired = dict(var_vals_fired)
2540 var_vals_fired['time'] = time
2541
2542 if dtf_dp is None:
2543
2544
2545
2546
2547 trigger = self.event_clauses[clause_index]
2548 trigger = self._smooth_trigger(trigger)
2549 trigger_vars_used = ExprManip.extract_vars(trigger)
2550
2551
2552
2553
2554
2555
2556 numerator = 0
2557 denominator = 0
2558
2559
2560 for ii, id in enumerate(self.dynamicVars.keys()):
2561 try:
2562 dtrigger_ddv = derivs_cache[(trigger, id)]
2563 except KeyError:
2564 dtrigger_ddv = self.takeDerivative(trigger, id,
2565 trigger_vars_used)
2566 derivs_cache[(trigger, id)] = dtrigger_ddv
2567 dtrigger_ddv = self.evaluate_expr(dtrigger_ddv, time_fired,
2568 var_vals_fired)
2569
2570 index_in_y = ii + N_dv
2571 ddv_dp = ysens_fired[index_in_y]
2572 ddv_dt = yp_fired[ii]
2573 numerator += dtrigger_ddv * ddv_dp
2574 denominator += dtrigger_ddv * ddv_dt
2575
2576
2577 dtrigger_dp = self.takeDerivative(trigger, opt_var,
2578 trigger_vars_used)
2579 dtrigger_dp = self.evaluate_expr(dtrigger_dp, time_fired,
2580 var_vals_fired)
2581 numerator += dtrigger_dp
2582
2583
2584 dtrigger_dt = self.takeDerivative(trigger, 'time',
2585 trigger_vars_used)
2586 dtrigger_dt = self.evaluate_expr(dtrigger_dt, time_fired,
2587 var_vals_fired)
2588 denominator += dtrigger_dt
2589
2590 dtf_dp = -numerator/denominator
2591
2592
2593
2594
2595
2596 delay = event.delay
2597 if not isinstance(delay, str):
2598 ddelay_dp = 0
2599 else:
2600
2601 delay_vars_used = ExprManip.extract_vars(delay)
2602 ddelay_dp = self.takeDerivative(delay, opt_var, delay_vars_used)
2603 ddelay_dp = self.evaluate_expr(ddelay_dp, time_fired,
2604 var_vals_fired)
2605
2606
2607 for ii, id in enumerate(self.dynamicVars.keys()):
2608 try:
2609 ddelay_dy = derivs_cache[(delay, id)]
2610 except KeyError:
2611 ddelay_dy = self.takeDerivative(delay, id, delay_vars_used)
2612 derivs_cache[(delay, id)] = ddelay_dy
2613 ddelay_dy = self.evaluate_expr(ddelay_dy, time_fired,
2614 var_vals_fired)
2615
2616 index_in_y = ii + N_dv
2617 dy_dp = ysens_fired[index_in_y]
2618 dy_dt = yp_fired[ii]
2619 ddelay_dp += ddelay_dy * dy_dp
2620 ddelay_dp += ddelay_dy * dy_dt * dtf_dp
2621
2622
2623 ddelay_dt = self.takeDerivative(delay, 'time', delay_vars_used)
2624 ddelay_dt = self.evaluate_expr(ddelay_dt, time_fired,
2625 var_vals_fired)
2626 ddelay_dp += ddelay_dt * dtf_dp
2627
2628
2629 dte_dp = dtf_dp + ddelay_dp
2630
2631
2632
2633 holder.dte_dp = dte_dp
2634
2635
2636
2637 self.updateVariablesFromDynamicVars(ysens_pre_exec, time_exec)
2638 var_vals_pre_exec = [(id, self.get_var_val(id)) for id
2639 in self.variables.keys()]
2640 var_vals_pre_exec = dict(var_vals_pre_exec)
2641 var_vals_pre_exec['time'] = time
2642
2643
2644 for y_ii, y_id in enumerate(self.dynamicVars.keys()):
2645 if not event.event_assignments.has_key(y_id):
2646
2647 index_in_y = y_ii + N_dv
2648
2649
2650 dy_dp_post_exec = ysens_pre_exec[index_in_y]
2651
2652
2653
2654 dy_dp_post_exec += yp_pre_exec[y_ii] * dte_dp
2655
2656 dy_dp_post_exec -= yp_post_exec[y_ii] * dte_dp
2657 ysens_post_exec[index_in_y] = dy_dp_post_exec
2658 else:
2659
2660
2661 a = event.event_assignments.get(y_id)
2662 if not isinstance(a, str):
2663
2664 dy_dp_post_exec = -yp_post_exec[y_ii] * dte_dp
2665 index_in_y = y_ii + N_dv
2666 ysens_post_exec[index_in_y] = dy_dp_post_exec
2667 else:
2668
2669
2670
2671
2672
2673
2674 a = self._sub_for_piecewise(a, time_fired)
2675 a_vars_used = ExprManip.extract_vars(a)
2676
2677
2678 da_dp = self.takeDerivative(a, opt_var, a_vars_used)
2679 da_dp = self.evaluate_expr(da_dp, time_fired,
2680 var_vals_fired)
2681 dy_dp_post_exec = da_dp
2682
2683
2684
2685
2686 for other_ii,other_id in enumerate(self.dynamicVars.keys()):
2687 try:
2688 da_dother = derivs_cache[(a, other_id)]
2689 except KeyError:
2690 da_dother = self.takeDerivative(a, other_id,
2691 a_vars_used)
2692 derivs_cache[(a, other_id)] = da_dother
2693 da_dother = self.evaluate_expr(da_dother, time_fired,
2694 var_vals_fired)
2695
2696
2697 index_in_y = other_ii + N_dv
2698 dother_dp = ysens_fired[index_in_y]
2699
2700 dother_dt = yp_fired[other_ii]
2701
2702 dy_dp_post_exec += da_dother * dother_dp
2703 dy_dp_post_exec += da_dother * dother_dt * dtf_dp
2704
2705
2706 da_dt = self.takeDerivative(a, 'time', a_vars_used)
2707 da_dt = self.evaluate_expr(da_dt, time_fired,
2708 var_vals_fired)
2709 dy_dp_post_exec += da_dt * dtf_dp
2710
2711
2712
2713 dy_dp_post_exec -= yp_post_exec[y_ii] * dte_dp
2714
2715 index_in_y = y_ii + N_dv
2716 ysens_post_exec[index_in_y] = dy_dp_post_exec
2717
2718 return ysens_post_exec
2719
2720
2721
2722
2724 """
2725 Create the cross-reference lists for the Network.
2726 """
2727 self.assignedVars = KeyedList()
2728 self.constantVars = KeyedList()
2729 self.optimizableVars = KeyedList()
2730 self.dynamicVars = KeyedList()
2731 self.algebraicVars = KeyedList()
2732
2733 self.compartments = KeyedList()
2734 self.parameters = KeyedList()
2735 self.species = KeyedList()
2736 mapping = {Compartment: self.compartments,
2737 Parameter: self.parameters,
2738 Species: self.species}
2739
2740 for id, var in self.variables.items():
2741 mapping[var.__class__].set(id, var)
2742 if var.is_constant:
2743 self.constantVars.set(id, var)
2744 if var.is_optimizable:
2745 self.optimizableVars.set(id, var)
2746 elif id in self.assignmentRules.keys():
2747 self.assignedVars.set(id, var)
2748 else:
2749 self.dynamicVars.set(id, var)
2750
2751 self.constantVarValues = [self.evaluate_expr(var.value) for var in
2752 self.constantVars.values()]
2753 self.constantVarValues = scipy.array(self.constantVarValues)
2754
2755
2756 vars_in_alg_rules = sets.Set()
2757 for rule in self.algebraicRules:
2758 vars_in_alg_rules.union_update(ExprManip.extract_vars(rule))
2759
2760
2761
2762
2763 assigned_in_alg = vars_in_alg_rules.intersection(sets.Set(
2764 self.assignedVars.keys()))
2765
2766
2767 while assigned_in_alg:
2768
2769
2770 for assigned_var in assigned_in_alg:
2771 vars_in_alg_rules.union_update(ExprManip.extract_vars(
2772 self.assignmentRules.get(assigned_var)))
2773 vars_in_alg_rules.remove(assigned_var)
2774
2775
2776 assigned_in_alg = vars_in_alg_rules.intersection(
2777 sets.Set(self.assignedVars.keys()))
2778
2779
2780
2781
2782
2783
2784 vars_in_alg_rules.intersection_update(sets.Set(self.dynamicVars.keys()))
2785
2786
2787 for rxn in self.reactions:
2788 for chem, value in rxn.stoichiometry.items():
2789 if value != 0 and (chem in vars_in_alg_rules):
2790 vars_in_alg_rules.remove(chem)
2791
2792
2793 for var in self.rateRules.keys():
2794 if (var in vars_in_alg_rules):
2795 vars_in_alg_rules.remove(var)
2796
2797
2798 for e in self.events:
2799 for var in e.event_assignments.keys():
2800 if (var in vars_in_alg_rules):
2801 vars_in_alg_rules.remove(var)
2802
2803
2804
2805 sorted_alg_vars = [(id, self.variables.get(id))
2806 for id in self.dynamicVars.keys()
2807 if id in vars_in_alg_rules]
2808 self.algebraicVars = KeyedList(sorted_alg_vars)
2809
2810
2812 """
2813 Disables the creation of derivative functions, which can speed up
2814 integration.
2815 """
2816
2817 if self.deriv_funcs_enabled == True:
2818 self.ddaskr_jac = None
2819 self._dynamic_structure_methods = ['_make_res_function',
2820 '_make_alg_deriv_func',
2821 '_make_alg_res_func',
2822 '_make_integrate_stochastic_tidbit'
2823 ]
2824 self.deriv_funcs_enabled = False
2825
2827 """
2828 Enables the creation of derivative functions, which allows
2829 sensitivity integration and may speed up normal integration
2830 as well.
2831 """
2832
2833 if self.deriv_funcs_enabled == False:
2834 self._dynamic_structure_methods = ['_make_res_function',
2835 '_make_alg_deriv_func',
2836 '_make_alg_res_func',
2837 '_make_dres_dc_function',
2838 '_make_dres_dcdot_function',
2839 '_make_ddaskr_jac',
2840 '_make_dres_dsinglep',
2841 '_make_sens_rhs',
2842 '_make_log_funcs',
2843 '_make_integrate_stochastic_tidbit'
2844 ]
2845 self.deriv_funcs_enabled = True
2846
2847
2848 _last_structure = None
2849
2850 disable_c = SloppyCell.disable_c
2851 _last_disabled_c = disable_c
2852 - def compile(self, disable_c=None):
2853 """
2854 Create the dynamically-generated functions for this Network.
2855
2856 Note that if a model involves many copies of the same network, with
2857 differences only in events or initial conditions, it will save time
2858 to compile the base Network before copying it.
2859 """
2860
2861
2862
2863
2864
2865 if disable_c is None:
2866 disable_c = self.disable_c
2867
2868 curr_structure = self._get_structure()
2869 structure_changed = (curr_structure != self._last_structure)
2870 if structure_changed:
2871 self._last_structure = copy.deepcopy(curr_structure)
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882 all_dynamic_keys = sets.Set(self._dynamic_funcs_python.keys())
2883 all_dynamic_keys.union_update(self._dynamic_funcs_c.keys())
2884 for dynamic_func in all_dynamic_keys:
2885 try:
2886 delattr(self, dynamic_func)
2887 except AttributeError:
2888 pass
2889
2890 self._dynamic_funcs_python = KeyedList()
2891 self._prototypes_c = self._common_prototypes_c.copy()
2892 self._dynamic_funcs_c = KeyedList()
2893
2894 reexec = False
2895 if structure_changed:
2896 logger.debug('Network %s: compiling structure.' % self.id)
2897 self._makeCrossReferences()
2898
2899 if len(self.algebraicVars) > len(self.algebraicRules):
2900 raise ValueError('System appears under-determined. '
2901 'Not enough algebraic rules. '
2902 '\n algebraicVars (%i) = \n%s '
2903 '\n algebraicRules (%i) = \n%s '%(len(self.algebraicVars), self.algebraicVars,
2904 len(self.algebraicRules), self.algebraicRules))
2905 self.make_func_defs()
2906 self._makeDiffEqRHS()
2907 for method in self._dynamic_structure_methods:
2908 getattr(self, method)()
2909 reexec = True
2910
2911 if self.events != getattr(self, '_last_events', None)\
2912 or structure_changed:
2913 logger.debug('Network %s: compiling events.' % self.id)
2914 self._makeCrossReferences()
2915 for method in self._dynamic_event_methods:
2916 getattr(self, method)()
2917 self._last_events = copy.deepcopy(self.events)
2918 reexec = True
2919
2920
2921
2922 if len(self.algebraicVars) > len(self.algebraicRules):
2923 raise ValueError('System appears under-determined. '
2924 'Not enough algebraic rules. '
2925 '\n algebraicVars (%i) = \n%s '
2926 '\n algebraicRules (%i) = \n%s '%(len(self.algebraicVars), self.algebraicVars,
2927 len(self.algebraicRules), self.algebraicRules))
2928
2929 if self._last_disabled_c != disable_c:
2930 self._last_disabled_c = disable_c
2931 reexec = True
2932
2933 self.compiled=True
2934 if reexec:
2935 self.exec_dynamic_functions(disable_c=disable_c)
2936
2938 """
2939 Return a tuple representing the structure of the Network.
2940
2941 The tuple contains the functionDefinitions, reactions, and rules for
2942 the Network. It also contains information on the constancy and
2943 optimizability of the variables.
2944 """
2945 var_struct = {}
2946 structure = (self.functionDefinitions, self.reactions,
2947 self.assignmentRules, self.rateRules, var_struct,
2948 self.algebraicRules)
2949 for id, var in self.variables.items():
2950
2951
2952
2953 if isinstance(self.get_var_ic(id), str):
2954 var_struct[id] = (var.is_constant, var.is_optimizable,
2955 self.get_var_ic(id))
2956 else:
2957 var_struct[id] = (var.is_constant, var.is_optimizable)
2958
2959 return structure
2960
2961
2962
2963 _py_func_dict_cache = {}
2964 _c_module_cache = {}
2965
2968
2969 curr_py_bodies = '\n'.join([body for body in self._dynamic_funcs_python.values()\
2970 if body != None])
2971
2972 key = (curr_py_bodies, tuple(self._func_strs.items()))
2973
2974 try:
2975 py_func_dict = self._py_func_dict_cache[key]
2976 except KeyError:
2977
2978 py_func_dict = {}
2979 self._py_func_dict_cache[key] = py_func_dict
2980 for func_name, body in self._dynamic_funcs_python.items():
2981 if body != None:
2982 exec body in self.namespace, locals()
2983 py_func_dict[func_name] = locals()[func_name]
2984
2985
2986 for func_name, func in py_func_dict.items():
2987 setattr(self, func_name, func)
2988 self.namespace[func_name] = func
2989
2990 if disable_c:
2991 return
2992
2993 if curr_c_code is None:
2994 curr_c_code = self.get_c_code()
2995
2996 try:
2997 c_module = self._c_module_cache[curr_c_code]
2998 except KeyError:
2999
3000
3001 module_name = self.output_c(curr_c_code)
3002 try:
3003
3004
3005 self.run_f2py(module_name, hide_f2py_output=True)
3006 c_module = __import__(module_name)
3007 if del_c_files:
3008 os.unlink('%s.pyf' % module_name)
3009 os.unlink('%s.c' % module_name)
3010 try:
3011 os.unlink('%s.so' % module_name)
3012 except OSError:
3013 pass
3014 try:
3015 os.unlink('%s.pyd' % module_name)
3016 except OSError:
3017 pass
3018 except ImportError, X:
3019
3020 logger.warn('Failed to import dynamically compiled C module %s '
3021 'for network %s.' % (module_name, self.get_id()))
3022 logger.warn(X)
3023
3024
3025 c_module = None
3026 self._c_module_cache[curr_c_code] = c_module
3027
3028
3029 if c_module is not None:
3030 self.import_c_funcs_from_module(c_module)
3031
3033
3034 c_code = []
3035 c_code.append('#include <math.h>')
3036 c_code.append('#include <stdio.h>')
3037 c_code.append('#include <float.h>')
3038 c_code.append('#include "mtrand.h"')
3039 c_code.append('#define exponentiale M_E')
3040 c_code.append('#define pi M_PI')
3041 c_code.append('double max(double a, double b){')
3042 c_code.append('return a > b ? a : b;}')
3043
3044
3045 for func_name, proto in self._prototypes_c.items():
3046 c_code.append(proto)
3047 c_code.append('')
3048
3049 for function, body in self._common_func_strs_c.items():
3050 c_code.append(body)
3051 c_code.append('')
3052
3053 for func_name, body in self._func_defs_c.items():
3054 c_code.append(body)
3055 c_code.append('')
3056
3057 for func_name, body in self._dynamic_funcs_c.items():
3058 c_code.append(body)
3059 c_code.append('')
3060
3061 c_code = '\n'.join(code for code in c_code if code != None)
3062 return c_code
3063
3064 - def output_c(self, c_code, mod_name=None):
3065 logger.debug('Outputting C for network %s.' % self.get_id())
3066 if mod_name is None:
3067 semi_unique = str(time.time())
3068 mod_name = '%s_%i_%s' % (self.get_id(), SloppyCell.my_rank,
3069 semi_unique[::-1])
3070 mod_name = mod_name.replace('-', '_')
3071
3072 mod_name = mod_name.replace('.', '_')
3073
3074
3075 c_fd = open('%s.c' % mod_name, 'w')
3076 c_fd.write(c_code)
3077 c_fd.close()
3078
3079
3080
3081 if self.deriv_funcs_enabled != True:
3082 pyf_base_filename = os.path.join(SloppyCell.__path__[0],
3083 'ReactionNetworks',
3084 'f2py_signatures_no_derivs.pyf')
3085 else:
3086 pyf_base_filename = os.path.join(SloppyCell.__path__[0],
3087 'ReactionNetworks',
3088 'f2py_signatures.pyf')
3089
3090 pyf_base_fd = file(pyf_base_filename, 'r')
3091 pyf_base = pyf_base_fd.read()
3092
3093 pyf_base_fd.close()
3094
3095 N_dyn = len(self.dynamicVars)
3096 N_const = len(self.constantVars)
3097 N_alg = len(self.algebraicVars)
3098
3099
3100
3101
3102
3103 dres_dparams_code = ''
3104 if self.deriv_funcs_enabled == True:
3105 for wrt_ii, wrt in enumerate(self.optimizableVars.keys()):
3106 func_name = 'dres_d' + wrt
3107 dres_dparams_code += ' subroutine ' + func_name + '(time, dynamicVars, yprime, constants, pd)\n'
3108 dres_dparams_code += ' double precision intent(in) :: time\n'
3109 dres_dparams_code += ' double precision intent(in), dimension(' + str(N_dyn) + ') :: dynamicVars\n'
3110 dres_dparams_code += ' double precision intent(in), dimension(' + str(N_dyn) + ') :: yprime\n'
3111 dres_dparams_code += ' double precision intent(in), dimension(' + str(N_const) + ') :: constants\n'
3112 dres_dparams_code += ' double precision intent(out), dimension(' + str(N_dyn) + ') :: pd\n'
3113 dres_dparams_code += ' end subroutine ' + func_name + '\n'
3114
3115
3116
3117 pyf_code = pyf_base % {'dres_dparams': dres_dparams_code,
3118 'mod_name': mod_name,
3119 'N_dyn': N_dyn,
3120 'N_const': N_const,
3121 'N_alg': N_alg,
3122 'N_rt': self.len_root_func}
3123
3124
3125 pyf_fd = open('%s.pyf' % mod_name, 'w')
3126 pyf_fd.write(pyf_code)
3127 pyf_fd.close()
3128
3129 return mod_name
3130
3131 - def run_f2py(self, mod_name, hide_f2py_output=True):
3132 logger.debug('Running f2py for network %s.' % self.get_id())
3133 from numpy.distutils.exec_command import exec_command
3134
3135
3136
3137 win_options = ''
3138 if sys.platform == 'win32':
3139 win_options = '--compiler=mingw32 --fcompiler=gnu'
3140 try:
3141 if hide_f2py_output:
3142 redir = Utility.Redirector()
3143 redir.start()
3144 sc_path = os.path.join(SloppyCell.__path__[0], 'ReactionNetworks')
3145 command = '-c %(win_options)s %(mod_name)s.pyf '\
3146 '%(mod_name)s.c %(sc_path)s/mtrand.c -I%(sc_path)s'\
3147 % {'win_options': win_options, 'mod_name': mod_name,
3148 'sc_path': sc_path}
3149
3150 prev_cflags = os.getenv('CFLAGS', '')
3151 os.putenv('CFLAGS', prev_cflags + ' -Wno-unused-variable')
3152
3153
3154 oldargv = sys.argv
3155 sys.argv = ['f2py'] + command.split()
3156 import numpy.f2py.f2py2e
3157 output = numpy.f2py.f2py2e.run_compile()
3158 sys.argv = sys.argv
3159 os.putenv('CFLAGS', prev_cflags)
3160 except SystemExit, X:
3161 logger.warn('Call to f2py failed for network %s.' % self.get_id())
3162 logger.warn(X)
3163 finally:
3164 if hide_f2py_output:
3165 redir.stop()
3166
3168 for function in self._dynamic_funcs_c.keys():
3169 setattr(self, function, getattr(module, function))
3170
3171 - def takeDerivative(self, input, wrt, vars_used=None, simplify=True):
3172 """
3173 Take the derivative of a math expression wrt a given variable id.
3174
3175 Does the chain rule through assigned variables.
3176 """
3177 output = ExprManip.diff_expr(input, wrt)
3178
3179 if vars_used is None:
3180 vars_used = ExprManip.extract_vars(input)
3181
3182
3183 assigned_used = vars_used.difference(sets.Set([wrt]))
3184 assigned_used.intersection_update(sets.Set(self.assignedVars.keys()))
3185
3186 for id in assigned_used:
3187 rule = self.assignmentRules.getByKey(id)
3188 d2 = self.takeDerivative(rule, wrt, simplify=False)
3189 if d2 != '0':
3190 d = ExprManip.diff_expr(input, id)
3191 output += ' + (%s) *(%s)' % (d, d2)
3192
3193
3194 constant_used = vars_used.difference(sets.Set([wrt]))
3195 constant_used.intersection_update(sets.Set(self.constantVars.keys()))
3196
3197 for id in constant_used:
3198 ic = self.get_var_ic(id)
3199 if isinstance(ic, str):
3200 d2 = self.takeDerivative(ic, wrt, simplify=False)
3201 if d2 != '0':
3202 d = ExprManip.diff_expr(input, id)
3203 output += ' + (%s) *(%s)' % (d, d2)
3204
3205 if simplify and output != '0':
3206 return ExprManip.simplify_expr(output)
3207 else:
3208 return output
3209
3210 - def copy(self, new_id=None, new_name=None):
3211 """
3212 Return a copy of the given network, with an optional new id.
3213 """
3214 new_net = copy.deepcopy(self)
3215 if new_id is not None:
3216 new_net.set_id(new_id)
3217 if new_name is not None:
3218 new_net.set_name(new_name)
3219
3220 return new_net
3221
3223
3224
3225 odict = copy.copy(self.__dict__)
3226
3227
3228 for func in self._dynamic_funcs_python.keys():
3229 odict[func] = None
3230 for func in self._dynamic_funcs_c.keys():
3231 odict[func] = None
3232 odict['namespace'] = None
3233
3234
3235 odict['trajectory'] = None
3236 odict['ddv_dpTrajectory'] = None
3237
3238 return odict
3239
3251
3253 """
3254 Return a components's name if it exists, else just return its id.
3255 """
3256
3257 complists = [self.variables, self.reactions, self.functionDefinitions,
3258 self.events, self.constraints]
3259
3260 name = id
3261 for complist in complists:
3262
3263 if complist.has_key(id) and complist.get(id).name:
3264 name = complist.get(id).name
3265 break
3266
3267
3268 if id == self.id and self.name:
3269 name = self.name
3270
3271 if TeX_form:
3272
3273
3274 if name.count('_') == 1:
3275 sp = name.split('_')
3276 name = '%s_{%s}' % (sp[0], sp[1])
3277 else:
3278
3279 name = name.replace('_', r'\_')
3280
3281 return name
3282
3284
3285 out = {}
3286 out['odes'] = dict(self.diff_eq_rhs.items())
3287 out['functions'] = {}
3288 for func_id, func_def in self.functionDefinitions.items():
3289 vars = ', '.join(func_def.variables)
3290 out['functions']['%s(%s)' % (func_id, vars)] = func_def.math
3291 out['parameters'] = dict([(id, var.value) for (id, var)
3292 in self.constantVars.items()])
3293 out['assignments'] = dict(self.assignmentRules.items())
3294 out['events'] = dict([(event.trigger, event.event_assignments)
3295 for event in self.events])
3296 out['constraints'] = dict([constraint.trigger for constraint in self.constraints])
3297
3298 return out
3299
3300
3301
3302 - def addCompartment(self, id, size=1.0, name='',
3303 typicalValue=False,isConstant=True, isOptimizable=False):
3304 self.add_compartment(id = id, initial_size = size, name = name,
3305 typical_value = typicalValue,
3306 is_constant = isConstant,
3307 is_optimizable = isOptimizable)
3308
3309 addVariable = _add_variable
3310
3311 - def addSpecies(self, id, compartment, initialConcentration=None,
3312 name='', typicalValue=None, is_boundary_condition=False,
3313 isConstant=False, isOptimizable=False, uniprot_ids=set()):
3314 self.add_species(id = id, compartment = compartment,
3315 initial_conc = initialConcentration,
3316 name = name,
3317 typical_value = typicalValue,
3318 is_boundary_condition = is_boundary_condition,
3319 is_constant = isConstant,
3320 is_optimizable = isOptimizable,
3321 uniprot_ids=uniprot_ids)
3322
3323 - def addParameter(self, id, value = 0.0,
3324 typicalValue = None, name = '',
3325 isConstant = True, isOptimizable = True):
3326 self.add_parameter(id = id, initial_value = value, name = name,
3327 typical_value = typicalValue,
3328 is_constant = isConstant,
3329 is_optimizable = isOptimizable)
3330
3331 addRateRule = add_rate_rule
3332
3335 FindFixedPoint = dyn_var_fixed_point
3336
3337 set_initial_var_value = set_var_ic
3338 setInitialVariableValue = set_var_ic
3339
3340 setOptimizables = update_optimizable_vars
3341
3342 - def addEvent(self, id, trigger, eventAssignments, delay=0, name=''):
3343 self.add_event(id = id, trigger = trigger,
3344 event_assignments = eventAssignments, name = name,
3345 delay = delay)
3346
3348 self.add_constraint(id = id, trigger = trigger, message = message,
3349 name = name)
3350
3351
3352 addFunctionDefinition = add_func_def
3353 addAssignmentRule = add_assignment_rule
3354
3355
3356
3358 """
3359 Create the executable function corresponding to func's functionBody.
3360
3361 This only exists now for Trajectory_mod. It's not used by the Network
3362 object.
3363 """
3364 try:
3365 function_body = obj._dynamic_funcs_python.get(func)
3366 except (KeyError, AttributeError):
3367 function_body = getattr(obj, '%s_functionBody' % func)
3368
3369
3370 exec function_body in in_namespace, locals()
3371
3372
3373
3374
3375
3376 setattr(obj, func,
3377 types.MethodType(locals()[func], obj, obj.__class__))
3378