api_overview.rst 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. *******************
  2. Python API Overview
  3. *******************
  4. Model Execution Phases
  5. ######################
  6. There are two phases in model execution.
  7. The first phase is **build phase**, where all the components
  8. of the simulated system are defined by creating objects such as ReactionRule,
  9. ReleaseSite, or Count. All class attributes of these objects
  10. are accessible, and any modifications are allowed.
  11. The second phase is entered by calling Model.initialize() and is called
  12. **simulation phase**. What precisely Model.initialize() does is that it
  13. transforms information in API objects (such as the ReactionRule object)
  14. into an internal MCell4 representation. Thus, modifying attributes or
  15. adding new objects, e.g., to reaction rules or geometry objects won't have
  16. any effect and attempting to do modifications raises an error in most cases.
  17. Some exceptions that are explicitly described in the API documentation,
  18. for instance changing rate of a reaction is allowed.
  19. Accessing API Object Attributes
  20. ###############################
  21. Attributes of API objects can be divided into **scalar**, **object**,
  22. and **vector** attributes.
  23. Types of scalar attributes are str (string), bool, float, integer, or enumerations.
  24. Types of object attributes are API classes and represent references to
  25. such objects.
  26. And the vector attributes are those that use ``List`` in their data type.
  27. Internally, getter and setter methods are generated for attributes and they
  28. are called when an attribute is read or set.
  29. Scalar Attributes
  30. *****************
  31. As an example, let's take a look on the forward rate of a ReactionRule object
  32. that is a scalar attribute.
  33. .. code-block:: python
  34. # get a reference to a ReactionRule object
  35. reaction = model.find_reaction_rule('my_reaction')
  36. # reading calls C++ method ReactionRule.get_fwd_rate()
  37. a = reaction.fwd_rate
  38. # writing calls C++ method ReactionRule.set_fwd_rate(float)
  39. reaction.fwd_rate = 1e5
  40. Reads of a scalar attribute are always allowed and a copy of the value is returned,
  41. therefore no change is propagated back.
  42. When a write to a scalar attribute is executed, the setter method is executed and
  43. when we are in the build phase, MCell allows any changes. In the simulation phase,
  44. the majority of writes cause an exception that disallows modification except for
  45. several cases where the modification is explicitly allowed, such as for the fwd_rate
  46. in our example. The way how the modifications are handled is that the ReactionRule
  47. contains a link to the internal MCell4 reaction representation and the call to
  48. set_fwd_rate, besides modifying the attribute value, also informs the MCell4
  49. engine to change the rate wherever needed.
  50. Object Attributes
  51. *****************
  52. Object attributes behave practically in the same way as scalar attributes.
  53. The only difference that instead of returning a value, a reference to an object
  54. is returned.
  55. .. code-block:: python
  56. # get a reference to a ReleaseSite object
  57. rel_site = model.find_release_site('rel_a')
  58. # get a reference to a Region object used by the ReleaseSite
  59. region = rel_site.region
  60. # create a 'box' object that we will use as a new region
  61. new_region = geometry_utils.create_box('box', 1)
  62. # and replace the original region, allowed only in build phase
  63. rel_site.region = new_region
  64. Reading a reference is allowed at all times. Accessing individual attributes
  65. of the object follows the same rules as for any other API object.
  66. Writes (replacing the reference) are only allowed in the build phase.
  67. No attribute of the object type is allowed to be changed in the simulation phase.
  68. Vector Attributes
  69. *****************
  70. In order to allow propagation of modifications of lists on the Python side to the
  71. C++ side and vice versa, special vector classes are used on the Python side instead
  72. of the standard list type.
  73. These vector attributes try to emulate the Python list data type, but currently allow only a
  74. subset of operations provided for lists.
  75. An example for states of a ComponentType is shown here:
  76. .. code-block:: python
  77. # create an object of class ComponentType
  78. # initially only one state with name 's1' is set
  79. ct_u = m.ComponentType('u', states = ['s1'])
  80. # accessing ct_u.states causes a getter method to be called that
  81. # returns a reference to an object of class VectorStr that
  82. # provides method append
  83. ct_u.states.append('s2')
  84. # we can also modify a specific item in this vector
  85. ct_u.states[1] = '2'
  86. Reading a vector attribute is always allowed. The returned reference to the Vector
  87. object is not guarded against writes and there are no semantic checks.
  88. In the build phase, such modifications are used when the model is initialized.
  89. However, in the simulation phase, such modifications are ignored by the MCell4 engine
  90. and no error is reported.
  91. When writing to a vector attribute, the original vector is replaced by the new one.
  92. This replacement is allowed in the build phase, but when attempting to replace the whole vector in the
  93. simulation phase, an error is reported.
  94. Object Cloning Support
  95. ######################
  96. API objects support shallow and deep copy operations provided through Python methods
  97. *copy.copy(x)* and *copy.deepcopy(x[, memo])*.
  98. Cloning is allowed even if the model was already initialized.
  99. However, all links in the cloned object to the initialized model are lost. E.g., it is not possible
  100. to clone a *Count* object and then call the clone's method *get_current_value* because the new object
  101. will be uninitialized and won't know which model's internal count it is referencing.
  102. Due to MCell4 being implemented primarily in C++, there is one significant difference
  103. in *copy* from Python semantics. All lists are copied
  104. by value, not by reference as Python's lists since they are internally implemented
  105. with C++ std::vector. This behavior is shown in the following code snippet:
  106. .. code-block:: python
  107. ct = m.ComponentType('u', states = ['0', '1'])
  108. ct_copy = copy.copy(ct3)
  109. ct_copy.states[0] = 'X' # change item in a copied list
  110. assert ct.states == ['0', '1']
  111. assert ct_copy.states == ['X', '1']
  112. For *copy.deepcopy(x[, memo])*, the optional *memo* argument is ignored.
  113. Object Debug Printouts
  114. ######################
  115. Each of the API objects provides method *__str__* to convert it to
  116. a string representation that shows the contents of this object.
  117. This method is used when a method *print* or cast *str(...)* is used.
  118. By default, not all details are shown for all objects because that would make the
  119. output too lengthy (especially for the *GeometryObject* and *Complex* classes).
  120. The method *__str__* has two arguments *all_details* (default False) and
  121. *ind* (indent, default ""). To obtain access to all details, set *all_details*
  122. to True.
  123. .. code-block:: python
  124. cplx = m.Complex('A(x~0)')
  125. print(cplx) # prints only 'A(x~0)'
  126. print(cplx.__str__(True)) # prints a detailed representation