HopkinsIDD / flepiMoP

The Flexible Epidemic Modeling Pipeline
https://flepimop.org
GNU General Public License v3.0
9 stars 4 forks source link

[Bug]: Disease state given to gempyor in a `proportional_to` with length greater than one, it gets cut off at a length of one and is interpreted further without warning #301

Open twallema opened 1 month ago

twallema commented 1 month ago

Label

bug, gempyor, invalid

Priority Label

high priority

Describe the bug/issue

This issue is related to #298 and confirms that when a disease state given to gempyor in a proportional_to of a transition block is a string of length greater than one, it gets cut off at a length of one and is interpreted as such further without sounding the alarm.

Issue

This is relevant in the current season influenza model, where we have explicitly defined disease states for infected and unvaccinated "I", and infected and vaccinated individuals "Iv". See attached flowchart below,

flowchart

The transitions out of the "Iv" disease state are defined as,

    # vaccinated infected outcomes
    - source: ["Iv"]
      destination: ["H"]
      rate: ["(1-e_h)*rho_h/T_h"]
      proportional_to: ["Iv"]           
      proportion_exponent: ["1"]
    - source: ["Iv"]
      destination: ["R"]
      rate: ["(1-((1-e_h)*rho_h))/T_h"]
      proportional_to: ["Iv"]            
      proportion_exponent: ["1"]

However, this is interpreted behind the screens as (confirmed thru simulation),

    # vaccinated infected outcomes
    - source: ["Iv"]
      destination: ["H"]
      rate: ["(1-e_h)*rho_h/T_h"]
      proportional_to: ["I"]           
      proportion_exponent: ["1"]
    - source: ["Iv"]
      destination: ["R"]
      rate: ["(1-((1-e_h)*rho_h))/T_h"]
      proportional_to: ["I"]            
      proportion_exponent: ["1"]

Resulting in the following output,

infected_1

The trajectory of "Iv", whose outflows are all proportional to "Iv", should "gently land" at Iv=0 (exponential tail) rather than "crash" at the origin.

Short-term fix

  1. The use of "source" works,
    # vaccinated infected outcomes
    - source: ["Iv"]
      destination: ["H"]
      rate: ["(1-e_h)*rho_h/T_h"]
      proportional_to: ["source"]           
      proportion_exponent: ["1"]
    - source: ["Iv"]
      destination: ["R"]
      rate: ["(1-((1-e_h)*rho_h))/T_h"]
      proportional_to: ["source"]            
      proportion_exponent: ["1"]

yielding,

infected_2

  1. An input check or warning for the user that disease states with a length longer than one are currently internally being cut off at a length of one.

Long-term fix

This issue only provides indirect evidence that disease states with a length greater than one are internally being cut short by gempyor. Identifying and rectifying the underlying issue in gempyor is the structural fix.

To Reproduce

reproduce_error.zip

Environment, if relevant

No response

saraloo commented 1 month ago

I don't understand why this happens or how come other things work fine in other situations? (Not familiar with the gempyor parsing code again).

If you add the additional brackets again does that also provide a similar fix?

twallema commented 1 month ago

How to resolve

    # vaccinated infected outcomes
    - source: ["Iv"]
      destination: ["H"]
      rate: ["(1-e_h)*rho_h/T_h"]
      proportional_to: [["Iv"]]          
      proportion_exponent: ["1"]
    - source: ["Iv"]
      destination: ["R"]
      rate: ["(1-((1-e_h)*rho_h))/T_h"]
      proportional_to: [["Iv"]]              
      proportion_exponent: ["1"]

So, the "dimension" of "proportional_to" should be equal to the number of "compartments" +1?

To do