-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP, API: Add simple API for KDA #83
Conversation
Cycle/Operational Flux Solution 1Regarding the storage of cycle information -- I think an initial solution might be to simply create a method that lets the user "register" a cycle with all of its information. Something like the following might work: model = kda.KineticModel(K, G=None)
model.register_cycle(identifier="1", cycle=[1, 2, 3, 4], order=[1, 2], substrate=["H"]) Currently the cycles are stored in a As an example of what we want to be able to store, we use the following dictionary to store the cycle info for the EmrE analysis: # define the cycles manually (for repeatability)
EmrE_cycles = {
1: {"cycle": [0, 1, 3, 2, 4, 5, 7, 6], "order": [6, 0]},
2: {"cycle": [0, 6, 7, 5, 4, 2], "order": [6, 0]},
3: {"cycle": [0, 6, 7, 5, 3, 2], "order": [6, 0]},
4: {"cycle": [0, 6, 7, 5, 3, 1], "order": [6, 0]},
5: {"cycle": [0, 2, 4, 5, 3, 1, 7, 6], "order": [6, 0]},
6: {"cycle": [0, 6, 7, 1, 3, 2], "order": [6, 0]},
7: {"cycle": [0, 6, 7, 1], "order": [6, 0]},
8: {"cycle": [0, 2, 3, 1, 7, 5, 4, 6], "order": [6, 0]},
9: {"cycle": [0, 6, 4, 5, 7, 1], "order": [6, 0]},
10: {"cycle": [0, 6, 4, 5, 3, 2], "order": [6, 0]},
11: {"cycle": [0, 6, 4, 5, 3, 1], "order": [6, 0]},
12: {"cycle": [0, 1, 7, 5, 3, 2, 4, 6], "order": [6, 0]},
13: {"cycle": [0, 6, 4, 2, 3, 1], "order": [6, 0]},
14: {"cycle": [0, 6, 4, 2], "order": [6, 0]},
15: {"cycle": [0, 1, 3, 5, 7, 6, 4, 2], "order": [0, 2]},
16: {"cycle": [0, 2, 4, 6, 7, 1], "order": [0, 2]},
17: {"cycle": [0, 2, 4, 5, 7, 1], "order": [0, 2]},
18: {"cycle": [0, 2, 4, 5, 3, 1], "order": [0, 2]},
19: {"cycle": [0, 2, 3, 5, 7, 1], "order": [0, 2]},
20: {"cycle": [0, 1, 7, 6, 4, 5, 3, 2], "order": [0, 2]},
21: {"cycle": [0, 1, 3, 2], "order": [0, 2]},
22: {"cycle": [1, 7, 6, 4, 5, 3], "order": [1, 3]},
23: {"cycle": [1, 7, 6, 4, 2, 3], "order": [2, 4]},
24: {"cycle": [1, 7, 5, 4, 2, 3], "order": [2, 4]},
25: {"cycle": [1, 7, 5, 3], "order": [1, 3]},
26: {"cycle": [2, 3, 5, 7, 6, 4], "order": [2, 4]},
27: {"cycle": [2, 3, 5, 4], "order": [2, 4]},
28: {"cycle": [6, 7, 5, 4], "order": [7, 5]},
} This is very tedious to create and error-prone, but the benefit of having all the info up front is it makes analysis a lot easier. So I think the goal should be to find a way to get all this info into the |
Cycle/Operational Flux Solution 2Perhaps we can require the user to submit the node positions for This provide us a few benefits:
This would require a little more info up front, but if the user Now, this feature is only useful in the context of summing With both of these functions implemented (CW/CCW cycle function, # minimum required diagram info
K = np.array(
[
[0, 1, 0, 1],
[1, 0, 1, 1],
[0, 1, 0, 1],
[1, 1, 1, 0],
]
)
pos = {0: [1, 1], 1: [-1, 1], 2: [-1, -1], 3: [1, -1]}
# create the model
model = kda.KineticModel(K, G=None, pos=pos, CCW=True)
model.build_cycles()
# register the cycles
cycle_labels = ["a", "b", "c"]
cycle_substrates = [["R"], ["R", "L"], ["L"]]
for cycle, label, substrate in zip(model.cycles, labels, cycle_substrates):
model.register_cycle(cycle=cycle, label=label, substrate=substrate)
# calculate the operational fluxes
J_L = model.operational_flux(substrate="L", symbolic=True)
J_R = model.operational_flux(substrate="R", symbolic=True) Behind the scenes,
I like this solution a fair amount more because it requires less information |
Tests are in now, only 2 lines are uncovered but they are low priority. With the size of this PR I'm going to shelve the cycle flux considerations for later and focus on wrapping this up so it is available for use. |
* Add `core.py` with new class object `KineticModel` used to create and store model information for kinetic diagrams * Add `KineticModel` import to `__init__.py` so new API is accessible by importing `kda` * Addresses issue #68
* Update existing tests to leverage the new API * Add `test_3_state_model_symbolic` to verify `KineticModel.transition_flux` symbolic results * Add `test_3_state_model_numeric` to verify `KineticModel.transition_flux` numeric results * Add `test_transition_flux_matching_indices` and `test_transition_flux_mismatched_symbolic` to verify appropriate errors are raised in `KineticModel.transition_flux`
* Add docstring to `KineticModel` * Add docstrings to all `KineticModel` methods
* Change `transition_flux` to `get_transition_flux` to follow method naming convention * Update call signature of `get_transition_flux` so initial/final states are more clear (`i` -> `state_i`) * Misc documentation changes
* Remove redundant code from `test_kda.py`. Code was previously moved to `conftest.py`. * Add hack to `KineticModel.build_state_probabilities` to handle `key` parameters. Can probably find a more elegant solution but this works for now.
* Update/fix documentation for `core.py` classes and methods * Update documentation in `__init__.py` * Add `core.py` to `api.rst`
15d00f5
to
5f7aa09
Compare
Locally the KDA paper code runs without error:
I'll check off the associated task. |
* Updates `README` to include details about calculating transition fluxes with the new API. Similar changes are made to `usage.rst`. * Fixes a minor documentation error in `core.py`
* Adds `test_invalid_inputs` to verify a `RuntimeError` is raised when no inputs are given when building a `KineticModel` * Remove unused code in `test_kda.py`
Okay I think this is ready to go at this point. The API is working as intended and already makes things much easier for a user, especially if transition fluxes are needed. The I'll open a separate issue regarding the cycle fluxes API and maybe one for plotting as well. For most users, the diagram plotting is probably not crucial but it would be nice to print the kinetic diagram and cycles. |
Description
Add
core.py
with new class objectKineticModel
used to create and storemodel information for kinetic diagrams
Add
KineticModel
import to__init__.py
so new API is accessible by importingkda
Fixes issue ENH: Improve KDA API #68
Todos
KineticModel
KineticModel
methodsREADME
to reflect API changescore.py
code is coveredcore.py
to docs (i.e.api.rst
)usage.rst
to matchREADME
Upstream Todos (handle separately)
Fix issue #56 -- remove the usage of"name"
/"val"
dict
keys for allkda
functions. I don't think this is a particularly useful feature and it will likely require a lot of code to keep it working. Instead we should simply store the edge value under theNetworkX
default"weight"
key. There is no reason to store "k12" as an edge weight under"name"
for edge(0, 1)
when the information is already available in the edge tuple. Also, if we do this we can likely remove bothgraph_utils.generate_edges(G)
andgraph_utils.retrieve_rate_matrix(K)
and simply use theNetworkX
built-in functions (e.g.nx.from_numpy_array(K, create_using=nx.MultiDiGraph)
).Comments
I'm still working out how to handle some of the cycle-based tasks. I need to figure out a good solution for cycles that allows the user to either input the cycle info (i.e. direction, substrate transport per cycle, etc.) or input general state info and automatically determine the cycle info. I haven't come up with anything novel so I'll likely leave that for later.
As it stands the API is already much easier to use than before, especially for transition fluxes (see script below).
Testing/Example Script
Testing Script
Status