Summarizing across trackers
Hi,
I have a microsimulation model in which I have several (~30) trackers, each representing a specific health condition. Each of these trackers takes on a value of -1 if the person does not have the condition, and a value starting at 0 to +Inf to count the number of cycles the person has had the condition (so 0 is used to identify an incident condition). The trackers are modified each cycle using a python formula.
I'm looking for a way to summarize the trackers. Specifically, I want to know a) how many conditions the person currently has, and b) how many incident conditions there are (how many trackers are 0). I thought I could do this with trackerincr(), but that doesn't seem to work within a Python function. I also don't see a way to do this with a Treeage-native tracker modification other than to write a separate python function that reads in all the trackers (which defeats the purpose, I'm trying to do this to increase model efficiency so I don't have to read in all these trackers to a function every cycle).
Just wanted to see if I was missing something.
Thanks,
Bill
Comments
Hey Bill
You can have any expression evaluated in Python by using a treeage.eval("") statement. The expression plus any arguments goes between the quotes e.g. randnorm = treeage.eval("Distforce(1)"). If distribution with index 1 is a normal, this expression will provide a sample from it within Python. You can concatenate using the + sign:
distnumber = 1;
diststring = "Distforce(" + distnumber + ")";
randnorm = treeage.eval(diststring);
You have an interesting problem. Unlike distributions which can be referenced by an index number, I don't believe that trackers have an index. They're specified by name which makes iterating across them cumbersome (Andrew may correct me). One thing you could consider doing is recording disease status in a global matrix rather than as trackers. Then you could create a simple Python function that uses a for loop to iterate down the rows of the matrix and sum up the number of values > -1 and the number equal to zero and record those values in the bottom two rows of the matrix. I's suggest looking over the Help regarding manipulation of matrix objects within Python.
I suspect that you'll want to know these totals after each cycle. There is a set of special variables that instruct Treeage to take actions at certain points in the analysis - e.g. _pre_analysis to do something at the very beginning of the simulation, _post_analysis at the very end and _monte_post_cycle_eval at the end of a cycle which would be perfect for you. You would set the value of _monte_post_cycle_eval equal to a user() function that calls your Python function e.g. user("fConditions";ntrackers). I think this is the old way of calling user defined Python functions. Andrew may suggest an alternative.
The only issue is that this particular special variable only works in parallel microsim. But that's OK, In tree preferences, click to allow probabilities to sum to more than 1. Add an entry node with a 'probability' equal to the number of trials you want to run and click parallel trial in the micrsimulation dialogue. Now set up a global matrix where the rows correspond to the conditions and the columns correspond to the trial number. You could create two other matrices, each with rows corresponding to _stage + 1 and columns corresponding to trial number. You could record the cycle-by-cycle number of entries > -1 in one of these matrices and the cycle-by-cycle number of 0's in the other.
My practice is to initialize matrices at the beginning otherwise Python may complain that you are trying to manipulate matrices that don't exist. I'd set the value of _pre_analysis to globalnset(1;ntrackers + 2;ntrials;0)+globalnset(2;maxcycles;ntrials;0)+globalnset(3;maxcycles;ntrials;0).
You can reference these matrices on the fly during simulations or dump the contents to text files to view after the simulation finishes: set _post_analysis to globalnexport(1;1)+globalnexport(2;2)+globalnexport(3;3)
David Naimark
Sorry, one additional bit. You can modify entries in the first global matrix during a cycle when individuals develop a condition from -1 to zero. At the end of a cycle, you can increment entries in GM1 that are >-1 by 1 using what I'm calling fConditions - i.e. it could loop through to count and then loop through to update.
While I agree that David's approach would work, it is a bit complex and global matrices can affect model performance. You will note that David is a very advanced TreeAge Pro modeler with extensive knowledge of the most complex features.
I think you can do this more simply with long but simple variable definitions. Something like these (with made-up tracker names).
var_incidence_all = if(t_incidence_1<0;0;1) + if(t_incidence_2<0;0;1) + more incidence checks
var_conditions_all = t_incidence_1+1 + t_incidence_2+1 + more condition checks
Those variable definitions should summarize the tracker values whenever you need them. Note that the definitions will be very long, so you might want to uncheck the "show in tree" checkbox for those variables.
You can send those or any other variables, trackers, etc. into a Python function as arguments. For example...
YourPythonFunction(var_incidence_all; var_conditions_all)
This will speed up Python functions, so you won't have to keep calling treeage.eval from withing Python functions.
Andrew
Thank you both. This is very helpful!
Please sign in to leave a comment.