Skip to content

Conversation

@marghe-molaro
Copy link
Collaborator

This PR updates previous PR draft #1468

Now includes changes in the mother_and_newborn_info dataframe.

…th, label what is only used for ddebugging and will be later removed
…ible to all modules. For now add person_ID to the dict of info printed as the outer dictionary key logging seems to have a problem.
…lysis file now collects all relevant info and prints them
…rected analysis file such as for small number of cases where the DALYs are not explicitly resolved the average DALYs are still computed correctly [skip ci]
@marghe-molaro
Copy link
Collaborator Author

To add following discussion at Q4:

  • Add option for users to specify characteristics of individuals for which histories are tracked;
  • Ensure events after death are not logged (a few of these may slip through via pop-wide events)

@tamuri
Copy link
Collaborator

tamuri commented Dec 3, 2025

Are the copies of pop dataframe/rows "deep" enough? Do columns containing series and lists need to be copied iteratively?

The following population dataframe columns have object type i.e. the ones to check are copied/checked properly:

>>> [col for col in df.columns if df[col].dtype == 'object']
['rt_injuries_to_cast', 'rt_injuries_for_minor_surgery', 'rt_injuries_for_major_surgery', 'rt_injuries_to_heal_with_time', 'rt_injuries_for_open_fracture_treatment', 'rt_injuries_left_untreated']

@marghe-molaro
Copy link
Collaborator Author

Hi @tamuri,
This is now ready for review. Notable changes:

  • Fixed issue with nan values being incorrectly logged as having changed;
  • Unified approach to copying pop df + mni dictionary, and ensured object types are copied by value;
  • In postprocessing, ensured events which may have been logged after the individual's death are not kept in the final histories (there won't be many)

@marghe-molaro
Copy link
Collaborator Author

Added features:

  • Individuals now have an additional property called track_history. Events are only logged for individuals for whom track_history = True either before or after the event has ran. Developers are free to specify how this variable is updated by events in the simulation.

Note:

  • Inpatient_Care is currently not an event associated with a specific individual, therefore (by definition) it is not logged by the individual history tracker

@marghe-molaro
Copy link
Collaborator Author

Now additionally tracking consumable, equipment, and bed days access for each individual

Copy link
Collaborator

@tamuri tamuri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few suggestions below...

Looking at the logs, I don't know how common is the following scenario: same individual, repeated same event on the same dat i.e. you would get a number of entries that were potentially of a different execution of the same event. If so, you could add an incrementing counter that gets logged as an identifier to group the entries in the EAV table. Might not be necessary if this doesn't happen.

items_used=items_used,
)

notifier.dispatch("consumables._request_consumables", data={'target' : target, 'event_name' : event_name, 'Item_Available': str(items_available),'Item_NotAvailable': str(items_not_available), 'Item_Used': str(items_used)})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change key to same format as elsewhere: consumables.post-request_consumables

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So unlike elsewhere, where the broadcasting happens before or after the named function is called, in this case the broadcasting occurs inside the _request_consumable fnc...so I opted to rename it consumables.on_request-consumables, but please let me know if you disagree

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should still be called post-request_consumables. It is the state of things at the end of that function's block of code (like a postcondition), doesn't need to be in the caller.

essential_item_codes: dict,
optional_item_codes: Optional[dict] = None,
to_log: bool = True,
to_broadcast: bool = True,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you don't need the to_broadcast argument here (I see that you check elsewhere where the individual tracker is registered) and simply use the existing `to_log? The notifier should always broadcast messages. Then the listeners register themselves to receive the message. If nothing is listening, there is no error. The obvious example is if a different module wants to listen for notifications.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reasoning for adding a check ahead of the broadcasting is not to avoid error, but rather to avoid having to create the items_available, items_not_available, and items_used dictionaries if they're not going to be used (through logging or broadcasting, though I think safest to disentangle the broadcasting from "to_log"). I have opted to check if the module is included here.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand. It's still worth decoupling the notification from the module. Add the following to notify.py:

    def has_listeners(self, notification_key):
        """
        Check if there are any listeners registered for a specific notification.

        :param notification_key: The identifier to check.
        :return: True if there are listeners, False otherwise.
        """
        return notification_key in self.listeners and len(self.listeners[notification_key]) > 0

Then use it in the consumables at the point of notification i.e.

if notifier.has_listeners('consumables.post-request_consumables'):
    # prepare the data
    # ....
    notifier.dispatch("consumables.post-request_consumables", data=....)

marghe-molaro and others added 2 commits January 9, 2026 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants