Skip to content
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

Detect negative rate and give a nice error when that happens #215

Open
jcblemai opened this issue Apr 23, 2024 · 3 comments · May be fixed by #428
Open

Detect negative rate and give a nice error when that happens #215

jcblemai opened this issue Apr 23, 2024 · 3 comments · May be fixed by #428
Labels
bug Defects or errors in the code. enhancement Request for improvement or addition of new feature(s). gempyor Concerns the Python core. low priority Low priority.

Comments

@jcblemai
Copy link
Collaborator

instead of letting the RK4 fail and catching this-

@TimothyWillard TimothyWillard added bug Defects or errors in the code. enhancement Request for improvement or addition of new feature(s). gempyor Concerns the Python core. low priority Low priority. labels Nov 18, 2024
@jcblemai
Copy link
Collaborator Author

jcblemai commented Dec 9, 2024

The bit of code that @emprzy put together that does this, and the test:

def neg_params(parsed_parameters, parameter_names, dates, subpop_names):
    # If any values in the array are below zero: 
    if ((parsed_parameters)< 0).any():

        # Create an array with the indices of each negative param
        # (parameter, day, subpop)
        negative_index_parameters = np.argwhere(parsed_parameters<0)  

        # This loop will record redundant rows in negative_index array
        unique_param_sp_combinations = []
        row_index = -1
        redundant_rows = []
        for row in negative_index_parameters:
            row_index += 1
            # If the (param, subpop) combination already exists in the list, count that row as one that needs to be removed
            if (row[0],row[2]) in unique_param_sp_combinations: 
                redundant_rows.append(row_index)
            # If the (param, sbupop) combination does not exist in the list, add it to the list
            if (row[0],row[2]) not in unique_param_sp_combinations: 
                unique_param_sp_combinations.append((row[0],row[2]))

        # Remove the redundant rows 
        non_redundant_negative_parameters = np.delete(negative_index_parameters, (redundant_rows), axis=0)

    
        # If there are any negative params, error will be raised and negative param locales will be cited
        print("The earliest date negative for each subpop and unique parameter are:")
        for param_idx, day_idx, sp_idx in non_redundant_negative_parameters:
            print("subpop: ", subpop_names[sp_idx], ", parameter ", parameter_names[param_idx], ": ", dates[day_idx].date(), sep="")
        raise ValueError("There are negative parsed-parameters, which is likely to result in incorrect integration.")
import pytest
from random import randint

# Test the negative_parameters() function
def test_negative_parameters():
   parameter_names = ['1*1*1*1', 'alpha*1*1*1', 'sigma_OMICRON*1*1*1', '3*gamma*1*1*1', 'epsilon+omegaph4*1*1*1', '1*zeta*1*1', 'r0*gamma*theta10*1*chi_OMICRON*1', 'r0*gamma*theta9*1*chi_OMICRON*1', 'r0*gamma*theta8*1*chi_OMICRON*1', 'r0*gamma*theta7*1*chi_OMICRON*1', 'r0*gamma*theta6*1*chi_OMICRON*1', 'r0*gamma*theta5*1*chi_OMICRON*1', 'r0*gamma*theta4*1*chi_OMICRON*1', 'r0*gamma*theta3*1*chi_OMICRON*1', 'r0*gamma*theta2*1*chi_OMICRON*1', 'r0*gamma*theta1*1*chi_OMICRON*1', 'r0*gamma*theta0*1*chi_OMICRON*1', 'eta_X0toX3_highIE*1*1*nuage0to17', 'eta_X0toX3_highIE*1*1*nuage18to64LR', 'eta_X0toX3_highIE*1*1*nuage18to64HR', 'eta_X0toX3_highIE*1*1*nuage65to100', 'eta_X0toX4_highIE*1*1*nuage0to17', 'eta_X0toX4_highIE*1*1*nuage18to64LR', 'eta_X0toX4_highIE*1*1*nuage18to64HR', 'eta_X0toX4_highIE*1*1*nuage65to100', 'eta_X0toX5_highIE*1*1*nuage0to17', 'eta_X0toX5_highIE*1*1*nuage18to64LR', 'eta_X0toX5_highIE*1*1*nuage18to64HR', 'eta_X0toX5_highIE*1*1*nuage65to100', 'eta_X1toX4_highIE*1*1*nuage0to17', 'eta_X1toX4_highIE*1*1*nuage18to64LR', 'eta_X1toX4_highIE*1*1*nuage18to64HR', 'eta_X1toX4_highIE*1*1*nuage65to100', 'eta_X1toX5_highIE*1*1*nuage0to17', 'eta_X1toX5_highIE*1*1*nuage18to64LR', 'eta_X1toX5_highIE*1*1*nuage18to64HR', 'eta_X1toX5_highIE*1*1*nuage65to100', 'eta_X2toX4_highIE*1*1*nuage0to17', 'eta_X2toX4_highIE*1*1*nuage18to64LR', 'eta_X2toX4_highIE*1*1*nuage18to64HR', 'eta_X2toX4_highIE*1*1*nuage65to100', 'eta_X2toX5_highIE*1*1*nuage0to17', 'eta_X2toX5_highIE*1*1*nuage18to64LR', 'eta_X2toX5_highIE*1*1*nuage18to64HR', 'eta_X2toX5_highIE*1*1*nuage65to100', 'eta_X2toX6_highIE*1*1*nuage0to17', 'eta_X2toX6_highIE*1*1*nuage18to64LR', 'eta_X2toX6_highIE*1*1*nuage18to64HR', 'eta_X2toX6_highIE*1*1*nuage65to100', 'eta_X3toX5_highIE*1*1*nuage0to17', 'eta_X3toX5_highIE*1*1*nuage18to64LR', 'eta_X3toX5_highIE*1*1*nuage18to64HR', 'eta_X3toX5_highIE*1*1*nuage65to100', 'eta_X3toX6_highIE*1*1*nuage0to17', 'eta_X3toX6_highIE*1*1*nuage18to64LR', 'eta_X3toX6_highIE*1*1*nuage18to64HR', 'eta_X3toX6_highIE*1*1*nuage65to100', 'eta_X4toX6_highIE*1*1*nuage0to17', 'eta_X4toX6_highIE*1*1*nuage18to64LR', 'eta_X4toX6_highIE*1*1*nuage18to64HR', 'eta_X4toX6_highIE*1*1*nuage65to100', 'eta_X4toX7_highIE*1*1*nuage0to17', 'eta_X4toX7_highIE*1*1*nuage18to64LR', 'eta_X4toX7_highIE*1*1*nuage18to64HR', 'eta_X4toX7_highIE*1*1*nuage65to100', 'eta_X5toX7_highIE*1*1*nuage0to17', 'eta_X5toX7_highIE*1*1*nuage18to64LR', 'eta_X5toX7_highIE*1*1*nuage18to64HR', 'eta_X5toX7_highIE*1*1*nuage65to100', 'eta_X6toX7_highIE*1*1*nuage0to17', 'eta_X6toX7_highIE*1*1*nuage18to64LR', 'eta_X6toX7_highIE*1*1*nuage18to64HR', 'eta_X6toX7_highIE*1*1*nuage65to100', 'eta_X6toX8_highIE*1*1*nuage0to17', 'eta_X6toX8_highIE*1*1*nuage18to64LR', 'eta_X6toX8_highIE*1*1*nuage18to64HR', 'eta_X6toX8_highIE*1*1*nuage65to100', 'eta_X7toX8_highIE*1*1*nuage0to17', 'eta_X7toX8_highIE*1*1*nuage18to64LR', 'eta_X7toX8_highIE*1*1*nuage18to64HR', 'eta_X7toX8_highIE*1*1*nuage65to100', 'eta_X8toX9_highIE*1*1*nuage0to17', 'eta_X8toX9_highIE*1*1*nuage18to64LR', 'eta_X8toX9_highIE*1*1*nuage18to64HR', 'eta_X8toX9_highIE*1*1*nuage65to100', 'eta_X9toX9_highIE*1*1*nuage0to17', 'eta_X9toX9_highIE*1*1*nuage18to64LR', 'eta_X9toX9_highIE*1*1*nuage18to64HR', 'eta_X9toX9_highIE*1*1*nuage65to100', 'eta_X10toX10_highIE*1*1*nuage0to17', 'eta_X10toX10_highIE*1*1*nuage18to64LR', 'eta_X10toX10_highIE*1*1*nuage18to64HR', 'eta_X10toX10_highIE*1*1*nuage65to100']
   dates = pd.date_range('2023-03-19', '2025-08-31', freq="D")
   subpop_names = ['56000', '50000', '11000', '02000', '38000', '46000', '10000', '30000', '44000', '23000', '33000', '15000', '16000', '54000', '31000', '35000', '20000', '32000', '28000', '05000', '49000', '19000', '09000', '40000', '41000', '21000', '22000', '01000', '45000', '27000', '08000', '55000', '24000', '29000', '18000', '47000', '25000', '04000', '53000', '51000', '34000', '26000', '37000', '13000', '39000', '17000', '42000', '36000', '12000', '48000', '06000']

   # Test case 1: no negative params
   test_array1 = np.zeros((93,897,51))

   # Test case 2: randomized negative params
   test_array2 = np.zeros((93,897,51))
   for num in range(5):
       test_array2[randint(0,93)][randint(0,897)][randint(0,51)] = -1

   # Test case 3: set negative params with redundancy
   test_array3 = np.zeros((93,897,51))
   test_array3[0][0][0] = -1
   test_array3[50,400:,2] =-1
   test_array3[6][7][15] = -1
   test_array3[6][8][15] = -1

   neg_params(test_array1, parameter_names, dates, subpop_names) # NoError

   with pytest.raises(ValueError):
        assert neg_params(test_array2, parameter_names, dates, subpop_names) # ValueError
        assert neg_params(test_array3, parameter_names, dates, subpop_names) # ValueError

which gives:

Screenshot 2024-12-09 at 10 55 55

@emprzy
Copy link
Collaborator

emprzy commented Dec 11, 2024

@jcblemai Do you want the error that results from having negative parameters to be fatal? Or just a warning?

@jcblemai
Copy link
Collaborator Author

An error is good at this stage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Defects or errors in the code. enhancement Request for improvement or addition of new feature(s). gempyor Concerns the Python core. low priority Low priority.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants