def create_report_file(campaign_obj, report_data_obj, report_name, debug):
    with open(report_name, "w") as outfile:
        success = True
        timestep = Outbreak_Start_Day
        new_infection = report_data_obj[KEY_NEW_INFECTIONS][timestep]
        statistical_population = report_data_obj[KEY_STATISTICAL_POPULATION][timestep]
        initial_effect = campaign_obj[KEY_INITIAL_EFFECT]
        demographic_coverage_v = campaign_obj[KEY_DEMOGRAPHIC_COVERAGE_V]
        demographic_coverage_o = campaign_obj[KEY_DEMOGRAPHIC_COVERAGE_O]
        immunity = initial_effect * demographic_coverage_v
        expected_new_infection = statistical_population * (1.0 - immunity) * demographic_coverage_o
        tolerance = 0.0 if expected_new_infection == 0.0 else 2e-2 * statistical_population
        if math.fabs(new_infection - expected_new_infection) > tolerance:
            success = False
            outfile.write("BAD: At time step {0}, new infections are {1} as reported, expected {2}.\n".format(
                timestep, new_infection, expected_new_infection))
        outfile.write(sft.format_success_msg(success))
    sft.plot_data(new_infection,expected_new_infection,
                           label1= "Actual", label2 = "Expected",
                           ylabel="new infection", xlabel="red: actual data, blue: expected data",
                           title = "Actual new infection vs. expected new infection",
                           category = 'New_infection',show = True )
    if debug:
        print( "SUMMARY: Success={0}\n".format(success) )
    return success
def create_report_file(param_obj, report_data_obj, report_name, debug):
    with open(report_name, "w") as outfile:
        success = True
        new_infection_portions = calc_expected_new_infection_portion(param_obj, debug)
        new_infections = []
        expected_new_infections = []
        # skip the first outbreak, which gives the natual immunity
        timestep = Outbreak_Start_Day + Timesteps_Between_Repetitions
        for i in range(len(KEY_NEW_INFECTIONS_GROUP)):
            new_infection = report_data_obj[KEY_NEW_INFECTIONS_GROUP[i]][timestep]
            statistical_population = report_data_obj[KEY_STATISTICAL_POPULATION_GROUP[i]][timestep]
            expected_new_infection = statistical_population * (new_infection_portions[i])
            tolerance = 0.0 if expected_new_infection == 0.0 else 2e-2 * statistical_population
            result = f"At time step: {timestep} Group: {KEY_NEW_INFECTIONS_GROUP[i]}" \
                     f" reported new infections: {new_infection} expected: {expected_new_infection}" \
                     f" tolerance: {tolerance}.\n"
            if math.fabs(new_infection - expected_new_infection) > tolerance:
                success = False
                outfile.write(f"BAD:  {result}")
            else:
                outfile.write(f"GOOD: {result}")

            new_infections.append(new_infection)
            expected_new_infections.append(expected_new_infection)
        outfile.write(sft.format_success_msg(success))
    sft.plot_data(new_infections,expected_new_infections,
                           label1= "Actual", label2 = "Expected",
                           xlabel= "0: Control group, 1: Test group",ylabel="new infection",
                           title = "Actual new infection vs. expected new infection",
                           category = 'New_infections',show = True )
    if debug:
        print( "SUMMARY: Success={0}\n".format(success) )
    return success
def create_report_file(report_data_obj, report_name, debug):
    with open(report_name, "w") as outfile:
        success = True
        timestep = Outbreak_Start_Day
        effects = calc_effect(debug)
        new_infections = []
        new_disease_deaths = []
        expected_new_disease_deaths = []
        actual_effects = []
        pre_disease_death = 0

        for i in range(len(Interventions)):
            new_infection = report_data_obj[KEY_NEW_INFECTIONS][timestep]
            disease_death = report_data_obj[KEY_DISEASE_DEATHS][timestep]
            new_disease_death = disease_death - pre_disease_death
            effect = effects[i]
            expected_new_disease_death = (1.0 - effect) * new_infection
            tolerance = 0.0 if expected_new_disease_death == 0.0 else 3e-2 * new_infection
            actual_effect = 1.0 - new_disease_death/float(new_infection) if new_infection != 0 else 0.0
            result = f"At time step {timestep}, outbreak {Interventions[i]}, {new_disease_death} reported" \
                     f" new disease death, expected {expected_new_disease_death} with tolerance {tolerance}.\n"
            mortality_effect_message = f"actual MortalityBlocking effect is {actual_effect}, expected {effect}."
            if math.fabs(new_disease_death - expected_new_disease_death) > tolerance:
                success = False
                outfile.write(f"BAD:  {result}")
            else:
                outfile.write(f"GOOD: {result}")
            outfile.write(f"\t {mortality_effect_message}\n")
            new_disease_deaths.append(new_disease_death)
            expected_new_disease_deaths.append(expected_new_disease_death)
            actual_effects.append(actual_effect)
            new_infections.append(new_infection)
            timestep += Timesteps_Between_Repetitions
            pre_disease_death = disease_death
        sft.plot_data(new_disease_deaths,expected_new_disease_deaths,
                               label1= "Actual", label2 = "Expected",
                               xlabel= "outbreak",ylabel="disease death",
                               title = "Actual disease death vs. expected disease death",
                               category = 'Disease_death',show = True )
        sft.plot_data(new_disease_deaths,new_infections,
                               label1= "death", label2 = "infection",
                               xlabel= "outbreak",ylabel="population",
                               title = "Actual disease death vs. new infections",
                               category = 'disease_death_vs_new_infections',show = True )
        if debug:
            with open("New_disease_death.txt", "w") as file:
                for i in range(len(new_disease_deaths)):
                    file.write("{0}, {1}.\n".format(new_disease_deaths[i],expected_new_disease_deaths[i]))
            with open("Effects.txt", "w") as file:
                for i in range(len(actual_effects)):
                    file.write("{0}, {1}.\n".format(actual_effects[i],effects[i]))

        outfile.write(sft.format_success_msg(success))
        if debug:
            print( "SUMMARY: Success={0}\n".format(success) )
        return success
def create_report_file(param_obj, inset_chart_obj, report_name, insetchart_name, debug):
    with open(report_name, "w") as outfile:
        config_name = param_obj[ConfigKeys.Config_Name]
        decay = param_obj[ConfigKeys.Node_Contagion_Decay_Rate]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        outfile.write("Config_name = {}\n".format(config_name))
        outfile.write("{0} = {1}\n".format(ConfigKeys.Node_Contagion_Decay_Rate, decay))
        outfile.write("{0} = {1} {2} = {3}\n".format(
            ConfigKeys.Base_Infectivity, base_infectivity,
            ConfigKeys.Run_Number, param_obj[ConfigKeys.Run_Number]))

        if decay == 1:
            outfile.write("WARNING: the decay rate is {}, expected value less than 1.\n".format(decay))
        if param_obj[ConfigKeys.Enable_Heterogeneous_Intranode_Transmission] == 1:
            outfile.write("WARNING: {0} = {1}, expected this feature is disabled".format(
                ConfigKeys.Enable_Heterogeneous_Intranode_Transmission,
            param_obj[ConfigKeys.Enable_Heterogeneous_Intranode_Transmission]))

        success = True

        outfile.write("Testing: Testing contagion decay for every time step:\n")
        duration = param_obj[ConfigKeys.Simulation_Duration]

        contagion_list_c = []
        pre_contagion = 0
        for t in range(duration - 1):
            infected = inset_chart_obj[InsetKeys.ChannelsKeys.Infected][t]
            # population = inset_chart_obj[InsetKeys.ChannelsKeys.Statistical_Population][t]
            # calculate contagion
            new_contagion = base_infectivity * infected # / population
            current_contagion = pre_contagion * (1.0 - decay) + new_contagion
            pre_contagion = current_contagion

            # get contagion from insetchart json
            actual_contagion_e = inset_chart_obj[InsetKeys.ChannelsKeys.Environmental_Contagion_Population][t]

            contagion_list_c.append([actual_contagion_e, current_contagion])

            if math.fabs(current_contagion - actual_contagion_e) > 5e-2 * current_contagion:
                success = False
                outfile.write("    BAD: at time step {0}, for route {1}, the total contagion is {2}, "
                              "expected {3}.\n".format(t, routes[0], actual_contagion_e,
                                                       current_contagion
                ))

        # plot actual and expected values for contagion
        sft.plot_data(np.array(contagion_list_c)[:, 0], np.array(contagion_list_c)[:, 1],
                          label1=insetchart_name, label2="calculated contagion",
                          title=InsetKeys.ChannelsKeys.Environmental_Contagion_Population,
                          xlabel='day',ylabel='contagion',category="contagion_{}".format(routes[0]),
                          line=True, alpha=0.5, overlap=True)

        outfile.write(sft.format_success_msg(success))
    if debug:
        print(sft.format_success_msg(success))
    return success
def create_report_file(report_data_obj, report_name, debug):
    with open(report_name, "w") as outfile:
        success = True
        timestep = Outbreak_Start_Day
        tb_effects = calc_tb_effect(debug)
        tb_effect_baseline = float(tb_effects[0]) # use the number of new infection from the 1st outbreak as a baseline
        new_infection_baseline = report_data_obj[KEY_NEW_INFECTIONS_GROUP[1]][timestep]
        statistical_population = report_data_obj[KEY_STATISTICAL_POPULATION_GROUP[1]][timestep] # no any death
        new_infections = []
        expected_new_infections = []
        new_infections.append(new_infection_baseline)
        expected_new_infections.append(new_infection_baseline)
        actual_tb_effects = []
        actual_tb_effects.append(tb_effect_baseline)

        for i in range(1, len(Interventions)): # no need to test the 1st outbreak
            timestep += Timesteps_Between_Repetitions
            new_infection = report_data_obj[KEY_NEW_INFECTIONS_GROUP[1]][timestep]
            tb_effect = tb_effects[i]
            # because expected_new_infection / (1.0 - tb_effect) = new_infection_baseline / (1.0- tb_effect_baseline), so
            expected_new_infection = (1.0 - tb_effect) * new_infection_baseline / (1.0- tb_effect_baseline)
            tolerance = 0.0 if expected_new_infection == 0.0 else 2e-2 * statistical_population
            actual_tb_effect = 1.0 - (new_infection * (1.0 - tb_effect_baseline) / new_infection_baseline)
            result = f"At time step: {timestep}, outbreak: {Interventions[i]}," \
                     f" {new_infection} reported new infections, expected {expected_new_infection}" \
                     f" with tolerance {tolerance}\n"
            if math.fabs(new_infection - expected_new_infection) > tolerance:
                success = False
                outfile.write(f"BAD:  {result}")
            else:
                outfile.write(f"GOOD: {result}")
            outfile.write("\tactual TransmissionBlocking effect is {0}, expected {1}.\n".format(actual_tb_effect, tb_effect))
            new_infections.append(new_infection)
            expected_new_infections.append(expected_new_infection)
            actual_tb_effects.append(actual_tb_effect)
        sft.plot_data(new_infections,expected_new_infections,
                               label1= "Actual", label2 = "Expected",
                               xlabel= "outbreak",ylabel="new infection",
                               title = "Actual new infection vs. expected new infection",
                               category = 'New_infections',show = True )
        if debug:
            with open("New_infections.txt", "w") as file:
                for i in range(len(new_infections)):
                    file.write("{0}, {1}.\n".format(new_infections[i],expected_new_infections[i]))
            with open("Effects.txt", "w") as file:
                for i in range(len(actual_tb_effects)):
                    file.write("{0}, {1}.\n".format(actual_tb_effects[i],tb_effects[i]))

        outfile.write(sft.format_success_msg(success))
        if debug:
            print( "SUMMARY: Success={0}\n".format(success) )
        return success
def application(output_folder="output",
                config_filename="config.json", campaign_filename="campaign.json",
                demographics_filename="demographics_100_overlay.json",
                insetchart_name="InsetChart.json",
                report_name=sft.sft_output_filename,
                debug=False):
    if debug:
        print("output_folder: " + output_folder)
        print("config_filename: " + config_filename+"\n")
        print("campaign_filename: " + campaign_filename+"\n")
        print("demographics_filename: " + demographics_filename+"\n")
        print("insetchart_name: " + insetchart_name+"\n")
        print("report_name: " + report_name+"\n")
        print("debug: " + str(debug)+"\n")

    sft.wait_for_done()

    param_obj = ips.load_emod_parameters(config_filename, debug)
    campaign_obj = ips.load_campaign_file(param_obj[KEY_CAMPAIGN_NAME], debug)
    demographics_obj = ips.load_demographics_file(param_obj[KEY_DEMOGRAPHICS_NAME][-1], debug)
    report_data_obj = ips.parse_json_report(output_folder, insetchart_name, debug)

    sft.plot_data(report_data_obj[KEY_NEW_INFECTIONS],
                  title="new infections",
                  label1="New Infections",
                  label2="NA",
                  xlabel="time steps", ylabel="new infection",
                  category='New_infections',
                  show=True)
    sft.plot_data(report_data_obj[KEY_STATISTICAL_POPULATION],
                  title="Statistical Population",
                  label1="Statistical Population",
                  label2="NA",
                  xlabel="time steps", ylabel="Statistical Population",
                  category='Statistical_population',
                  show=True, line=True)

    ips.create_report_file(param_obj, campaign_obj, demographics_obj, report_data_obj, report_name,
                           debug)
def create_report_file(report_data_obj, report_name, debug):
    with open(report_name, "w") as outfile:
        success = True

        timestep = Outbreak_Start_Day
        tb_effect = prime
        baseline = 2 # group 3_Control is the baseline
        test = 3 # group 4_Test is the test group
        # first outbreak
        pre_new_infection_baseline = report_data_obj[KEY_NEW_INFECTIONS_GROUP[baseline]][timestep]
        pre_new_infection_test= report_data_obj[KEY_NEW_INFECTIONS_GROUP[test]][timestep]
        # second outbreak
        timestep +=  Timesteps_Between_Repetitions
        new_infection_baseline = report_data_obj[KEY_NEW_INFECTIONS_GROUP[baseline]][timestep]
        statistical_population_baseline = report_data_obj[KEY_STATISTICAL_POPULATION_GROUP[baseline]][timestep]
        new_infection_test= report_data_obj[KEY_NEW_INFECTIONS_GROUP[test]][timestep]
        statistical_population_test = report_data_obj[KEY_STATISTICAL_POPULATION_GROUP[test]][timestep]
        # because expected_new_infection_test / ((1.0 - tb_effect)* statistical_population_test)= new_infection_baseline / statistical_population_baseline, so
        expected_new_infection_test = (1.0 - tb_effect) * new_infection_baseline * statistical_population_test / statistical_population_baseline
        tolerance = 0.0 if expected_new_infection_test == 0.0 else 2e-2 * statistical_population_test
        result = f"At time step {timestep}, {new_infection_test} reported new infections in Group 4_Test," \
                 f"expected {expected_new_infection_test} tolerance: {tolerance}.\n"
        if math.fabs(new_infection_test - expected_new_infection_test) > tolerance:
            success = False
            outfile.write(f"BAD:  {result}")
        else:
            outfile.write(f"GOOD: {result}")

        sft.plot_data([pre_new_infection_baseline, new_infection_baseline],[pre_new_infection_test, new_infection_test],
                               label1= "control_group", label2 = "test_group",
                               xlabel= "0: first outbreak, 1: second outbreak",ylabel="new infection",
                               title = "control vs. test",
                               category = 'New_infections',show = True )

        outfile.write(sft.format_success_msg(success))
        if debug:
            print( "SUMMARY: Success={0}\n".format(success) )
        return success
def create_report_file(report_data_obj, report_name, debug):
    with open(report_name, "w") as outfile:
        success = True
        immunity = calc_immunity(debug)
        new_infections = []
        expected_new_infections = []
        timestep = Outbreak_Start_Day
        if not report_data_obj:
            success = False
            outfile.write("BAD: There is no data in the PropertyReport report")
        else:
            for i in range(Number_Repetitions):
                for j in range(len(KEY_NEW_INFECTIONS_GROUP)):
                    new_infection = report_data_obj[KEY_NEW_INFECTIONS_GROUP[j]][timestep]
                    statistical_population = report_data_obj[KEY_STATISTICAL_POPULATION_GROUP[j]][timestep]
                    expected_new_infection = statistical_population * (1.0 - immunity[j][i])
                    tolerance = 0.0 if expected_new_infection == 0.0 else 2e-2 * statistical_population
                    result = f"At time step {timestep}, {KEY_NEW_INFECTIONS_GROUP[j]}" \
                             f" new infections: {new_infection}, expected infections: {expected_new_infection}" \
                             f"  with tolerance {tolerance}.\n"
                    if math.fabs(new_infection - expected_new_infection) > tolerance:
                        success = False
                        outfile.write(f"BAD:  {result}")
                    else:
                        outfile.write(f"GOOD: {result}")
                    new_infections.append(new_infection)
                    expected_new_infections.append(expected_new_infection)
                timestep += Timesteps_Between_Repetitions
        outfile.write(sft.format_success_msg(success))
    sft.plot_data(new_infections,expected_new_infections,
                           label1= "Actual", label2 = "Expected",
                           xlabel= "group: 0-4 outbreak 1, 5-9 outbreak 2",ylabel="new infection",
                           title = "Actual new infection vs. expected new infection",
                           category = 'New_infections',show = True )
    if debug:
        print( "SUMMARY: Success={0}\n".format(success) )
    return success
def create_report_file(report_data_obj, csv_df, report_name, debug):
    with open(report_name, "w") as outfile:
        success = True
        timestep = Outbreak_Start_Day
        effect = prime
        new_infections = []
        statistical_populations = []
        disease_deaths = []
        for i in range(len(PROPERTY_GROUP)):
            new_infection = report_data_obj[KEY_NEW_INFECTIONS_GROUP[i]][timestep]
            statistical_population = report_data_obj[KEY_STATISTICAL_POPULATION_GROUP[i]][timestep]
            # disease death in the last two groups happen 1 day later than the first two groups.
            disease_death = len(csv_df[(csv_df['Time'] == int(timestep + i / 2)) &
                                       (csv_df['QualityOfCare'] == PROPERTY_GROUP[i]) &
                                       (csv_df['Event_Name'] == 'DiseaseDeaths')])
            new_infections.append(new_infection)
            statistical_populations.append(statistical_population)
            disease_deaths.append(disease_death)
        # test acquisition blocking
        new_infection_seed_test = new_infections[1]
        statistical_population_seed_test = statistical_populations[1]
        expected_new_infection_seed_test = statistical_population_seed_test * (1.0 - effect)
        tolerance_1 = 0.0 if expected_new_infection_seed_test == 0.0 else 2e-2 * statistical_population_seed_test
        result_1 = f"At time step {timestep}, {new_infection_seed_test}" \
                   f" reported new infections in Group 2_Seed_Test, expected" \
                   f" {expected_new_infection_seed_test} with tolerance {tolerance_1}.\n"
        if math.fabs(new_infection_seed_test - expected_new_infection_seed_test) > tolerance_1:
            success = False
            outfile.write(f"BAD: {result_1}")
        else:            
            outfile.write(f"GOOD: {result_1}")
        # test transmission blocking
        new_infection_seed_control = new_infections[0]
        new_infection_control = new_infections[2]
        new_infection_test = new_infections[3]
        expected_new_infection_test = (1.0 - effect) * new_infection_control * new_infection_seed_test/float(new_infection_seed_control)
        statistical_population_test = statistical_populations[3]
        tolerance_2 = 0.0 if expected_new_infection_test == 0.0 else 2e-2 * statistical_population_test
        result_2 = f"At time step {timestep}, {new_infection_test} reported" \
                   f" disease deaths in Group 4_Test, expected" \
                   f" {expected_new_infection_test}, tolerance {tolerance_2}.\n"
        if math.fabs(new_infection_test - expected_new_infection_test) > tolerance_2:
            success = False
            outfile.write(f"BAD:  {result_2}")
        else:
            outfile.write(f"GOOD: {result_2}")
        #test mortality blocking
        disease_death_seed_test = disease_deaths[1]
        expected_disease_death_seed_test = new_infection_seed_test * (1.0 - effect)
        tolerance_3 = 0.0 if expected_disease_death_seed_test == 0.0 else 2e-2 * new_infection_seed_test
        result_3 = f"At time step {timestep}, {disease_death_seed_test} reported" \
                   f" disease deaths in Group 2_Seed_Test, expected" \
                   f" {expected_disease_death_seed_test}, tolerance {tolerance_3}.\n"
        if math.fabs(disease_death_seed_test - expected_disease_death_seed_test) > tolerance_3:
            success = False
            outfile.write(f"BAD:  {result_3}")
        else:
            outfile.write(f"GOOD: {result_3}")
        outfile.write(sft.format_success_msg(success))
    sft.plot_data(new_infections,disease_deaths,
                           label1= "new_infections", label2 = "disease_death",
                           xlabel= "0:1_Seed_Control, 1:2_Seed_Test, 2:3_Control, 4:3_Test",
                           title = "new_infections vs. disease_death",
                           category = 'New_infections_vs_disease_death',show = True )
    if debug:
        print( "SUMMARY: Success={0}\n".format(success) )
    return success
def create_report_file(param_obj, campaign_obj, demographics_obj, report_data_obj, report_name, debug=False):
    with open(report_name, "w") as outfile:
        total_timesteps = param_obj[KEY_TOTAL_TIMESTEPS]
        start_timestep = param_obj[KEY_START_TIME]
        initial_population = demographics_obj[KEY_INITIAL_POPULATION]
        rates = [x * campaign_obj[KEY_NODE_LIST_COUNT] for x in campaign_obj[KEY_CAMPAIGN_DIP]]
        durations = campaign_obj[KEY_CAMPAIGN_DURATIONS]
        new_infections = report_data_obj[KEY_NEW_INFECTIONS]
        statistical_population = report_data_obj[KEY_STATISTICAL_POPULATION]
        length = len(rates)
        start_duration = start_timestep
        new_infections_dict = {}
        calculate_new_population = initial_population
        outfile.write("# Test name: " + str(param_obj[KEY_CONFIG_NAME]) + ", Run number: " +
                      str(param_obj[KEY_RUN_NUMBER]) +
                      "\n# Test compares the statistical population with the"
                      " calculated population and tests the Poisson distribution for new infections.\n")
        for i in range(length):
            rate = rates[i]
            duration = durations[i]
            calculate_new_population = rate * duration + calculate_new_population
            end_duration = duration + start_duration
            if rate not in new_infections_dict:
                new_infections_dict[rate] = []
            for j in range(start_duration + 1, end_duration + 1):
                new_infections_dict[rate].append(new_infections[j])
            start_duration = end_duration
        if end_duration < total_timesteps + start_timestep:
            rate = 0.0
            if rate not in new_infections_dict:
                new_infections_dict[rate] = []
            for j in range(end_duration + 1, len(new_infections)):
                new_infections_dict[rate].append(new_infections[j])
        if debug:
            with open("DEBUG_new_infections_parsed.json", "w") as new_infections_file:
                json.dump(new_infections_dict, new_infections_file, indent=4)

        # test statistical population channel
        diff_population = math.fabs(calculate_new_population - statistical_population[-1])
        if debug:
            print("calculated population is {0}, statistical population "
                  "from InsetChart is {1}.".format(calculate_new_population,
                                                   statistical_population[-1]))
        error_tolerance = math.fabs(calculate_new_population - initial_population) * 0.1
        low_acceptance_bound = round(calculate_new_population - error_tolerance)
        high_acceptance_bound = round(calculate_new_population + error_tolerance)
        if debug:
            print("diff_population is {0}, error_tolerance is {1}".format(diff_population, error_tolerance))
        success = diff_population < error_tolerance
        result_string = "GOOD" if success else "BAD"
        within_acceptance_bounds = " " if success else " not "
        outfile.write("{0}: statistical population is {1}, which is{2}within range of ({3}, {4}).  "
                      "Expected about {5}.\n".format(result_string, statistical_population[-1],
                                                     within_acceptance_bounds, low_acceptance_bound,
                                                     high_acceptance_bound, calculate_new_population))
        # test poisson distribution for new infections
        for rate in new_infections_dict:
            dist = new_infections_dict[rate]
            title = "rate = " + str(rate)
            result = sft.test_poisson(dist, rate, route=title, report_file=outfile, normal_approximation=False)
            if not result:
                success = False
            numpy_distro = np.random.poisson(rate, len(dist))
            sft.plot_data(dist, numpy_distro,
                          title="new infections for {}".format(title),
                          label1="new infection from model, {}".format(title),
                          label2="Poisson distro from numpy",
                          xlabel="data points", ylabel="new infection",
                          category="plot_data_{0}".format(title), show=True,
                          sort=True)
            sft.plot_probability(dist, numpy_distro,
                                 title="probability mass function for {}".format(title),
                                 label1="new infection probability from model",
                                 label2="new infection probability from numpy distro",
                                 category="plot_probability_{0}".format(title), show=True)

        outfile.write(sft.format_success_msg(success))
        if debug:
            print("SUMMARY: Success={0}\n".format(success))
        return success
def create_report_file(param_obj, campaign_obj, stdout_df, property_df, property_obj, report_name, debug):
    with open(report_name, "w") as outfile:
        config_name = param_obj[ConfigKeys.Config_Name]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        outfile.write("Config_name = {}\n".format(config_name))
        outfile.write("{0} = {1} {2} = {3}\n".format(
            ConfigKeys.Base_Infectivity, base_infectivity,
            ConfigKeys.Run_Number, param_obj[ConfigKeys.Run_Number]))

        success = True

        outfile.write("Test 1: checking test conditions/setup in config.json and campaign.json:\n")
        if int(param_obj[ConfigKeys.Enable_Heterogeneous_Intranode_Transmission]) != 1:
            success = False
            outfile.write("BAD: HINT is not enabled, please check the test.\n")
        else:
            if not all(x == 0 for x in campaign_obj[CampaignKeys.Start_Day]):
                success = False
                outfile.write("BAD: All intervention should start at day 0, please check campaign.json.\n")

            if not all(x == 1 for x in campaign_obj[CampaignKeys.Demographic_Coverage]):
                success = False
                outfile.write("BAD: {} should be 1, please check campaign.json.\n".format(CampaignKeys.Demographic_Coverage))

            expected_property_restrictions = []
            # seed_groups = list(filter(lambda value: 'seed' in value.lower(),
            #                           property_obj[DemographicsKeys.PropertyKeys.Values]))
            # easier to read
            property_values = property_obj[DemographicsKeys.PropertyKeys.Values]
            seed_groups = [value for value in property_values if 'seed' in value.lower()]
            for value in seed_groups:
                expected_property_restrictions.append(["{0}:{1}".format(
                    property_obj[DemographicsKeys.PropertyKeys.Property], value)])
            if campaign_obj[CampaignKeys.Property_Restrictions] != expected_property_restrictions:
                success = False
                outfile.write(
                    "BAD: {0} should be {1}, got {2} in campaign.json, please check campaign.json.\n".format(
                        CampaignKeys.Property_Restrictions, expected_property_restrictions,
                        campaign_obj[CampaignKeys.Property_Restrictions]))
        outfile.write("Test 1: campaign and config met preconditions: {}.\n".format(success))

        if success:
            outfile.write("Test 2: Testing contagion and probability with calculated values for every time step:\n")
            outfile.write("Test 3: Testing New Infection channel from property report based on transmission matrix:\n")
            outfile.write("Test 2 and 3 and running at the same time:\n")
            result_2 = result_3 = True
            stat_pop = stdout_df[Stdout.stat_pop]
            infected = stdout_df[Stdout.infected]
            duration = param_obj[ConfigKeys.Simulation_Duration]
            transmission_matrix = property_obj[DemographicsKeys.PropertyKeys.Matrix]
            for seed_group in seed_groups:
                contagion_list = []
                prob_list = []
                # get the name of susceptible group, there should be only one susceptible group based on the query
                susceptible_group = [value for value in property_obj[DemographicsKeys.PropertyKeys.Values
                ] if "susceptible" in value.lower() and seed_group.split('_')[-1] in value][0]
                # get all the column names that contains the seed group
                seed_cols = [c for c in property_df.columns if seed_group in c]
                # get all the column names that contains the susceptible group
                susceptible_cols = [c for c in property_df.columns if susceptible_group in c]

                # test data for seed group
                infected_seed = property_df[[c for c in seed_cols if channels[0] in c]]
                # population_seed = property_df[[c for c in seed_cols if channels[2] in c]]

                # test data for susceptible group
                infected_sus = property_df[[c for c in susceptible_cols if channels[0] in c]]
                new_infection_sus = property_df[[c for c in susceptible_cols if channels[1] in c]]
                population_sus = property_df[[c for c in susceptible_cols if channels[2] in c]]

                expected_new_infection_list = []
                failed_count = 0
                for t in range(duration):
                    # calculate infectivity of seed group
                    # infectivity_seed = base_infectivity * infected_seed.iloc[t][0] / population_seed.iloc[t][0]
                    # nomalized with total population
                    infectivity_seed = base_infectivity * infected_seed.iloc[t][0] / stat_pop[t]

                    # calculate contagion of susceptible group
                    calculated_contagion = infectivity_seed * transmission_matrix[property_values.index(seed_group)][
                        property_values.index(susceptible_group)]

                    # get contagion of susceptible group from stdout_df
                    group_id = property_values.index(susceptible_group)
                    actual_contagion = stdout_df[(stdout_df[ConfigKeys.Simulation_Timestep] == t) &
                                                 (stdout_df[Stdout.group_id] == group_id)][Stdout.contagion].values[0]
                    contagion_list.append([actual_contagion, calculated_contagion])
                    if math.fabs(calculated_contagion - actual_contagion) > 5e-2 * calculated_contagion:
                        result_2 = success = False
                        outfile.write("    BAD: at time step {0}, for group {1} id {2}, the total contagion is {3}, "
                                      "expected {4}.\n".format(t, susceptible_group, group_id, actual_contagion,
                                                               calculated_contagion
                        ))

                    # calculate infection probability based on contagion
                    calculated_prob = 1.0 - math.exp(-1 * calculated_contagion * param_obj[ConfigKeys.Simulation_Timestep])
                    # get infection probability of susceptible group from stdout_df
                    actual_prob = stdout_df[(stdout_df[ConfigKeys.Simulation_Timestep] == t) &
                                                 (stdout_df[Stdout.group_id] == group_id)][Stdout.prob].values[0]
                    prob_list.append([actual_prob, calculated_prob])
                    if math.fabs(calculated_prob - actual_prob) > 5e-2 * calculated_prob:
                        result_2 = success = False
                        outfile.write("    BAD: at time step {0}, for group {1} id {2}, the infected probability is "
                                      "{3}, expected {4}.\n".format( t, susceptible_group, group_id, actual_prob,
                                                                     calculated_prob
                        ))

                    # calculate expected new infection for susceptible group
                    susceptible_population = population_sus.iloc[t][0] - infected_sus.iloc[t][0]
                    expected_new_infection = susceptible_population * calculated_prob
                    expected_new_infection_list.append(expected_new_infection)
                    actual_new_infection = new_infection_sus.iloc[t][0]
                    with open("DEBUG_binomial_test_{}.txt".format(susceptible_group), 'w') as file:
                        if expected_new_infection < 5 or susceptible_population * (1 - calculated_prob) < 5:
                            binom_pmf = stats.binom.pmf(k=actual_new_infection, n=susceptible_population, p=calculated_prob)
                            if binom_pmf < 1e-3:
                                failed_count += 1
                                outfile.write("WARNING: at timestep {0}, new infections for {1} group is {2}, expected "
                                              " = {3}, calculated binomial pmf is {4}.\n"
                                              "".format(t, susceptible_group, actual_new_infection,
                                                        expected_new_infection, binom_pmf))

                        elif not sft.test_binomial_99ci(num_success=actual_new_infection, num_trials=susceptible_population,
                                                   prob=calculated_prob, report_file=file,
                                                   category="new infections for {0} at time {1}".format(susceptible_group, t)):
                            failed_count += 1
                            standard_deviation = math.sqrt(
                                calculated_prob * (1 - calculated_prob) * susceptible_population)
                            # 99% confidence interval
                            lower_bound = expected_new_infection - 3 * standard_deviation
                            upper_bound = expected_new_infection + 3 * standard_deviation
                            outfile.write("WARNING: at timestep {0}, new infections for {1} group is {2}, expected "
                                          "within 99% binomial interval ({3}, {4}) with mean = {5}\n".format(t, susceptible_group,
                                                                                          actual_new_infection,
                                                                                          lower_bound, upper_bound,
                                                                                          expected_new_infection))


                sft.plot_data(np.array(contagion_list)[:, 0], np.array(contagion_list)[:, 1], label1='contagion from logging', label2="calculated contagion",
                                  title="actual vs. expected contagion", xlabel='day',ylabel='contagion',category="contagion_{}".format(susceptible_group),
                                  line=True, alpha=0.5, overlap=True)
                sft.plot_data(np.array(prob_list)[:, 0], np.array(prob_list)[:, 1], label1='probability from logging', label2="calculated probability",
                                  title="actual vs. expected probability", xlabel='day',ylabel='probability',category="probability_{}".format(susceptible_group),
                                  line=True, alpha=0.5, overlap=True)

                sft.plot_data(new_infection_sus.ix[:, 0].tolist(), expected_new_infection_list,
                                  label1='from property report',
                                  label2="calculated data",
                                  title="new infections for {}".format(susceptible_group),
                                  xlabel='day', ylabel='new_infections',
                                  category="new_infections_{}".format(susceptible_group),
                                  line=False, alpha=0.5, overlap=True, sort=False)

                message_template = "{0}: binomial test for {1} failed {2} times within {3} total timesteps, which is " \
                                   "{4}% fail rate, test is {5}.\n"
                if failed_count / duration > 5e-2:
                    result_3 = success = False
                    outfile.write(message_template.format("BAD", new_infection_sus.columns.values, failed_count,
                                                          duration, (failed_count / duration) * 100, "failed"))
                else:
                    outfile.write(message_template.format("GOOD", new_infection_sus.columns.values, failed_count,
                                                          duration, (failed_count / duration) * 100, "passed"))

            outfile.write("Test 2: result is: {}.\n".format(result_2))
            outfile.write("Test 3: result is: {}.\n".format(result_3))

        outfile.write(sft.format_success_msg(success))
    if debug:
        print(sft.format_success_msg(success))
    return success
def create_report_file(param_obj, campaign_obj, property_obj, property_df, stdout_df, recorder_obj,
                       report_name, report_event_recorder, stdout_filename, debug):
    with open(report_name, "w") as outfile:
        for name, param in param_obj.items():
            outfile.write("{0} = {1}\n".format(name, param))
        sample_threshold = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold])
        base_sensitivity = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity])
        base_specificity = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity])
        ip_key_value = campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value]
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold, sample_threshold))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity, base_sensitivity))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity, base_specificity))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value,
                                           ip_key_value))
        success = recorder_obj[1]

        if not success:
            error_message = recorder_obj[0]
            outfile.write("Failed to parse report file: {0}, get exception: {1}.\n".format(report_event_recorder,
                                                                                           error_message
                                                                                           ))
        else:
            # Throw warning messages for condition checks. Make sure all features are enabled.
            if not sample_threshold:
                outfile.write("WARNING: {0} should not be 0 in this test, got {1} from compaign file. Please fix the test.\n"
                              "".format(CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold, sample_threshold))
            if base_specificity == 1:
                outfile.write("WARNING: the {0} is {1}, expected value is less than 1.\n".format(
                    CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity, base_specificity))
            if base_sensitivity == 1:
                outfile.write("WARNING: the {0} is {1}, expected value is less than 1.\n".format(
                    CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity, base_sensitivity))
            if not ip_key_value:
                outfile.write(
                    "WARNING: {0} should not be empty in this test, got '{1}' from compaign file. Please fix the test.\n"
                    "".format(CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value, ip_key_value))

            duration = param_obj[ConfigKeys.Simulation_Duration]
            base_infectivity = param_obj[ConfigKeys.Base_Infectivity]

            positive_list = []
            negative_list = []
            positive_event_list = []
            negative_event_list = []

            # get infected and stat_pop channels for the selected IP group from property report
            infected_ip_group_list = property_df[[c for c in property_df.columns if Diagnostic_Support.channels[0] in c]]
            stat_pop_ip_group_list = property_df[[c for c in property_df.columns if Diagnostic_Support.channels[-1] in c]]

            # group by time and event name, then count how many event in each time step and put the value into a new
            # column named: "Test result counts"
            event_df = recorder_obj[0]
            event_df = event_df.groupby([Diagnostic_Support.ReportColumn.time,
                                         Diagnostic_Support.ReportColumn.event]).size().reset_index()
            event_df.rename(columns={0: Diagnostic_Support.ReportColumn.counts}, inplace=True)

            contagion_list = []
            expected_positive_count = expected_negative_count = 0
            for t in range(1, duration):
                # Test 1: make sure we get the correct contagion sample and
                # number of positive and negative results in StdOut.txt
                stdout_t_df = stdout_df[stdout_df[Diagnostic_Support.ConfigKeys.Simulation_Timestep] == t]

                #stdout_next_t_df = stdout_df[stdout_df[Diagnostic_Support.ConfigKeys.Simulation_Timestep] == t + 1]

                infected = stdout_t_df[Diagnostic_Support.Stdout.infected].iloc[0]
                stat_pop = stdout_t_df[Diagnostic_Support.Stdout.stat_pop].iloc[0]

                test_positive = stdout_t_df[Diagnostic_Support.Stdout.test_positive].iloc[0]
                test_negative = stdout_t_df[Diagnostic_Support.Stdout.test_negative].iloc[0]
                test_default = stdout_t_df[Diagnostic_Support.Stdout.test_default].iloc[0]
                envi_sample = stdout_t_df[Diagnostic_Support.Stdout.sample].iloc[0]
                ip = stdout_t_df[Diagnostic_Support.Stdout.ip_value].iloc[0]

                infected_ip_group = infected_ip_group_list.iloc[t - 1][0]
                stat_pop_ip_group = stat_pop_ip_group_list.iloc[t - 1][0]
                if stat_pop == stat_pop_ip_group and infected == infected_ip_group:
                    success = False
                    outfile.write("BAD: at time step {0} the total stat_pop = {1} and total infect = {2}, we got "
                                  "stat_pop_ip_group = {3} and infected_ip_group = {4} in group {5}, we expect to "
                                  "see less stat_pop and infected individual in the IP group , this is not a valid test "
                                  "for Environment_IP_Key_Value, please check the test condition.\n".format(t, stat_pop,
                                   infected, stat_pop_ip_group, infected_ip_group, ip_key_value))
                if ip_key_value != ip:
                    success = False
                    outfile.write("BAD: at time step {0}, IP={1} from StdOut.txt, expected IP={2}.\n".format(
                        t, ip, ip_key_value))
                susceptible = stat_pop_ip_group - infected_ip_group
                message = "BAD: at time {0}, group {1} has infected individuals = {2} and susceptible individuals = {3}," \
                " expected {4} individuals receive a {5} test result, got {6} from logging.\n"

                # calculated environmental contagion
                contagion = base_infectivity * infected_ip_group / stat_pop_ip_group
                contagion_list.append(contagion)
                if math.fabs(contagion - envi_sample) > envi_sample * 1e-2:
                    success = False
                    outfile.write(
                        "BAD: at time step {0} the environmental sample for IP group {1} is {2}, expected value is {3}"
                        ".\n".format(
                            t, ip_key_value, envi_sample, contagion
                        ))
                # positive = real positive or false positive
                # negative = false negative or real negative
                if contagion > sample_threshold:
                    expected_test_positive = base_sensitivity
                    expected_test_negative = 1.0 - base_sensitivity
                else:
                    expected_test_positive = 1.0 - base_specificity
                    expected_test_negative = base_specificity

                expected_positive_count += expected_test_positive
                expected_negative_count += expected_test_negative

                # no test default in this intervention
                expected_test_default = 0
                if test_default != expected_test_default:
                    success = False
                    outfile.write(message.format(
                        t, ip_key_value, infected_ip_group, susceptible, expected_test_default,
                        "default", test_default))
                positive_list.append([test_positive, expected_test_positive])
                negative_list.append([test_negative, expected_test_negative])
                # End of Test 1 at this time step

                # Test 2: make sure events reported in ReportEventRecorder.csv and test results from StdOut.txt are matched.
                message = "BAD: at time {0}, {1} records {2} {3} events, got {4} {5} results from {5}.\n"

                # get the positive event count from data frame
                positive_event = event_df[
                    (event_df[Diagnostic_Support.ReportColumn.time] == t) &
                    (event_df[Diagnostic_Support.ReportColumn.event] == Diagnostic_Support.ReportColumn.positive)][
                    Diagnostic_Support.ReportColumn.counts].values
                if len(positive_event):
                    positive_event = positive_event[0]
                else:
                    positive_event = 0

                # StdOut.txt should match ReportEventRecorder.csv
                if test_positive != positive_event:
                    success = False
                    outfile.write(message.format(
                        t, report_event_recorder, positive_event, Diagnostic_Support.ReportColumn.positive, test_positive,
                        Diagnostic_Support.Stdout.test_positive, stdout_filename))

                # get the negative event count from data frame
                negative_event = event_df[
                    (event_df[Diagnostic_Support.ReportColumn.time] == t) &
                    (event_df[Diagnostic_Support.ReportColumn.event] == Diagnostic_Support.ReportColumn.negative)][
                    Diagnostic_Support.ReportColumn.counts].values
                if len(negative_event):
                    negative_event = negative_event[0]
                else:
                    negative_event = 0

                # StdOut.txt should match ReportEventRecorder.csv
                if test_negative != negative_event:
                    success = False
                    outfile.write(message.format(
                        t, report_event_recorder, negative_event, Diagnostic_Support.ReportColumn.negative, test_negative,
                        Diagnostic_Support.Stdout.test_negative, stdout_filename))

                positive_event_list.append(positive_event)
                negative_event_list.append(negative_event)
                # End of Test 2 at this time step

            stdout_sum = stdout_df.sum()

            result = sft.test_multinomial([stdout_sum[Diagnostic_Support.Stdout.test_positive],
                                               stdout_sum[Diagnostic_Support.Stdout.test_negative]],
                                              proportions=[expected_positive_count, expected_negative_count],
                                              report_file=outfile,
                                              prob_flag=False, )

            message = "{0}: the total test positive and negative counts from StdOut.txt are {1} and {2}, expected values" \
                      " are {3} and {4}.\n"

            if result:
                outfile.write(message.format("GOOD", stdout_sum[Diagnostic_Support.Stdout.test_positive],
                                             stdout_sum[Diagnostic_Support.Stdout.test_negative],
                                             expected_positive_count, expected_negative_count))
            else:
                success = False
                outfile.write(message.format("BAD", stdout_sum[Diagnostic_Support.Stdout.test_positive],
                                             stdout_sum[Diagnostic_Support.Stdout.test_negative],
                                             expected_positive_count, expected_negative_count))


            # these two plots are replaced with the scatter with fit line plots
            # sft.plot_data(np.array(positive_list)[:, 0], np.array(positive_list)[:, 1],
            #                   label1="Actual",
            #                   label2="Probability of Positive",
            #                   title="Test Positive\n Group {}".format(ip_key_value), xlabel="Day",
            #                   ylabel="Positive count",
            #                   category='Test_Positive_Probability', overlap=False)
            # sft.plot_data(np.array(negative_list)[:, 0], np.array(negative_list)[:, 1],
            #                   label1="Actual",
            #                   label2="Probability of Negative",
            #                   title="Test Negative\n Group {}".format(ip_key_value), xlabel="Day",
            #                   ylabel="Negative count",
            #                   category='Test_Negative_Probability', overlap=False)

            sft.plot_scatter_fit_line(np.array(positive_list)[:, 0], dist2=np.array(positive_list)[:, 1],
                                          label1="Actual", label2="Probability of Positive",
                                          title="Test Positive\n Group {}".format(ip_key_value),
                                          xlabel="Day",
                                          ylabel="Positive count",
                                          category='Test_Positive_Probability_Scatter_Fit_Line')

            sft.plot_scatter_fit_line(np.array(negative_list)[:, 0], dist2=np.array(negative_list)[:, 1],
                                          label1="Actual", label2="Probability of Negative",
                                          title="Test Negative\n Group {}".format(ip_key_value),
                                          xlabel="Day",
                                          ylabel="Negative count",
                                          category='Test_Negative_Probability_Scatter_Fit_Line')

            sft.plot_data(np.array(positive_list)[:, 0], positive_event_list,
                              label1=stdout_filename,
                              label2=report_event_recorder,
                              title="Test Positive\n Group {}".format(ip_key_value), xlabel="Day",
                              ylabel="Positive count",
                              category='Test_Positive_stdout_vs_event_recorder', overlap=True, alpha=0.5)
            sft.plot_data(np.array(negative_list)[:, 0], negative_event_list,
                              label1=stdout_filename,
                              label2=report_event_recorder,
                              title="Test Negative\n Group {}".format(ip_key_value), xlabel="Day",
                              ylabel="Negative count",
                              category='Test_Negative_stdout_vs_event_recorder', overlap=True, alpha=0.5)
            sft.plot_data(stdout_df[Diagnostic_Support.Stdout.sample].tolist()[1:], contagion_list,
                              label1="Actual",
                              label2="Expected",
                              title="Environmental_Contagion", xlabel="Day",
                              ylabel="Environmental_Contagion",
                              category='Environmental_Contagion', overlap=True, alpha=0.5)
        outfile.write(sft.format_success_msg(success))
        if debug:
            print(sft.format_success_msg(success))
        return success
def create_report_file(param_obj, stdout_df, property_obj, property_df, report_name, debug):
    with open(report_name, "w") as outfile:
        for name, param in param_obj.items():
            outfile.write("{0} = {1}\n".format(name, param))
        success = True
        start_day = param_obj[ConfigKeys.Environmental_Peak_Start]
        ramp_up = param_obj[ConfigKeys.Environmental_Ramp_Up_Duration]
        ramp_down = param_obj[ConfigKeys.Environmental_Ramp_Down_Duration]
        cut_off = param_obj[ConfigKeys.Environmental_Cutoff_Days]
        duration = param_obj[ConfigKeys.Simulation_Duration]

        peak_duration = sft.DAYS_IN_YEAR - ramp_up - ramp_down - cut_off
        peak_starttime = start_day % sft.DAYS_IN_YEAR
        peak_endtime = peak_starttime + peak_duration
        cutoff_starttime = peak_starttime + peak_duration + ramp_down
        cutoff_endtime = peak_starttime + peak_duration + ramp_down + cut_off

        amp = []
        expected_amp = []
        expected_contagion_e_list = []
        expected_contagion_c_list = []
        # adjust the times so that the ramp up starts at time 0, which means the cut off ends at time 0 too.
        adjust_time = peak_starttime - ramp_up
        peak_starttime -= adjust_time
        peak_endtime -= adjust_time
        cutoff_starttime -= adjust_time
        cutoff_endtime -= adjust_time
        cutoff_endtime %= sft.DAYS_IN_YEAR

        contagion_channels_e = [c for c in property_df.columns if channels[3] in c]
        contagion_channels_c = [c for c in property_df.columns if channels[4] in c]
        property_df[channels[3]] = property_df[contagion_channels_e].sum(axis=1)
        property_df[channels[4]] = property_df[contagion_channels_c].sum(axis=1)

        for t in range(1, duration):
            amplification = stdout_df[Stdout.amplification].iloc[t]
            day_in_year = stdout_df[Stdout.day_of_year].iloc[t]
            if day_in_year != t % sft.DAYS_IN_YEAR:
                success = False
                outfile.write("BAD: at time step {0}, day_in_year is {1}, it should be {2}.\n".format(t, day_in_year,
                                                                                                      t % sft.DAYS_IN_YEAR))
                day_in_year = t % sft.DAYS_IN_YEAR
            day_in_year -= adjust_time
            day_in_year %= sft.DAYS_IN_YEAR
            # Environment Ramp Up
            if cutoff_endtime < day_in_year < peak_starttime:
                expected_amplification = day_in_year / ramp_up
            # Environment peak
            elif peak_starttime <= day_in_year <= peak_endtime:
                expected_amplification = 1
            # Environment Ramp Down
            elif peak_endtime < day_in_year < cutoff_starttime:
                expected_amplification = (cutoff_starttime - day_in_year) / ramp_down
            # Environment cutoff
            else:
                expected_amplification = 0
            if not math.fabs(amplification - expected_amplification) <= 5e-2 * expected_amplification:
                success = False
                outfile.write(
                    "BAD: at time {0}, day of year = {1}, the environmental amplification is {2}, expected {3}.\n".format(
                        t, t % sft.DAYS_IN_YEAR, amplification, expected_amplification))
            amp.append(amplification)
            expected_amp.append(expected_amplification)

            # Sinusoidal scaling
            sinusoidal_multiplier = Sinusoidal_Support.calculate_infectiousness(
                infected_pop=1, index=t, simulation_timestep=param_obj[ConfigKeys.Simulation_Timestep],
                phase=param_obj[ConfigKeys.Infectivity_Sinusoidal_Forcing_Phase],
                base_infectivity=1,
                amplitude=param_obj[ConfigKeys.Infectivity_Sinusoidal_Forcing_Amplitude], debug=debug)
            expected_contagion_e = param_obj[ConfigKeys.Base_Infectivity] * \
                                   expected_amplification * \
                                  (len(property_obj[DemographicsKeys.PropertyKeys.Values]) ** 2)

            # infectivity scaling should only applies to contact route.
            # expected_contagion_e *= sinusoidal_multiplier

            expected_contagion_c = sinusoidal_multiplier * param_obj[ConfigKeys.Base_Infectivity] * \
                                   len(property_obj[DemographicsKeys.PropertyKeys.Values])
            actual_contagion_e = property_df[channels[3]][t]
            actual_contagion_c = property_df[channels[4]][t]
            for expected_contagion, actual_contagion, column_name in [
                (expected_contagion_e, actual_contagion_e, channels[3]),
                (expected_contagion_c, actual_contagion_c, channels[4])]:
                if not math.fabs(actual_contagion - expected_contagion) <= 5e-2 * expected_contagion:
                    success = False
                    outfile.write(
                        "BAD: at time {0}, day of year = {1}, the {2} is {3}, expected {4}.\n".format(
                            t, t % sft.DAYS_IN_YEAR, column_name, actual_contagion, expected_contagion))
            expected_contagion_e_list.append(expected_contagion_e)
            expected_contagion_c_list.append(expected_contagion_c)

        sft.plot_data(amp, expected_amp,
                      label1="Actual amplification",
                      label2="Expected amplification",
                      title="Seasonality", xlabel="Day",
                      ylabel="Environmental amplification",
                      category='seasonal_attenuation', overlap=True, alpha=0.5)

        sft.plot_data(property_df[channels[3]][1:], expected_contagion_e_list[1:],
                      label1="Actual",
                      label2="Expected",
                      title="Environmental Contagion\nSeasonality_Sinusoidal", xlabel="Day",
                      ylabel="Environmental Contagion",
                      category='Environmental_Contagion', overlap=True, alpha=0.5)

        sft.plot_data(property_df[channels[4]][1:], expected_contagion_c_list[1:],
                      label1="Actual",
                      label2="Expected",
                      title="Contact Contagion\nSeasonality_Sinusoidal", xlabel="Day",
                      ylabel="Contact Contagion",
                      category='Contact_Contagion', overlap=True, alpha=0.5)

        outfile.write(sft.format_success_msg(success))
        if debug:
            print(sft.format_success_msg(success))
        return success
def create_report_file(param_obj, inset_chart_obj, report_name, insetchart_name, debug):
    with open(report_name, "w") as outfile:
        for param in param_obj:
            outfile.write("{0} = {1}\n".format(param, param_obj[param]))

        # base_infectivity = param_obj[ConfigKeys.Base_Infectivity]

        if param_obj[ConfigKeys.Enable_Heterogeneous_Intranode_Transmission] == 1:
            outfile.write("WARNING: {0} = {1}, expected this feature is disabled".format(
                ConfigKeys.Enable_Heterogeneous_Intranode_Transmission,
            param_obj[ConfigKeys.Enable_Heterogeneous_Intranode_Transmission]))

        success = True

        outfile.write("Test 1: Testing new infections for every time step:\n")
        duration = param_obj[ConfigKeys.Simulation_Duration]

        new_infection_list_c = []
        new_infection_list_e = []

        failed_count_c = failed_count_e = 0

        with open("DEBUG_binomial_test.txt", "w") as binomial_test_file:
            for t in range(duration):
                infected = inset_chart_obj[InsetKeys.ChannelsKeys.Infected][t]
                stat_pop = inset_chart_obj[InsetKeys.ChannelsKeys.Statistical_Population][t]
                susceptible = stat_pop * (1.0 - infected)

                contagion_e = inset_chart_obj[InsetKeys.ChannelsKeys.Environmental_Contagion_Population][t]
                contagion_c = inset_chart_obj[InsetKeys.ChannelsKeys.Contact_Contagion_Population][t]

                probability_e = 1.0 - math.exp(-1 * contagion_e)
                probability_c = 1.0 - math.exp(-1 * contagion_c)

                expected_new_infections_c = probability_c * susceptible
                actual_new_infection_c = inset_chart_obj[InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT][t]
                if actual_new_infection_c > math.ceil(susceptible):
                    success = False
                    outfile.write("BAD: at time step {0} the {1} is {2} while calculated susceptible individual is"
                                  " {3}, {1} should be less than calculated susceptible individual, please check the "
                                  "test.\n".format(t, InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT,
                                                   actual_new_infection_c, susceptible))

                susceptible_e = susceptible - actual_new_infection_c
                expected_new_infections_e = probability_e * susceptible_e
                actual_new_infection_e = inset_chart_obj[InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT][t]
                if actual_new_infection_e > math.ceil(susceptible_e):
                    success = False
                    outfile.write("BAD: at time step {0} the {1} is {2} while calculated susceptible individual is"
                                  "{3}, {1} should be less than calculated susceptible individual, please check the "
                                  "test.\n".format(t, InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT,
                                                   actual_new_infection_e, susceptible_e))

                new_infection_list_c.append([actual_new_infection_c, expected_new_infections_c])
                new_infection_list_e.append([actual_new_infection_e, expected_new_infections_e])

                failed_count_c = test_new_infections(expected_new_infections_c, actual_new_infection_c, susceptible,
                                                     probability_c, failed_count_c, routes[1],insetchart_name,
                                                     binomial_test_file, t)
                failed_count_e = test_new_infections(expected_new_infections_e, actual_new_infection_e, susceptible_e,
                                                     probability_e, failed_count_e, routes[0], insetchart_name,
                                                     binomial_test_file, t)

                # actual_total_new_infection = inset_chart_obj[InsetKeys.ChannelsKeys.New_Infections][t + 1]
                # new_infection_list.append(actaul_new_infection_c + actaul_new_infection_e)
                # if actaul_new_infection_c + actaul_new_infection_e != actual_total_new_infection:
                #     success = False
                #     outfile.write("BAD: at time step {0}, in {1} the {2} channel reports {3} new infections, while "
                #                   "{4} and {5} are {6} and {7} respectively.\n".format(
                #                     t + 1, insetchart_name, InsetKeys.ChannelsKeys.New_Infections,
                #                     actual_total_new_infection,
                #                     InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT,
                #                     InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT,
                #                     actaul_new_infection_e,
                #                     actaul_new_infection_c))

        message_template = "\t{0}: (route {1}) binomial test for new infections channel failed {2} times within {3} " \
                           "total timesteps, which is {4}% fail rate, test is {5}. Please see " \
                           "'DEBUG_binomial_test.txt' for details.\n"
        for failed_count, route in [(failed_count_e, routes[0]),
                                    (failed_count_c, routes[1])]:
            if failed_count / duration > 5e-2:
                success = False
                outfile.write(message_template.format("BAD", route,
                                                      failed_count, duration, (failed_count / duration) * 100,
                                                      "failed"))
            else:
                outfile.write(message_template.format("GOOD", route,
                                                      failed_count, duration, (failed_count / duration) * 100,
                                                      "passed"))
        # plot actual and expected values for new infections
        sft.plot_data(np.array(new_infection_list_c)[:, 0], np.array(new_infection_list_c)[:, 1],
                          label1=insetchart_name, label2="expected new infections",
                          title=InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT,
                          xlabel='day', ylabel='new infections', category="new_infections_{}".format(routes[1]),
                          line=True, alpha=0.5, overlap=True)

        sft.plot_data(np.array(new_infection_list_e)[:, 0], np.array(new_infection_list_e)[:, 1],
                          label1=insetchart_name, label2="expected new infections",
                          title=InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT,
                          xlabel='day', ylabel='new infections', category="new_infections_{}".format(routes[0]),
                          line=True, alpha=0.5, overlap=True)
        outfile.write("Test 1: result is {}.\n".format(success))

        outfile.write("Test 2: Testing sums of new infections by routes match expected values.\n")
        result = True
        message_template = "\t{0}: sum of {1} is {2}, it should be closed to expected value {3}.\n"
        for new_infection_list, channel_name in [(new_infection_list_c,
                                                  InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT),
                                                 (new_infection_list_e,
                                                  InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT)]:
            new_infection_sum = np.array(new_infection_list)[:, 0].sum()
            expected_new_infections_sum = np.array(new_infection_list)[:, 1].sum()
            if math.fabs(new_infection_sum - expected_new_infections_sum) > 5e-2 * expected_new_infections_sum:
                success = result = False
                outfile.write(message_template.format("BAD", channel_name, new_infection_sum,
                                                      expected_new_infections_sum))
            else:
                outfile.write(message_template.format("GOOD", channel_name, new_infection_sum,
                                                      expected_new_infections_sum))
        outfile.write("Test 2: result is {}.\n".format(result))

        outfile.write("Test 3: Testing if {0} = {1} + {2} in {3} for every time step.\n".format(
            InsetKeys.ChannelsKeys.New_Infections,
            InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT,
            InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT,
            insetchart_name
        ))
        result = True
        expected_new_infection_list = []
        # skip the first time step t = 0, when outbreak happens, this is OK for now, next step:
        # ToDO: load stdout.txt for outbreak new infections and add it to expected_total_new_infection
        for t in range(1, duration):
            actual_total_new_infection = inset_chart_obj[InsetKeys.ChannelsKeys.New_Infections][t]
            actaul_new_infection_c = inset_chart_obj[InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT][t]
            actaul_new_infection_e = inset_chart_obj[InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT][t]
            expected_total_new_infection = actaul_new_infection_c + actaul_new_infection_e
            expected_new_infection_list.append(expected_total_new_infection)
            if expected_total_new_infection != actual_total_new_infection:
                success = result = False
                outfile.write("\tBAD: at time step {0}, in {1} the {2} channel reports {3} new infections, while "
                              "{4} and {5} are {6} and {7} respectively.\n".format(
                    t + 1, insetchart_name, InsetKeys.ChannelsKeys.New_Infections,
                    actual_total_new_infection,
                    InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT,
                    InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT,
                    actaul_new_infection_e,
                    actaul_new_infection_c))

        outfile.write("Test 3: '{0} = {1} + {2}' is {3}.\n".format(
            InsetKeys.ChannelsKeys.New_Infections,
            InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT,
            InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT,
            result
        ))

        sft.plot_data(inset_chart_obj[InsetKeys.ChannelsKeys.New_Infections][1:], expected_new_infection_list,
                          label1=InsetKeys.ChannelsKeys.New_Infections, label2="{0} + \n{1}".format(
                                InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT,
                                InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT),
                          title="{0}_{1}".format(InsetKeys.ChannelsKeys.New_Infections, insetchart_name),
                          xlabel='day(t-1, skip the first time step)', ylabel='new infections', category="total_new_infections",
                          line=True, alpha=0.5, overlap=True)

        outfile.write(sft.format_success_msg(success))
    if debug:
        print(sft.format_success_msg(success))
    return success
def create_report_file(param_obj, intervention_obj, outbreak_obj, stdout_df, report_name, debug):
    with open(report_name, "w") as outfile:
        for name, param in param_obj.items():
            outfile.write("{0} = {1}\n".format(name, param))
        success = True
        sample_threshold = float(intervention_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold])
        base_sensitivity = float(intervention_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity])
        base_specificity = float(intervention_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity])
        ip_key_value = intervention_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value]
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold, sample_threshold))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity, base_sensitivity))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity, base_specificity))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value,
                                           ip_key_value))

        # make sure no outbreak in this test, so the sample should not be greater than threshold at all time
        if outbreak_obj:
            success = False
            outfile.write("BAD: Campaign.json should not have {0}, got {1} from the json file.\n".format(
                CampaignKeys.InterventionClassKeys.OutbreakIndividual, outbreak_obj
            ))
        if sample_threshold:
            outfile.write("WARNING: {0} should be 0 in this test, got {1} from compaign file. Please fix the test.\n"
                          "".format(CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold, sample_threshold))
        if base_sensitivity != 1:
            outfile.write("WARNING: the {0} is {1}, expected value is 1.\n".format(
                CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity, base_sensitivity))
        if ip_key_value:
            success = False
            outfile.write("BAD: {0} should be empty in this test, got {1} from compaign file. Please fix the test.\n"
                          "".format(CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value, ip_key_value))

        duration = param_obj[ConfigKeys.Simulation_Duration]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        expected_positive_count = expected_negative_count = 0
        contagion_list = []
        contagion = 0
        for t in range(1, duration):
            stdout_t_df = stdout_df[stdout_df[Diagnostic_Support.ConfigKeys.Simulation_Timestep] == t]
            infected = stdout_t_df[Diagnostic_Support.Stdout.infected].iloc[0]
            stat_pop = stdout_t_df[Diagnostic_Support.Stdout.stat_pop].iloc[0]
            envi_sample = stdout_t_df[Diagnostic_Support.Stdout.sample].iloc[0]

            # calculated environmental contagion
            contagion = base_infectivity * infected /stat_pop
            if math.fabs(contagion - envi_sample) > envi_sample * 1e-2:
                success = False
                outfile.write("BAD: at time step {0} the environmental sample is {1}, expected value is {2}.\n".format(
                    t, envi_sample, contagion
                ))
            if contagion > sample_threshold:
                expected_test_positive = base_sensitivity
                expected_test_negative = 1.0 - base_sensitivity
            else:
                expected_test_positive = 1.0 - base_specificity
                expected_test_negative = base_specificity
            contagion_list.append(contagion)

            expected_positive_count += expected_test_positive
            expected_negative_count += expected_test_negative

        stdout_sum = stdout_df.sum()

        result = sft.test_multinomial([stdout_sum[Diagnostic_Support.Stdout.test_positive],
                                  stdout_sum[Diagnostic_Support.Stdout.test_negative]],
                                 proportions=[expected_positive_count, expected_negative_count],
                                 report_file=outfile,
                                 prob_flag=False, )

        message = "{0}: the total test positive and negative counts from StdOut.txt are {1} and {2}, expected values" \
                  " are {3} and {4}.\n"

        if result:
            outfile.write(message.format("GOOD", stdout_sum[Diagnostic_Support.Stdout.test_positive],
                                         stdout_sum[Diagnostic_Support.Stdout.test_negative],
                                         expected_positive_count, expected_negative_count))
        else:
            success = False
            outfile.write(message.format("BAD", stdout_sum[Diagnostic_Support.Stdout.test_positive],
                                         stdout_sum[Diagnostic_Support.Stdout.test_negative],
                                         expected_positive_count, expected_negative_count))

        sft.plot_data(stdout_df[Diagnostic_Support.Stdout.sample].tolist()[1:], contagion_list,
                          label1="Actual",
                          label2="Expected",
                          title="Environmental_Contagion", xlabel="Day",
                          ylabel="Environmental_Contagion",
                          category='Environmental_Contagion', overlap=True, alpha=0.5)
        outfile.write(sft.format_success_msg(success))
        if debug:
            print(sft.format_success_msg(success))
        return success
def create_report_file(param_obj, campaign_obj, stdout_df, recorder_obj, report_name, report_event_recorder, debug):
    with open(report_name, "w") as outfile:
        for name, param in param_obj.items():
            outfile.write("{0} = {1}\n".format(name, param))
        sample_threshold = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold])
        base_sensitivity = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity])
        base_specificity = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity])
        ip_key_value = campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value]
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold, sample_threshold))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity, base_sensitivity))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity, base_specificity))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value,
                                           ip_key_value))
        success = recorder_obj[1]

        if not success:
            error_message = recorder_obj[0]
            outfile.write("Failed to parse report file: {0}, get exception: {1}.\n".format(report_event_recorder,
                                                                                           error_message
                                                                                           ))
        else:
            # the following condition checks throw warning messages instead of fail the test.
            if sample_threshold:
                outfile.write("WARNING: {0} should be 0 in this test, got {1} from compaign file. Please fix the test.\n"
                              "".format(CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold, sample_threshold))
            if base_specificity != 1:
                outfile.write("WARNING: the {0} is {1}, expected value is 1.\n".format(
                    CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity, base_specificity))
            if base_sensitivity != 1:
                outfile.write("WARNING: the {0} is {1}, expected value is 1.\n".format(
                    CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity, base_sensitivity))
            if ip_key_value:
                outfile.write(
                    "WARNING: {0} should be empty in this test, got {1} from compaign file. Please fix the test.\n"
                    "".format(CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value, ip_key_value))

            # group by time and event name, then count how many event in each time step and put the value into a new
            # column named: "Test result counts"
            event_df = recorder_obj[0]
            event_df = event_df.groupby([Diagnostic_Support.ReportColumn.time, Diagnostic_Support.ReportColumn.event]).size().reset_index()
            event_df.rename(columns={0: Diagnostic_Support.ReportColumn.counts}, inplace=True)

            #event_df[ReportColumn.counts] = event_df.groupby(ReportColumn.time)[ReportColumn.event].transform('count')

            duration = param_obj[ConfigKeys.Simulation_Duration]
            positive_list = []
            negative_list = []
            for t in range(1, duration):
                # get values of how many test positive and test negative for each time step from stdout file
                stdout_t_df = stdout_df[stdout_df[Diagnostic_Support.ConfigKeys.Simulation_Timestep] == t]
                test_positive = stdout_t_df[Diagnostic_Support.Stdout.test_positive].iloc[0]
                test_negative = stdout_t_df[Diagnostic_Support.Stdout.test_negative].iloc[0]

                message = "BAD: at time {0}, {1} records {2} {3}, got {4} {5} result from logging.\n"

                # get the positive event count from data frame
                positive_event = event_df[
                    (event_df[Diagnostic_Support.ReportColumn.time] == t) &
                    (event_df[Diagnostic_Support.ReportColumn.event] == Diagnostic_Support.ReportColumn.positive)] \
                [Diagnostic_Support.ReportColumn.counts].values
                if len(positive_event):
                    positive_event = positive_event[0]
                else:
                    positive_event = 0

                # StdOut.txt should match ReportEventRecorder.csv
                if test_positive != positive_event:
                    success = False
                    outfile.write(message.format(
                        t, report_event_recorder, positive_event, Diagnostic_Support.ReportColumn.positive, test_positive,
                        Diagnostic_Support.Stdout.test_positive))

                # get the negative event count from data frame
                negative_event = event_df[(event_df[Diagnostic_Support.ReportColumn.time] == t) &
                                          (event_df[Diagnostic_Support.ReportColumn.event] == Diagnostic_Support.ReportColumn.negative)][
                    Diagnostic_Support.ReportColumn.counts].values
                if len(negative_event):
                    negative_event = negative_event[0]
                else:
                    negative_event = 0

                # StdOut.txt should match ReportEventRecorder.csv
                if test_negative != negative_event:
                    success = False
                    outfile.write(message.format(
                        t, report_event_recorder, negative_event, Diagnostic_Support.ReportColumn.negative, test_negative,
                        Diagnostic_Support.Stdout.test_negative))

                positive_list.append([test_positive, positive_event])
                negative_list.append([test_negative, negative_event])
            sft.plot_data(np.array(positive_list)[:, 0], np.array(positive_list)[:, 1],
                              label1="Stdout",
                              label2=report_event_recorder,
                              title="Test Positive vs. {}".format(Diagnostic_Support.ReportColumn.positive),
                              xlabel="Day",
                              ylabel="Positive count",
                              category='Test_Positive', overlap=True, alpha=0.5)
            sft.plot_data(np.array(negative_list)[:, 0], np.array(negative_list)[:, 1],
                              label1="Stdout",
                              label2=report_event_recorder,
                              title="Test Negative vs. {}".format(Diagnostic_Support.ReportColumn.negative),
                              xlabel="Day",
                              ylabel="Negative count",
                              category='Test_Negative', overlap=True, alpha=0.5)
        outfile.write(sft.format_success_msg(success))
        if debug:
            print(sft.format_success_msg(success))
        return success
예제 #17
0
def create_report_file(param_obj, inset_chart_obj, report_name,
                       insetchart_name, debug):
    with open(report_name, "w") as outfile:
        config_name = param_obj[ConfigKeys.Config_Name]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        outfile.write("Config_name = {}\n".format(config_name))
        outfile.write("{0} = {1} {2} = {3}\n".format(
            ConfigKeys.Base_Infectivity, base_infectivity,
            ConfigKeys.Run_Number, param_obj[ConfigKeys.Run_Number]))

        if param_obj[
                ConfigKeys.Enable_Heterogeneous_Intranode_Transmission] == 1:
            outfile.write(
                "WARNING: {0} = {1}, expected this feature is disabled".format(
                    ConfigKeys.Enable_Heterogeneous_Intranode_Transmission,
                    param_obj[ConfigKeys.
                              Enable_Heterogeneous_Intranode_Transmission]))

        success = True

        outfile.write("Testing: Testing contagion for every time step:\n")
        duration = param_obj[ConfigKeys.Simulation_Duration]

        contagion_list_c = []

        for t in range(duration - 1):
            infected = inset_chart_obj[InsetKeys.ChannelsKeys.Infected][t]
            # population = inset_chart_obj[InsetKeys.ChannelsKeys.Statistical_Population][t]
            # calculate contagion
            # The Infected channel in InsetChart is normalized data
            calculated_contagion = base_infectivity * infected  # / population

            # get contagion from insetchart file
            actual_contagion_c = inset_chart_obj[
                InsetKeys.ChannelsKeys.Contact_Contagion_Population][t]

            contagion_list_c.append([actual_contagion_c, calculated_contagion])

            if math.fabs(calculated_contagion -
                         actual_contagion_c) > 5e-2 * calculated_contagion:
                success = False
                outfile.write(
                    "    BAD: at time step {0}, for route {1}, the total contagion is {2}, "
                    "expected {3}.\n".format(t, routes[1], actual_contagion_c,
                                             calculated_contagion))

        # plot actual and expected values for contagion
        sft.plot_data(
            np.array(contagion_list_c)[:, 0],
            np.array(contagion_list_c)[:, 1],
            label1=insetchart_name,
            label2="calculated contagion",
            title=InsetKeys.ChannelsKeys.Contact_Contagion_Population,
            xlabel='day',
            ylabel='contagion',
            category="contagion_{}".format(routes[1]),
            line=True,
            alpha=0.5,
            overlap=True)

        outfile.write(sft.format_success_msg(success))
    if debug:
        print(sft.format_success_msg(success))
    return success
예제 #18
0
def create_report_file(param_obj, campaign_obj, stdout_df, property_df,
                       property_obj, inset_chart_obj, insetchart_name,
                       property_report_name, report_name, debug):
    with open(report_name, "w") as sft_report_file:
        config_name = param_obj[ConfigKeys.Config_Name]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        sft_report_file.write("Config_name = {}\n".format(config_name))
        sft_report_file.write("{0} = {1} {2} = {3}\n".format(
            ConfigKeys.Base_Infectivity, base_infectivity,
            ConfigKeys.Run_Number, param_obj[ConfigKeys.Run_Number]))

        success = True

        sft_report_file.write(
            "Test 1: checking test conditions/setup in config.json and campaign.json:\n"
        )
        if int(param_obj[
                ConfigKeys.Enable_Heterogeneous_Intranode_Transmission]) != 1:
            success = False
            sft_report_file.write(
                "BAD: HINT is not enabled, please check the test.\n")
        else:
            if float(param_obj[ConfigKeys.Node_Contagion_Decay_Rate]) != 1:
                success = False
                sft_report_file.write(
                    "BAD: Expect Environmental contagion decay 100%, but Node_Contagion_Decay_Rate = {}"
                    ", please check the test.\n".format(
                        param_obj[ConfigKeys.Node_Contagion_Decay_Rate]))

            if not all(x == 0 for x in campaign_obj[CampaignKeys.Start_Day]):
                success = False
                sft_report_file.write(
                    "BAD: All intervention should start at day 0, please check campaign.json.\n"
                )

            if not all(
                    x == 0.05
                    for x in campaign_obj[CampaignKeys.Demographic_Coverage]):
                success = False
                sft_report_file.write(
                    "BAD: {} should be 0.05, please check campaign.json.\n".
                    format(CampaignKeys.Demographic_Coverage))

            expected_property_restrictions = []

            property_values = property_obj[
                DemographicsKeys.PropertyKeys.Values]
            seed_groups = [
                value for value in property_values if 'seed' in value.lower()
            ]
            for value in seed_groups:
                expected_property_restrictions.append([
                    "{0}:{1}".format(
                        property_obj[DemographicsKeys.PropertyKeys.Property],
                        value)
                ])
            if campaign_obj[
                    CampaignKeys.
                    Property_Restrictions] != expected_property_restrictions:
                success = False
                sft_report_file.write(
                    "BAD: {0} should be {1}, got {2} in campaign.json, please check campaign.json.\n"
                    .format(CampaignKeys.Property_Restrictions,
                            expected_property_restrictions,
                            campaign_obj[CampaignKeys.Property_Restrictions]))
        sft_report_file.write(
            "Test 1: campaign and config met preconditions: {}.\n".format(
                success))

        if success:
            sft_report_file.write(
                "Test 2: Testing contagion and probability for each Routes for every time step:\n"
            )
            sft_report_file.write(
                "Test 3: Testing New Infection channel from property report based on transmission matrix "
                "for every timestep:\n")
            sft_report_file.write(
                "Test 4: testing total new infection by routes match the total expected new infections"
                "for each group.\n".format(
                    InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT,
                    InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT,
                    insetchart_name, property_report_name))
            sft_report_file.write(
                "Test 2, 3 and 4 and running at the same time:\n")
            result_2 = result_3 = result_4 = True
            stat_pop = stdout_df[Stdout.stat_pop]
            duration = param_obj[ConfigKeys.Simulation_Duration]
            transmission_matrix_e = property_obj[
                DemographicsKeys.PropertyKeys.TransmissionMatrix][routes[0]]
            transmission_matrix_c = property_obj[
                DemographicsKeys.PropertyKeys.TransmissionMatrix][routes[1]]
            for seed_group in seed_groups:
                # get the name of susceptible group, there should be only one susceptible group based on the query
                susceptible_group = [
                    value for value in property_obj[
                        DemographicsKeys.PropertyKeys.Values]
                    if "susceptible" in value.lower()
                ][0]
                # get all the column names that contains the seed group
                seed_cols = [c for c in property_df.columns if seed_group in c]
                # get all the column names that contains the susceptible group
                susceptible_cols = [
                    c for c in property_df.columns if susceptible_group in c
                ]

                # test data for seed group
                infected_seed = property_df[[
                    c for c in seed_cols if channels[0] in c
                ]]
                contagion_seed_e = property_df[[
                    c for c in seed_cols if channels[3] in c
                ]]
                contagion_seed_c = property_df[[
                    c for c in seed_cols if channels[4] in c
                ]]

                # test data for susceptible group
                infected_sus = property_df[[
                    c for c in susceptible_cols if channels[0] in c
                ]]
                new_infection_sus_e = property_df[[
                    c for c in susceptible_cols if channels[1] in c
                ]]
                new_infection_sus_c = property_df[[
                    c for c in susceptible_cols if channels[2] in c
                ]]
                contagion_sus_e = property_df[[
                    c for c in susceptible_cols if channels[3] in c
                ]]
                contagion_sus_c = property_df[[
                    c for c in susceptible_cols if channels[4] in c
                ]]
                population_sus = property_df[[
                    c for c in susceptible_cols if channels[5] in c
                ]]

                expected_new_infection_list_e = []
                expected_new_infection_list_c = []
                contagion_list_e = [[contagion_sus_e.iloc[0][0], 0]]
                contagion_list_c = [[contagion_sus_c.iloc[0][0], 0]]

                failed_count_e = 0
                failed_count_c = 0
                with open(
                        "DEBUG_binomial_test_{}.txt".format(susceptible_group),
                        'w') as group_file:
                    for t in range(duration - 1):
                        infectivity_seed = base_infectivity * infected_seed.iloc[
                            t][0]

                        # calculate contagion of susceptible group
                        # environmental contagion decay 100% at each time step so it works as contact contagion
                        # "contact" route will be normalized by total population
                        # "environmental" route will be normalized by group population
                        calculated_contagion_e = infectivity_seed * \
                                                 transmission_matrix_e[property_values.index(seed_group)][
                            property_values.index(susceptible_group)] / population_sus.iloc[t][0]

                        calculated_contagion_c = infectivity_seed * \
                                                 transmission_matrix_c[property_values.index(seed_group)][
                            property_values.index(susceptible_group)] / stat_pop[t]

                        # get contagion of susceptible group from property report
                        actual_contagion_e = contagion_sus_e.iloc[t + 1][0]
                        actual_contagion_c = contagion_sus_c.iloc[t + 1][0]

                        contagion_list_e.append(
                            [actual_contagion_e, calculated_contagion_e])
                        contagion_list_c.append(
                            [actual_contagion_c, calculated_contagion_c])

                        if math.fabs(calculated_contagion_e -
                                     actual_contagion_e
                                     ) > 5e-2 * calculated_contagion_e:
                            result_2 = success = False
                            sft_report_file.write(
                                "    BAD: at time step {0}, for group {1} route {2}, the contagion is {3}, "
                                "expected {4}.\n".format(
                                    t + 1, susceptible_group, routes[0],
                                    actual_contagion_e,
                                    calculated_contagion_e))

                        if math.fabs(calculated_contagion_c -
                                     actual_contagion_c
                                     ) > 5e-2 * calculated_contagion_c:
                            result_2 = success = False
                            sft_report_file.write(
                                "    BAD: at time step {0}, for group {1} route {2}, the contagion is {3}, "
                                "expected {4}.\n".format(
                                    t + 1, susceptible_group, routes[1],
                                    actual_contagion_c,
                                    calculated_contagion_c))

                        # calculate infection probability based on contagion
                        calculated_prob_e = 1.0 - math.exp(
                            -1 * calculated_contagion_e *
                            param_obj[ConfigKeys.Simulation_Timestep])
                        calculated_prob_c = 1.0 - math.exp(
                            -1 * calculated_contagion_c *
                            param_obj[ConfigKeys.Simulation_Timestep])

                        # calculate expected new infection for susceptible group
                        susceptible_population_c = population_sus.iloc[t][
                            0] - infected_sus.iloc[t][0]
                        expected_new_infection_c = susceptible_population_c * calculated_prob_c

                        # Superinfection is not supported, so individuals may not be infected from both the environmental and the contact route.
                        susceptible_population_e = susceptible_population_c - new_infection_sus_c.iloc[
                            t + 1][0]
                        expected_new_infection_e = susceptible_population_e * calculated_prob_e

                        expected_new_infection_list_e.append(
                            expected_new_infection_e)
                        expected_new_infection_list_c.append(
                            expected_new_infection_c)

                        actual_new_infection_e = new_infection_sus_e.iloc[t +
                                                                          1][0]
                        actual_new_infection_c = new_infection_sus_c.iloc[t +
                                                                          1][0]

                        # run the same test for both routes
                        failed_count_e = hint_support.test_new_infections(
                            expected_new_infection_e, actual_new_infection_e,
                            calculated_prob_e, failed_count_e, routes[0],
                            t + 1, susceptible_group, sft_report_file,
                            susceptible_population_e, group_file)

                        failed_count_c = hint_support.test_new_infections(
                            expected_new_infection_c, actual_new_infection_c,
                            calculated_prob_c, failed_count_c, routes[1],
                            t + 1, susceptible_group, sft_report_file,
                            susceptible_population_c, group_file)

                # make sure the seed group has no contagion to itself
                message_template = "{0}: (route {1}) contagion pool for seed group is {2}, expected 0 contagion, " \
                                   "test is {3}.\n"
                for contagion_seed, route in [(contagion_seed_e, routes[0]),
                                              (contagion_seed_c, routes[1])]:
                    contagion_sum = contagion_seed.values.sum()
                    if contagion_sum:
                        result_2 = success = False
                        sft_report_file.write(
                            message_template.format("BAD", route,
                                                    contagion_sum, "failed"))
                    else:
                        sft_report_file.write(
                            message_template.format("GOOD", route,
                                                    contagion_sum, "passed"))

                message_template = "{0}: (route {1}) binomial test for {2} failed {3} times within {4} total " \
                                   "timesteps, which is {5}% fail rate, test is {6}. Please see " \
                                   "'DEBUG_binomial_test_{7}.txt' for details.\n"
                for failed_count, new_infection_sus, route in [
                    (failed_count_e, new_infection_sus_e, routes[0]),
                    (failed_count_c, new_infection_sus_c, routes[1])
                ]:
                    if failed_count / duration > 5e-2:
                        result_3 = success = False
                        sft_report_file.write(
                            message_template.format(
                                "BAD", route, new_infection_sus.columns.values,
                                failed_count, duration,
                                (failed_count / duration) * 100, "failed",
                                susceptible_group))
                    else:
                        sft_report_file.write(
                            message_template.format(
                                "GOOD", route,
                                new_infection_sus.columns.values, failed_count,
                                duration, (failed_count / duration) * 100,
                                "passed", susceptible_group))

                # check the total new infection
                # plot actual and expected values for contagion and new infeciton for each route and each group
                message = "{0}: for route {1} and group {2}, the total new infection is {3}, expected {4}.\n"
                for contagion_list, new_infection_sus, expected_new_infection_list, route in \
                        [(contagion_list_e, new_infection_sus_e, expected_new_infection_list_e, routes[0]),
                         (contagion_list_c, new_infection_sus_c, expected_new_infection_list_c, routes[1])]:
                    if math.fabs(new_infection_sus.ix[1:, 0].sum() - sum(expected_new_infection_list)) > \
                            5e-2 * sum(expected_new_infection_list):
                        result_4 = success = False
                        sft_report_file.write(
                            message.format("BAD", route, susceptible_group,
                                           new_infection_sus.ix[1:, 0].sum(),
                                           sum(expected_new_infection_list)))
                    else:
                        sft_report_file.write(
                            message.format("GOOD", route, susceptible_group,
                                           new_infection_sus.ix[1:, 0].sum(),
                                           sum(expected_new_infection_list)))

                    sft.plot_data(
                        np.array(contagion_list)[:, 0],
                        np.array(contagion_list)[:, 1],
                        label1=property_report_name,
                        label2="calculated contagion",
                        title="contagion\nroute {0}, group {1}".format(
                            route, susceptible_group),
                        xlabel='day',
                        ylabel='contagion',
                        category="contagion_{0}_{1}".format(
                            susceptible_group, route),
                        line=True,
                        alpha=0.5,
                        overlap=True,
                        sort=False)

                    sft.plot_data(
                        new_infection_sus.ix[1:, 0].tolist(),
                        expected_new_infection_list,
                        label1=property_report_name,
                        label2="expected new infection",
                        title="new infections\nroute {0}, group {1}".format(
                            route, susceptible_group),
                        xlabel='day',
                        ylabel='new_infections',
                        category="new_infections_{0}_{1}".format(
                            susceptible_group, route),
                        line=False,
                        alpha=0.5,
                        overlap=True,
                        sort=False)

            sft_report_file.write("Test 2: result is: {}.\n".format(result_2))
            sft_report_file.write("Test 3: result is: {}.\n".format(result_3))
            sft_report_file.write("Test 4: result is: {}.\n".format(result_4))

            sft_report_file.write(
                "Test 5: testing {0} and {1} in {2} and data collected form {3} for every time step.\n"
                .format(
                    InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT,
                    InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT,
                    insetchart_name, property_report_name))
            result_5 = hint_support.compare_new_infections_channels(
                inset_channels[:2], property_df, duration, inset_chart_obj,
                sft_report_file, insetchart_name, property_report_name)
            if not result_5:
                success = False
            sft_report_file.write("Test 5: result is: {}.\n".format(result_5))

            sft_report_file.write(
                "Test 6: testing {0} and {1} in {2} and data collected form {3} for every time step.\n"
                .format(
                    InsetKeys.ChannelsKeys.Environmental_Contagion_Population,
                    InsetKeys.ChannelsKeys.Contact_Contagion_Population,
                    insetchart_name, property_report_name))
            result_6 = hint_support.compare_contagion_channels(
                inset_channels[2:], channels[3:5], property_df, duration,
                inset_chart_obj, sft_report_file, insetchart_name,
                property_report_name)
            if not result_6:
                success = False
            sft_report_file.write("Test 6: result is: {}.\n".format(result_6))

        sft_report_file.write(sft.format_success_msg(success))
    if debug:
        print(sft.format_success_msg(success))
    return success
예제 #19
0
def create_report_file(report_data_obj, report_name, debug):
    with open(report_name, "w") as outfile:
        success = True
        timestep = Outbreak_Start_Day
        tb_effects = calc_tb_effect(debug)
        tb_effect_baseline = float(
            tb_effects[0]
        )  # use the number of new infection from the 1st outbreak as a baseline
        new_infection_baseline = report_data_obj[
            KEY_NEW_INFECTIONS_GROUP[1]][timestep]
        statistical_population = report_data_obj[
            KEY_STATISTICAL_POPULATION_GROUP[1]][timestep]  # no any death
        new_infections = []
        expected_new_infections = []
        new_infections.append(new_infection_baseline)
        expected_new_infections.append(new_infection_baseline)
        actual_tb_effects = []
        actual_tb_effects.append(tb_effect_baseline)

        for i in range(1,
                       len(Interventions)):  # no need to test the 1st outbreak
            timestep += Timesteps_Between_Repetitions
            new_infection = report_data_obj[
                KEY_NEW_INFECTIONS_GROUP[1]][timestep]
            tb_effect = tb_effects[i]
            # because expected_new_infection / (1.0 - tb_effect) = new_infection_baseline / (1.0- tb_effect_baseline), so
            expected_new_infection = (1.0 -
                                      tb_effect) * new_infection_baseline / (
                                          1.0 - tb_effect_baseline)
            tolerance = 0.0 if expected_new_infection == 0.0 else 2e-2 * statistical_population
            actual_tb_effect = 1.0 - (new_infection *
                                      (1.0 - tb_effect_baseline) /
                                      new_infection_baseline)
            result = f"At time step: {timestep}, outbreak: {Interventions[i]}," \
                     f" {new_infection} reported new infections, expected {expected_new_infection}" \
                     f" with tolerance {tolerance}\n"
            if math.fabs(new_infection - expected_new_infection) > tolerance:
                success = False
                outfile.write(f"BAD:  {result}")
            else:
                outfile.write(f"GOOD: {result}")
            outfile.write(
                "\tactual TransmissionBlocking effect is {0}, expected {1}.\n".
                format(actual_tb_effect, tb_effect))
            new_infections.append(new_infection)
            expected_new_infections.append(expected_new_infection)
            actual_tb_effects.append(actual_tb_effect)
        sft.plot_data(new_infections,
                      expected_new_infections,
                      label1="Actual",
                      label2="Expected",
                      xlabel="outbreak",
                      ylabel="new infection",
                      title="Actual new infection vs. expected new infection",
                      category='New_infections',
                      show=True)
        if debug:
            with open("New_infections.txt", "w") as file:
                for i in range(len(new_infections)):
                    file.write("{0}, {1}.\n".format(
                        new_infections[i], expected_new_infections[i]))
            with open("Effects.txt", "w") as file:
                for i in range(len(actual_tb_effects)):
                    file.write("{0}, {1}.\n".format(actual_tb_effects[i],
                                                    tb_effects[i]))

        outfile.write(sft.format_success_msg(success))
        if debug:
            print("SUMMARY: Success={0}\n".format(success))
        return success
예제 #20
0
def create_report_file(param_obj, property_df, property_obj, inset_chart_obj,
                       insetchart_name, property_report_name, report_name,
                       debug):
    with open(report_name, "w") as outfile:
        config_name = param_obj[ConfigKeys.Config_Name]
        decay_rate = param_obj[ConfigKeys.Node_Contagion_Decay_Rate]
        outfile.write("Config_name = {}\n".format(config_name))
        outfile.write("{0} = {1} {2} = {3}\n".format(
            ConfigKeys.Node_Contagion_Decay_Rate, decay_rate,
            ConfigKeys.Run_Number, param_obj[ConfigKeys.Run_Number]))

        success = True

        outfile.write(
            "Testing: Testing contagion and decay in each groups for every time step:\n"
        )
        duration = param_obj[ConfigKeys.Simulation_Duration]
        transmission_matrix_e = property_obj[
            DemographicsKeys.PropertyKeys.TransmissionMatrix][routes[0]]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        groups = property_obj[DemographicsKeys.PropertyKeys.Values]
        contagion = []
        for group in groups:
            outfile.write("  Testing group: {}.\n".format(group))
            contagion_list_e = []
            # get list of column names that contains the group that we are testing
            cols = [c for c in property_df.columns if group in c]
            # get the list of the other group
            other_group = [x for x in groups if x is not group][0]
            # get all the column names that contains the other group
            cols_others = [c for c in property_df.columns if group not in c]

            # test data for test group
            infected = property_df[[c for c in cols if channels[0] in c]]
            contagion_e = property_df[[c for c in cols if channels[3] in c]]
            population = property_df[[c for c in cols if channels[5] in c]]

            # test data for the other group
            infected_other = property_df[[
                c for c in cols_others if channels[0] in c
            ]]
            # population_other = property_df[[c for c in cols_others if channels[5] in c]]

            pre_contagion = 0
            for t in range(duration - 1):
                if t == 0:
                    contagion_list_e.append([contagion_e.iloc[t][0], 0])
                    if contagion_e.iloc[t][0]:
                        success = False
                        outfile.write(
                            "    BAD: at time step {0}, for group {1} route {2}, the contagion is {3}, "
                            "expected {4}.\n".format(t, group, routes[0],
                                                     contagion_e.iloc[t][0],
                                                     0))

                infectivity = base_infectivity * infected.iloc[t][
                    0] / population.iloc[t][0]
                infectivity_other = base_infectivity * infected_other.iloc[t][
                    0] / population.iloc[t][0]

                # calculate contagion for environmental group
                new_contagion = infectivity * transmission_matrix_e[
                    groups.index(group)][groups.index(
                        group)] + infectivity_other * transmission_matrix_e[
                            groups.index(other_group)][groups.index(group)]

                current_contagion = pre_contagion * (
                    1 - decay_rate) + new_contagion

                # for next time step
                pre_contagion = current_contagion

                # get contagion from property report
                actual_contagion_e = contagion_e.iloc[t + 1][0]

                contagion_list_e.append(
                    [actual_contagion_e, current_contagion])

                if math.fabs(current_contagion -
                             actual_contagion_e) > 5e-2 * current_contagion:
                    success = False
                    outfile.write(
                        "    BAD: at time step {0}, for group {1} route {2}, the contagion is {3}, "
                        "expected {4}.\n".format(t + 1, group, routes[0],
                                                 actual_contagion_e,
                                                 current_contagion))

            contagion.append(contagion_list_e)
            # plot actual and expected values for contagion
            sft.plot_data(np.array(contagion_list_e)[:, 0],
                          np.array(contagion_list_e)[:, 1],
                          label1=property_report_name,
                          label2="calculated contagion",
                          title="contagion for group {0}\n route {1}".format(
                              group, routes[0]),
                          xlabel='day',
                          ylabel='contagion',
                          category="contagion_{0}_{1}".format(
                              group, routes[0]),
                          line=True,
                          alpha=0.5,
                          overlap=True)

        outfile.write(
            "Checking if contagion data from insetchart matches sum of group contagion from property report"
            " for every time step:\n")
        total_contagion_list = []
        for t in range(duration - 1):
            total_contagion = 0
            for contagion_list_e in contagion:
                total_contagion += contagion_list_e[t][0]
            total_contagion_list.append(total_contagion)
            insetchart_contagion = inset_chart_obj[
                InsetKeys.ChannelsKeys.Environmental_Contagion_Population][t]
            if math.fabs(total_contagion -
                         insetchart_contagion) > 5e-2 * total_contagion:
                success = False
                outfile.write(
                    "    BAD: at time step {0}, for route {1}, the total contagion from {2} is {3}, "
                    "expected {4}(sum of group contagion in {5}).\n".format(
                        t, routes[0], insetchart_name, insetchart_contagion,
                        total_contagion, property_report_name))
        sft.plot_data(
            inset_chart_obj[
                InsetKeys.ChannelsKeys.Environmental_Contagion_Population],
            total_contagion_list,
            label1=insetchart_name,
            label2="sum calculated from {}".format(property_report_name),
            title=InsetKeys.ChannelsKeys.Environmental_Contagion_Population,
            xlabel='day',
            ylabel='contagion',
            category=InsetKeys.ChannelsKeys.Environmental_Contagion_Population,
            line=True,
            alpha=0.5,
            overlap=True)

        outfile.write(sft.format_success_msg(success))
    if debug:
        print(sft.format_success_msg(success))
    return success
def create_report_file(param_obj, campaign_obj, stdout_df, property_df, property_obj, inset_chart_obj,
                       insetchart_name, property_report_name, report_name, debug):
    with open(report_name, "w") as sft_report_file :
        config_name = param_obj[ConfigKeys.Config_Name]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        sft_report_file.write("Config_name = {}\n".format(config_name))
        sft_report_file.write("{0} = {1} {2} = {3}\n".format(
            ConfigKeys.Base_Infectivity, base_infectivity,
            ConfigKeys.Run_Number, param_obj[ConfigKeys.Run_Number]))

        success = True

        sft_report_file.write("Test 1: checking test conditions/setup in config.json and campaign.json:\n")
        if int(param_obj[ConfigKeys.Enable_Heterogeneous_Intranode_Transmission]) != 1:
            success = False
            sft_report_file.write("BAD: HINT is not enabled, please check the test.\n")
        else:
            if float(param_obj[ConfigKeys.Node_Contagion_Decay_Rate]) != 1:
                success = False
                sft_report_file.write("BAD: Expect Environmental contagion decay 100%, but Node_Contagion_Decay_Rate = {}"
                              ", please check the test.\n".format(param_obj[ConfigKeys.Node_Contagion_Decay_Rate]))

            if not all(x == 0 for x in campaign_obj[CampaignKeys.Start_Day]):
                success = False
                sft_report_file.write("BAD: All intervention should start at day 0, please check campaign.json.\n")

            if not all(x == 0.05 for x in campaign_obj[CampaignKeys.Demographic_Coverage]):
                success = False
                sft_report_file.write("BAD: {} should be 0.05, please check campaign.json."
                              "\n".format(CampaignKeys.Demographic_Coverage))

            expected_property_restrictions = [[]]
            if campaign_obj[CampaignKeys.Property_Restrictions] != expected_property_restrictions:
                success = False
                sft_report_file.write(
                    "BAD: {0} should be be empty list(target everyone), got {1} in campaign.json, please check "
                    "campaign.json.\n".format(
                        CampaignKeys.Property_Restrictions,
                        campaign_obj[CampaignKeys.Property_Restrictions]))
        sft_report_file.write("Test 1: campaign and config met preconditions: {}.\n".format(success))

        if success:
            sft_report_file.write("Test 2: Testing contagion and probability with calculated values for every time step:\n")
            sft_report_file.write("Test 3: Testing New Infection channel from property report based on transmission matrix "
                          "for every timestep:\n")
            sft_report_file.write("Test 4: testing total new infection by routes match the total expected new infections"
                          "for each group.\n".format(
                InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT,
                InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT, insetchart_name, property_report_name))
            sft_report_file.write("Test 2, 3 and 4 and running at the same time:\n")
            result_2 = result_3 = result_4 = True
            stat_pop = stdout_df[Stdout.stat_pop]
            duration = param_obj[ConfigKeys.Simulation_Duration]
            transmission_matrix_e = property_obj[DemographicsKeys.PropertyKeys.TransmissionMatrix][routes[0]]
            transmission_matrix_c = property_obj[DemographicsKeys.PropertyKeys.TransmissionMatrix][routes[1]]
            # get all the column names that contains the seed group
            property_values = property_obj[DemographicsKeys.PropertyKeys.Values]
            for group in property_values:
                # get all the column names that contains the group
                cols = [c for c in property_df.columns if group in c]

                # test data for susceptible group
                infected = property_df[[c for c in cols if channels[0] in c]]
                new_infection_e = property_df[[c for c in cols if channels[1] in c]]
                new_infection_c = property_df[[c for c in cols if channels[2] in c]]
                contagion_e = property_df[[c for c in cols if channels[3] in c]]
                contagion_c = property_df[[c for c in cols if channels[4] in c]]
                population = property_df[[c for c in cols if channels[5] in c]]

                expected_new_infection_list_e = []
                expected_new_infection_list_c = []
                contagion_list_e = [[contagion_e.iloc[0][0], 0]]
                contagion_list_c = [[contagion_e.iloc[0][0], 0]]

                failed_count_e = 0
                failed_count_c = 0
                with open("DEBUG_binomial_test_{}.txt".format(group), 'w') as group_file:
                    for t in range(duration - 1):
                        infectivity_seed = base_infectivity * infected.iloc[t][0]
                        # calculate contagion of susceptible group
                        # environmental contagion decay 100% at each time step so it works as contact contagion
                        # "contact" route will be normalized by total population
                        # "environmental" route will be normalized by group population
                        calculated_contagion_e = infectivity_seed * transmission_matrix_e[property_values.index(group)][
                            property_values.index(group)] / population.iloc[t][0]
                        calculated_contagion_c = infectivity_seed * transmission_matrix_c[property_values.index(group)][
                            property_values.index(group)] / stat_pop[t]

                        # get contagion of susceptible group from property report
                        actual_contagion_e = contagion_e.iloc[t + 1][0]
                        actual_contagion_c = contagion_c.iloc[t + 1][0]

                        contagion_list_e.append([actual_contagion_e, calculated_contagion_e])
                        contagion_list_c.append([actual_contagion_c, calculated_contagion_c])

                        if math.fabs(calculated_contagion_e - actual_contagion_e) > 5e-2 * calculated_contagion_e:
                            result_2 = success = False
                            sft_report_file.write("    BAD: at time step {0}, for group {1} route {2}, the contagion is {3}, "
                                          "expected {4}.\n".format(t + 1, group, routes[0], actual_contagion_e,
                                                                   calculated_contagion_e
                            ))

                        if math.fabs(calculated_contagion_c - actual_contagion_c) > 5e-2 * calculated_contagion_c:
                            result_2 = success = False
                            sft_report_file.write("    BAD: at time step {0}, for group {1} route {2}, the contagion is {3}, "
                                          "expected {4}.\n".format(t + 1, group, routes[1], actual_contagion_c,
                                                                   calculated_contagion_c
                            ))

                        # calculate infection probability based on contagion
                        calculated_prob_e = 1.0 - math.exp(-1 * calculated_contagion_e *
                                                           param_obj[ConfigKeys.Simulation_Timestep])
                        calculated_prob_c = 1.0 - math.exp(-1 * calculated_contagion_c *
                                                           param_obj[ConfigKeys.Simulation_Timestep])

                        # calculate expected new infection for susceptible group
                        susceptible_population_c = population.iloc[t][0] - infected.iloc[t][0]
                        expected_new_infection_c = susceptible_population_c * calculated_prob_c

                        # Superinfection is not supported, so individuals may not be infected from both the environmental and the contact route.
                        susceptible_population_e = susceptible_population_c - new_infection_c.iloc[t + 1][0]
                        expected_new_infection_e = susceptible_population_e * calculated_prob_e

                        expected_new_infection_list_e.append(expected_new_infection_e)
                        expected_new_infection_list_c.append(expected_new_infection_c)

                        actual_new_infection_e = new_infection_e.iloc[t + 1][0]
                        actual_new_infection_c = new_infection_c.iloc[t + 1][0]

                        # run the same test for both routes
                        failed_count_e = hint_support.test_new_infections(
                            expected_new_infection_e, actual_new_infection_e, calculated_prob_e, failed_count_e,
                            routes[0], t + 1, group, sft_report_file, susceptible_population_e, group_file)

                        failed_count_c = hint_support.test_new_infections(
                            expected_new_infection_c, actual_new_infection_c, calculated_prob_c, failed_count_c,
                            routes[1], t + 1, group, sft_report_file, susceptible_population_c, group_file)

                message_template = "{0}: (route {1}) binomial test for {2} failed {3} times within {4} total " \
                                   "timesteps, which is {5}% fail rate, test is {6}. Please see " \
                                   "'DEBUG_binomial_test_{7}.txt' for details.\n"
                for failed_count, new_infection_sus, route in [(failed_count_e, new_infection_e, routes[0]),
                                            (failed_count_c, new_infection_c, routes[1])]:
                    if failed_count / duration > 5e-2:
                        result_3 = success = False
                        sft_report_file.write(message_template.format("BAD", route, new_infection_sus.columns.values,
                                                              failed_count, duration, (failed_count / duration) * 100,
                                                              "failed", group))
                    else:
                        sft_report_file.write(message_template.format("GOOD", route, new_infection_sus.columns.values,
                                                              failed_count, duration, (failed_count / duration) * 100,
                                                              "passed", group))

                # check the total new infection
                # plot actual and expected values for contagion and new infeciton for each routes and each group
                message = "{0}: for route {1} and group {2}, the total new infection is {3}, expected {4}.\n"
                for contagion_list, new_infection_sus, expected_new_infection_list, route in \
                        [(contagion_list_e, new_infection_e, expected_new_infection_list_e, routes[0]),
                         (contagion_list_c, new_infection_c, expected_new_infection_list_c, routes[1])]:
                    tolerance = 0
                    total_expected_new_infections = sum(expected_new_infection_list)
                    total_new_infections = new_infection_sus.ix[1:, 0].sum()
                    if total_expected_new_infections > 1000:
                        tolerance = 5e-2
                    elif total_expected_new_infections > 500:
                        tolerance = 1e-1
                    elif total_expected_new_infections > 50:
                        tolerance = 2e-1
                    else:
                        tolerance = -1
                        sft_report_file.write("WARNING: the new infection size for route {0} and group {1} is too "
                                              "small, skip it in this test. Expected {2} total new infectuins " 
                                              "got {3}.\n".format(route, group,
                                                                  total_expected_new_infections,
                                                                  total_new_infections
                                                                  ))
                    if tolerance > 0:
                        if math.fabs(total_new_infections - total_expected_new_infections) > \
                                tolerance * total_expected_new_infections:
                            result_4 = success = False
                            sft_report_file.write(message.format("BAD", route, group, total_new_infections,
                                                                 total_expected_new_infections))
                        else:
                            sft_report_file.write(message.format("GOOD", route, group, total_new_infections,
                                                                 total_expected_new_infections))

                    sft.plot_data(np.array(contagion_list)[:, 0], np.array(contagion_list)[:, 1],
                                      label1=property_report_name, label2="calculated contagion",
                                      title="contagion\nroute {0}, group {1}".format(route, group),
                                      xlabel='day', ylabel='contagion', category="contagion_{0}_{1}"
                                                                                 "".format(group, route),
                                      line=True, alpha=0.5, overlap=True, sort=False)
                    sft.plot_data(new_infection_sus.ix[1:, 0].tolist(), expected_new_infection_list,
                                      label1=property_report_name,
                                      label2="expected new infection",
                                      title="new infections\nroute {0}, group {1}".format(route, group),
                                      xlabel='day', ylabel='new_infections',
                                      category="new_infections_{0}_{1}".format(group, route),
                                      line=False, alpha=0.5, overlap=True, sort=False)

            sft_report_file.write("Test 2: result is: {}.\n".format(result_2))
            sft_report_file.write("Test 3: result is: {}.\n".format(result_3))
            sft_report_file.write("Test 4: result is: {}.\n".format(result_4))

            sft_report_file.write("Test 5: testing {0} and {1} in {2} and data collected form {3} for every time step.\n".format(
                InsetKeys.ChannelsKeys.New_Infections_By_Route_ENVIRONMENT,
                InsetKeys.ChannelsKeys.New_Infections_By_Route_CONTACT, insetchart_name, property_report_name))
            result_5 = hint_support.compare_new_infections_channels(inset_channels[:2], property_df, duration,
                                                                    inset_chart_obj, sft_report_file, insetchart_name,
                                                                    property_report_name)
            if not result_5:
                success = False
            sft_report_file.write("Test 5: result is: {}.\n".format(result_5))

            sft_report_file.write("Test 6: testing {0} and {1} in {2} and data collected form {3} for every time step.\n".format(
                InsetKeys.ChannelsKeys.Environmental_Contagion_Population,
                InsetKeys.ChannelsKeys.Contact_Contagion_Population, insetchart_name, property_report_name))
            result_6 = hint_support.compare_contagion_channels(inset_channels[2:], channels[3:5], property_df, duration,
                                                               inset_chart_obj, sft_report_file, insetchart_name,
                                                               property_report_name)
            if not result_6:
                success = False
            sft_report_file.write("Test 6: result is: {}.\n".format(result_6))

        sft_report_file.write(sft.format_success_msg(success))
    if debug:
        print(sft.format_success_msg(success))
    return success
def create_report_file(param_obj, stdout_df, report_name, debug):
    with open(report_name, "w") as outfile:
        for name, param in param_obj.items():
            outfile.write("{0} = {1}\n".format(name, param))
        success = True
        start_day = param_obj[ConfigKeys.Environmental_Peak_Start]
        ramp_up = param_obj[ConfigKeys.Environmental_Ramp_Up_Duration]
        ramp_down = param_obj[ConfigKeys.Environmental_Ramp_Down_Duration]
        cut_off = param_obj[ConfigKeys.Environmental_Cutoff_Days]
        duration = param_obj[ConfigKeys.Simulation_Duration]

        peak_duration = sft.DAYS_IN_YEAR - ramp_up - ramp_down - cut_off
        # adjust peak start time to day in year
        peak_starttime = start_day % sft.DAYS_IN_YEAR
        peak_endtime = peak_starttime + peak_duration
        cutoff_starttime = peak_starttime + peak_duration + ramp_down
        cutoff_endtime = peak_starttime + peak_duration + ramp_down + cut_off

        amp = []
        expected_amp = []
        # adjust the times so that the ramp up starts at time 0, which means the cut off ends at time 0 too.
        adjust_time = peak_starttime - ramp_up
        peak_starttime -= adjust_time
        peak_endtime -= adjust_time
        cutoff_starttime -= adjust_time
        cutoff_endtime -= adjust_time
        cutoff_endtime %= sft.DAYS_IN_YEAR

        for t in range(1, duration):
            amplification = stdout_df[Stdout.amplification].iloc[t]
            day_in_year = stdout_df[Stdout.day_of_year].iloc[t]
            if day_in_year != t % sft.DAYS_IN_YEAR:
                success = False
                outfile.write("BAD: at time step {0}, day_in_year is {1}, it should be {2}.\n".format(
                    t, day_in_year, t % sft.DAYS_IN_YEAR))
                day_in_year = t % sft.DAYS_IN_YEAR
            day_in_year -= adjust_time
            day_in_year %= sft.DAYS_IN_YEAR
            # Environment Ramp Up
            if cutoff_endtime < day_in_year < peak_starttime:
                expected_amplification = day_in_year / ramp_up
            # Environment peak
            elif peak_starttime <= day_in_year <= peak_endtime:
                expected_amplification = 1
            # Environment Ramp Down
            elif peak_endtime < day_in_year < cutoff_starttime:
                expected_amplification = (cutoff_starttime - day_in_year) / ramp_down
            # Environment cutoff
            else:
                expected_amplification = 0
            if not math.fabs(amplification - expected_amplification) <= 5e-2 * expected_amplification:
                success = False
                outfile.write(
                    "BAD: at time {0}, day of year = {1}, the environmental amplification is {2}, expected {3}.\n".format(
                        t, t % sft.DAYS_IN_YEAR, amplification, expected_amplification))
            amp.append(amplification)
            expected_amp.append(expected_amplification)
        sft.plot_data(amp, expected_amp,
                          label1="Actual amplification",
                          label2="Expected amplification",
                          title="Seasonality", xlabel="Day",
                          ylabel="Environmental amplification",
                          category='Environmental_amplification', overlap=True, alpha=0.5)
        outfile.write(sft.format_success_msg(success))
        if debug:
            print(sft.format_success_msg(success))
        return success
def create_report_file(param_obj, output_df, report_df, report_name, debug):
    total_timesteps = int(param_obj[KEY_TOTAL_TIMESTEPS])
    simulation_timestep = float(param_obj[KEY_SIMULATION_TIMESTEP])
    base_infectivity = float(param_obj[KEY_BASE_INFECTIVITY])
    amplitude = float(param_obj[KEY_AMPLITUDE])
    phase = float(param_obj[KEY_PHASE])
    infected = output_df[KEY_INFECTED]
    infectiousness = output_df[KEY_INFECTIOUSNESS]
    statpop = output_df[KEY_STAT_POP]
    new_infections = report_df[KEY_NEW_INFECTIONS]
    if debug:
        sft.plot_data(
            new_infections,
            label1="new infections",
            label2="NA",
            title="Phase: {0} day, amplitude: {1}, base_infectivity: {2}".
            format(phase, amplitude, base_infectivity),
            xlabel="Time_Step_{0}_Days".format(simulation_timestep),
            ylabel=None,
            category='New_infections',
            show=True,
            line=True)
    with open(report_name, "w") as outfile:
        expected_infectiousness = []
        for index in range(len(infected)):
            infected_pop = int(infected[index])
            expected_infectiousness.append(
                calculate_infectiousness(infected_pop, index,
                                         simulation_timestep, phase,
                                         base_infectivity, amplitude, debug))
        success = True
        actual_infectiousness_all = []
        calc_infectiousness_all = []
        for index in range(len(infectiousness)):
            timestep = index * simulation_timestep
            actual_infectiousness = float(infectiousness[index])
            calc_infectiousness = expected_infectiousness[index] / float(
                statpop[index])
            actual_infectiousness_all.append(actual_infectiousness)
            calc_infectiousness_all.append(calc_infectiousness)
            tolerance = 0 if calc_infectiousness == 0 else 5e-2 * calc_infectiousness
            if math.fabs(actual_infectiousness -
                         calc_infectiousness) > tolerance:
                success = False
                outfile.write(
                    "BAD: actual infectiousness at time step {0} is {1}, expected {2}.\n"
                    .format(timestep, actual_infectiousness,
                            calc_infectiousness))
        outfile.write(sft.format_success_msg(success))
    sft.plot_data(
        actual_infectiousness_all,
        calc_infectiousness_all,
        label1="actual infectiousness",
        label2="calc infectiousness",
        title="Phase: {0} day, amplitude: {1}, base_infectivity: {2}".format(
            phase, amplitude, base_infectivity),
        xlabel="Time_Step_{0}_Days".format(simulation_timestep),
        ylabel="Infectiousness",
        category='Infectiousness',
        show=True,
        line=True)
    return success
def create_report_file(param_obj, campaign_obj, stdout_df, property_df, property_list, report_name, debug):
    with open(report_name, "w") as outfile:
        config_name = param_obj[ConfigKeys.Config_Name]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        outfile.write("Config_name = {}\n".format(config_name))
        outfile.write("{0} = {1} {2} = {3}\n".format(
            ConfigKeys.Base_Infectivity, base_infectivity,
            ConfigKeys.Run_Number, param_obj[ConfigKeys.Run_Number]))

        success = True

        outfile.write("Test 1: checking test conditions/setup in config.json and campaign.json:\n")
        if int(param_obj[ConfigKeys.Enable_Heterogeneous_Intranode_Transmission]) != 1:
            success = False
            outfile.write("BAD: HINT is not enabled, please check the test.\n")
        else:
            if not all(x == 0 for x in campaign_obj[CampaignKeys.Start_Day]):
                success = False
                outfile.write("BAD: All intervention should start at day 0, please check campaign.json.\n")

            if not all(x == 1 for x in campaign_obj[CampaignKeys.Demographic_Coverage]):
                success = False
                outfile.write("BAD: {} should be 1, please check campaign.json.\n".format(CampaignKeys.Demographic_Coverage))

            expected_property_restrictions = []
            seed_groups = []
            susceptible_groups = []
            for property_obj in property_list:
                property_values = property_obj[DemographicsKeys.PropertyKeys.Values]
                seed_groups.append(property_values[0])
                susceptible_groups.append(property_values[1])
                expected_property_restrictions.append(["{0}:{1}".format(
                    property_obj[DemographicsKeys.PropertyKeys.Property], property_values[0])])
            if campaign_obj[CampaignKeys.Property_Restrictions] != expected_property_restrictions:
                success = False
                outfile.write(
                    "BAD: {0} should be {1}, got {2} in campaign.json, please check campaign.json.\n".format(
                        CampaignKeys.Property_Restrictions, expected_property_restrictions,
                        campaign_obj[CampaignKeys.Property_Restrictions]))

        outfile.write("Test 1: campaign and config met preconditions: {}.\n".format(success))

        if success:
            outfile.write("Test 2: Testing contagion and probability with calculated values for every time step:\n")
            outfile.write("Test 3: Testing New Infection channel from property report based on transmission matrix:\n")
            outfile.write("Test 2 and 3 and running at the same time:\n")
            result_2 = result_3 = True
            stat_pop = stdout_df[hint_support.Stdout.stat_pop]
            # infected = stdout_df[Stdout.infected]
            duration = param_obj[ConfigKeys.Simulation_Duration]

            contagion_list = []
            prob_list = []
            seed_cols = []
            for seed_group in seed_groups:
                # get all the column names that contains the seed group
                seed_cols += [c for c in property_df.columns if seed_group in c]
            # remove duplicates
            seed_cols = list(set(seed_cols))
            # get all the column names that only contains the susceptible group, which should be property_df.columns - seed_cols
            susceptible_only_cols = [c for c in property_df.columns if c not in seed_cols]

            susceptible_cols = []
            for susceptible_group in susceptible_groups:
                susceptible_cols += [c for c in property_df.columns if susceptible_group in c]
            susceptible_cols = list(set(susceptible_cols))
            # get all the column names that only contains the seed group, which should be property_df.columns - susceptible_cols
            seed_only_cols = [c for c in property_df.columns if c not in susceptible_cols]

            # test data for seed group
            infected_seed = property_df[[c for c in seed_only_cols if hint_support.channels[0] in c]]
            # population_seed = property_df[[c for c in seed_cols if channels[2] in c]]

            # test data for susceptible group
            infected_sus = property_df[[c for c in susceptible_only_cols if hint_support.channels[0] in c]]
            new_infection_sus = property_df[[c for c in susceptible_only_cols if hint_support.channels[1] in c]]
            population_sus = property_df[[c for c in susceptible_only_cols if hint_support.channels[2] in c]]

            expected_new_infection_list = []
            failed_count = 0
            for t in range(duration):
                calculated_contagion = 0
                for col in infected_seed:
                    # calculate infectivity of seed group
                    # nomalized with total population
                    infectivity_seed = base_infectivity * infected_seed[col].iloc[t] / stat_pop[t]
                    infectivity_mod = 1
                    for i in range(len(seed_groups)):
                        seed_group = seed_groups[i]
                        susceptible_group = susceptible_groups[i]
                        if seed_group in col:
                            for property_obj in property_list:
                                property_values = property_obj[DemographicsKeys.PropertyKeys.Values]
                                if seed_group in property_values:
                                    transmission_matrix = property_obj[DemographicsKeys.PropertyKeys.Matrix]
                                    infectivity_mod *= transmission_matrix[property_values.index(seed_group)][
                                                       property_values.index(susceptible_group)]

                    # calculate contagion of susceptible group
                    calculated_contagion += infectivity_seed * infectivity_mod

                # round the calculated value to 6 Decimal numbers
                calculated_contagion = round(calculated_contagion, 6)

                # get contagion of susceptible group from stdout
                # group_id is the last element in all group_ids
                group_id = -1
                for property_obj in property_list:
                    group_id += len(property_obj[DemographicsKeys.PropertyKeys.Values])
                actual_contagion = stdout_df[(stdout_df[ConfigKeys.Simulation_Timestep] == t) &
                                             (stdout_df[hint_support.Stdout.group_id] == group_id)][hint_support.Stdout.contagion].values[0]
                contagion_list.append([actual_contagion, calculated_contagion])
                if math.fabs(calculated_contagion - actual_contagion) > 5e-2 * calculated_contagion:
                    result_2 = success = False
                    outfile.write("    BAD: at time step {0}, for group {1} id {2}, the total contagion is {3}, "
                                  "expected {4}.\n".format(t, susceptible_group, group_id, actual_contagion,
                                                           calculated_contagion
                    ))

                # calculate infection probability based on contagion
                calculated_prob = 1.0 - math.exp(-1 * calculated_contagion * param_obj[ConfigKeys.Simulation_Timestep])
                # round the calculated value to 6 Decimal numbers
                calculated_prob = round(calculated_prob, 6)
                # get infection probability of susceptible group from stdout_df
                actual_prob = stdout_df[(stdout_df[ConfigKeys.Simulation_Timestep] == t) &
                                             (stdout_df[hint_support.Stdout.group_id] == group_id)][hint_support.Stdout.prob].values[0]
                prob_list.append([actual_prob, calculated_prob])
                if math.fabs(calculated_prob - actual_prob) > 5e-2 * calculated_prob:
                    result_2 = success = False
                    outfile.write("    BAD: at time step {0}, for group {1} id {2}, the infected probability is "
                                  "{3}, expected {4}.\n".format( t, susceptible_group, group_id, actual_prob,
                                                                 calculated_prob
                    ))

                # calculate expected new infection for susceptible group
                susceptible_population = population_sus.iloc[t][0] - infected_sus.iloc[t][0]
                expected_new_infection = susceptible_population * calculated_prob
                expected_new_infection_list.append(expected_new_infection)
                actual_new_infection = new_infection_sus.iloc[t][0]
                with open("DEBUG_binomial_test_{}.txt".format(susceptible_group), 'w') as file:
                    if expected_new_infection < 5 or susceptible_population * (1 - calculated_prob) < 5:
                        binom_pmf = stats.binom.pmf(k=actual_new_infection, n=susceptible_population, p=calculated_prob)
                        if binom_pmf < 1e-3:
                            failed_count += 1
                            outfile.write("WARNING: at timestep {0}, new infections for {1} group is {2}, expected "
                                          " = {3}, calculated binomial pmf is {4}.\n"
                                          "".format(t, susceptible_group, actual_new_infection,
                                                    expected_new_infection, binom_pmf))

                    elif not sft.test_binomial_99ci(num_success=actual_new_infection, num_trials=susceptible_population,
                                               prob=calculated_prob, report_file=file,
                                               category="new infections for {0} at time {1}".format(susceptible_group, t)):
                        failed_count += 1
                        standard_deviation = math.sqrt(
                            calculated_prob * (1 - calculated_prob) * susceptible_population)
                        # 99% confidence interval
                        lower_bound = expected_new_infection - 3 * standard_deviation
                        upper_bound = expected_new_infection + 3 * standard_deviation
                        outfile.write("WARNING: at timestep {0}, new infections for {1} group is {2}, expected "
                                      "within 99% binomial interval ({3}, {4}) with mean = {5}\n".format(t, susceptible_group,
                                                                                      actual_new_infection,
                                                                                      lower_bound, upper_bound,
                                                                                      expected_new_infection))

            # make sure non-susceptible groups has no new infections after outbreak
            new_infection_non_susceptible = property_df[
                [c for c in seed_cols if hint_support.channels[1] in c]]
            message_template = "{0}: total new infection after outbreak for {1} is {2}, expected 0.\n"
            for col in new_infection_non_susceptible:
                total_new_infection = new_infection_non_susceptible.ix[1:, col].sum()
                if total_new_infection != 0:
                    success = False
                    outfile.write(message_template.format("BAD", col, total_new_infection))
                else:
                    outfile.write(message_template.format("GOOD", col, total_new_infection))

            # plotting
            # get the group name for the susceptible only group
            group_name = susceptible_only_cols[0].replace(":"," ", 1).split()[-1]
            # ":" is not allowed in filename, replace it with "-" to avoid OSError
            group_name_modified = group_name.replace(":", "-")
            sft.plot_data(np.array(contagion_list)[:, 0], np.array(contagion_list)[:, 1], label1='contagion from logging', label2="calculated contagion",
                              title="{}\ncontagion".format(group_name), xlabel='day',ylabel='contagion',category="contagion_{}".format(group_name_modified),
                              line=True, alpha=0.5, overlap=True)
            sft.plot_data(np.array(prob_list)[:, 0], np.array(prob_list)[:, 1], label1='probability from logging', label2="calculated probability",
                              title="{}\nprobability".format(group_name), xlabel='day',ylabel='probability',category="probability_{}".format(group_name_modified),
                              line=True, alpha=0.5, overlap=True)

            sft.plot_data(new_infection_sus.ix[:, 0].tolist(), expected_new_infection_list,
                              label1='from property report',
                              label2="calculated data",
                              title="{}\nnew infections".format(group_name),
                              xlabel='day', ylabel='new_infections',
                              category="new_infections_{}".format(group_name_modified),
                              line=False, alpha=0.5, overlap=True, sort=False)

            message_template = "{0}: binomial test for {1} failed {2} times within {3} total timesteps, which is " \
                               "{4}% fail rate, test is {5}.\n"
            if failed_count / duration > 5e-2:
                result_3 = success = False
                outfile.write(message_template.format("BAD", new_infection_sus.columns.values, failed_count,
                                                      duration, (failed_count / duration) * 100, "failed"))
            else:
                outfile.write(message_template.format("GOOD", new_infection_sus.columns.values, failed_count,
                                                      duration, (failed_count / duration) * 100, "passed"))

            outfile.write("Test 2: result is: {}.\n".format(result_2))
            outfile.write("Test 3: result is: {}.\n".format(result_3))

        outfile.write(sft.format_success_msg(success))
    if debug:
        print(sft.format_success_msg(success))
    return success
def create_report_file(param_obj, property_df, property_obj, inset_chart_obj, insetchart_name, property_report_name,
                       report_name, debug):
    with open(report_name, "w") as outfile:
        config_name = param_obj[ConfigKeys.Config_Name]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        outfile.write("Config_name = {}\n".format(config_name))
        outfile.write("{0} = {1} {2} = {3}\n".format(
            ConfigKeys.Base_Infectivity, base_infectivity,
            ConfigKeys.Run_Number, param_obj[ConfigKeys.Run_Number]))

        success = True

        outfile.write("Testing contagion in each groups for every time step:\n")
        duration = param_obj[ConfigKeys.Simulation_Duration]
        transmission_matrix_c = property_obj[DemographicsKeys.PropertyKeys.TransmissionMatrix][routes[1]]
        groups = property_obj[DemographicsKeys.PropertyKeys.Values]
        contagion = []
        for group in groups:
            outfile.write("  Testing group: {}.\n".format(group))
            contagion_list_c = []
            # get list of column names that contains the group that we are testing
            cols = [c for c in property_df.columns if group in c]
            # get the list of the other group
            other_group = [x for x in groups if x is not group][0]
            # get all the column names that contains the other group
            cols_others = [c for c in property_df.columns if group not in c]

            # test data for test group
            infected = property_df[[c for c in cols if channels[0] in c]]
            contagion_c = property_df[[c for c in cols if channels[4] in c]]
            population = property_df[[c for c in cols if channels[5] in c]]

            # test data for the other group
            infected_other = property_df[[c for c in cols_others if channels[0] in c]]
            population_other = property_df[[c for c in cols_others if channels[5] in c]]

            for t in range(duration - 1):
                if t == 0:
                    contagion_list_c.append([contagion_c.iloc[t][0], 0])
                    if contagion_c.iloc[t][0]:
                        success = False
                        outfile.write("    BAD: at time step {0}, for group {1} route {2}, the contagion is {3}, "
                                      "expected {4}.\n".format(t, group, routes[1], contagion_c.iloc[t][0],
                                                               0
                                                               ))

                infectivity = base_infectivity * infected.iloc[t][0] / \
                              (population.iloc[t][0] + population_other.iloc[t][0])
                infectivity_other = base_infectivity * infected_other.iloc[t][0] / \
                                    (population.iloc[t][0] + population_other.iloc[t][0])

                # calculate contagion
                calculated_contagion = infectivity * transmission_matrix_c[groups.index(group)][
                    groups.index(group)] + infectivity_other * transmission_matrix_c[groups.index(other_group)][
                    groups.index(group)]

                # get contagion from property report
                actual_contagion_c = contagion_c.iloc[t + 1][0]

                contagion_list_c.append([actual_contagion_c, calculated_contagion])

                if math.fabs(calculated_contagion - actual_contagion_c) > 5e-2 * calculated_contagion:
                    success = False
                    outfile.write("    BAD: at time step {0}, for group {1} route {2}, the contagion is {3}, "
                                  "expected {4}.\n".format(t + 1, group, routes[1], actual_contagion_c,
                                                           calculated_contagion
                    ))


            contagion.append(contagion_list_c)
            # plot actual and expected values for contagion
            sft.plot_data(np.array(contagion_list_c)[:, 0], np.array(contagion_list_c)[:, 1],
                              label1=property_report_name, label2="calculated contagion",
                              title="contagion for group {0}\n route {1}".format(group, routes[1]),
                              xlabel='day',ylabel='contagion',category="contagion_{0}_{1}"
                                                                       "".format(group, routes[1]),
                              line=True, alpha=0.5, overlap=True)

        outfile.write("Checking if contagion data from insetchart matches sum of group contagion from property report"
                      " for every time step:\n")
        total_contagion_list = []
        for t in range(duration - 1):
            total_contagion = 0
            for contagion_list_c in contagion:
                total_contagion += contagion_list_c[t][0]
            total_contagion_list.append(total_contagion)
            insetchart_contagion = inset_chart_obj[InsetKeys.ChannelsKeys.Contact_Contagion_Population][t]
            if math.fabs(total_contagion - insetchart_contagion) > 5e-2 * total_contagion:
                success = False
                outfile.write("    BAD: at time step {0}, for route {1}, the total contagion from {2} is {3}, "
                              "expected {4}(sum of group contagion in {5}).\n".format(
                                    t, routes[1], insetchart_name, insetchart_contagion, total_contagion,
                                    property_report_name
                                                       ))
        sft.plot_data(inset_chart_obj[InsetKeys.ChannelsKeys.Contact_Contagion_Population],
                          total_contagion_list,
                          label1=insetchart_name, label2="sum calculated from {}".format(property_report_name),
                          title=InsetKeys.ChannelsKeys.Contact_Contagion_Population,
                          xlabel='day', ylabel='contagion', category=InsetKeys.ChannelsKeys.Contact_Contagion_Population,
                          line=True, alpha=0.5, overlap=True)


        outfile.write(sft.format_success_msg(success))
    if debug:
        print(sft.format_success_msg(success))
    return success
def create_report_file(report_data_obj, csv_df, report_name, debug):
    with open(report_name, "w") as outfile:
        success = True
        timestep = Outbreak_Start_Day
        effect_a = Prime_Acquire
        effect_t = Prime_Transmit
        effect_m = Prime_Mortality
        new_infections = []
        statistical_populations = []
        new_disease_deaths = []
        for x in range(Number_Repetitions):
            num_group = len(KEY_NEW_INFECTIONS_GROUP)
            for i in range(num_group):
                new_infection = report_data_obj[KEY_NEW_INFECTIONS_GROUP[i]][timestep]
                statistical_population = report_data_obj[KEY_STATISTICAL_POPULATION_GROUP[i]][timestep]
                # disease death in the last two groups happen 1 day later than the first two groups.
                pre_disease_death = len(csv_df[(csv_df['Time'] == int(timestep + i / 2 - 1)) &
                                           (csv_df['QualityOfCare'] == PROPERTY_GROUP[i]) &
                                           (csv_df['Event_Name'] == 'DiseaseDeaths')])
                disease_death = len(csv_df[(csv_df['Time'] == int(timestep + i / 2)) &
                                           (csv_df['QualityOfCare'] == PROPERTY_GROUP[i]) &
                                           (csv_df['Event_Name'] == 'DiseaseDeaths')])
                new_disease_death = disease_death - pre_disease_death
                new_infections.append(new_infection)
                statistical_populations.append(statistical_population)
                new_disease_deaths.append(new_disease_death)
            # test acquisition blocking
            new_infection_seed_test = new_infections[1 + x * num_group]
            statistical_population_seed_test = statistical_populations[1 + x * num_group]
            expected_new_infection_seed_test = statistical_population_seed_test * (1.0 - effect_a) * Outbreak_Demographic_Coverage
            tolerance_1 = 0.0 if expected_new_infection_seed_test == 0.0 else 2e-2 * statistical_population_seed_test
            if math.fabs(new_infection_seed_test - expected_new_infection_seed_test) > tolerance_1:
                success = False
                outfile.write("BAD: At time step {0}, {1} reported new infections in Group 2_Seed_Test, expected {2}.\n".format(
                    timestep, new_infection_seed_test, expected_new_infection_seed_test))
            # test transmission blocking
            new_infection_seed_control = new_infections[0 + x * num_group]
            new_infection_control = new_infections[2 + x * num_group]
            new_infection_test = new_infections[3+ x * num_group]
            expected_new_infection_test = (1.0 - effect_t) * new_infection_control * new_infection_seed_test/float(new_infection_seed_control)
            statistical_population_test = statistical_populations[3]
            tolerance_2 = 0.0 if expected_new_infection_test == 0.0 else 2e-2 * statistical_population_test
            if math.fabs(new_infection_test - expected_new_infection_test) > tolerance_2:
                success = False
                outfile.write("BAD: At time step {0}, {1} reported new infections in Group 4_Test, expected {2}.\n".format(
                    timestep, new_infection_test, expected_new_infection_test))
            #test mortality blocking
            disease_death_seed_test = new_disease_deaths[1 + x * num_group]
            expected_disease_death_seed_test = new_infection_seed_test * (1.0 - effect_m)
            tolerance_3 = 0.0 if expected_disease_death_seed_test == 0.0 else 2e-2 * new_infection_seed_test
            if math.fabs(disease_death_seed_test - expected_disease_death_seed_test) > tolerance_3:
                success = False
                outfile.write("BAD: At time step {0}, {1} reported disease deaths in Group 2_Seed_Test, expected {2}.\n".format(
                    timestep, disease_death_seed_test, expected_disease_death_seed_test))
            timestep += Timesteps_Between_Repetitions
            effect_a = effect_a + (1.0 - effect_a) * Boost_Acquire
            effect_t = effect_t + (1.0 - effect_t) * Boost_Transmit
            effect_m = effect_m + (1.0 - effect_m) * Boost_Mortality
        outfile.write(sft.format_success_msg(success))
    sft.plot_data(new_infections,new_disease_deaths,
                           label1= "new_infections", label2 = "disease_death",
                           xlabel= "0&4:Seed_Control, 1&5:Seed_Test, 2&6:Control, 4&7:Test",
                           title = "new_infections vs. new_disease_death",
                           category = 'New_infections_vs_new_disease_death',show = True )
    if debug:
        print( "SUMMARY: Success={0}\n".format(success) )
    return success
예제 #27
0
def application(report_file):
    sft.wait_for_done()
    regex = "immunity calculated as"
    lines = []
    with open("test.txt") as logfile:
        for line in logfile:
            if re.search(regex, line):
                lines.append(line)

    cdj = json.loads(open("config.json").read())["parameters"]
    protection_per_infection = cdj["Typhoid_Protection_Per_Infection"]

    immunity_observed_data = []
    immunity_predicted_data = []
    immunity_based_on_infection_count = {}
    success = True
    with open(sft.sft_output_filename, "w") as report_file:
        if not lines:
            success = False
            report_file.write("BAD: Found no data matching test case.\n")
        else:
            for line in lines:
                immunity = float(line.split()[8])
                immunity_observed_data.append(immunity)
                infection_count = int((sft.get_val("_infection_count=",
                                                   line)).rstrip('.'))
                immunity_predicted = float(
                    format(
                        math.pow(1 - protection_per_infection,
                                 infection_count), '0.6f'))
                immunity_predicted_data.append(immunity_predicted)
                if abs(immunity - immunity_predicted) > 1e-5:
                    success = False
                    report_file.write(
                        "BAD: Immunity is {} instead of predicted {}\n".format(
                            immunity, immunity_predicted))
                if infection_count not in immunity_based_on_infection_count:
                    immunity_based_on_infection_count[
                        infection_count] = immunity_predicted

        report_file.write(sft.format_success_msg(success))

        sft.plot_data(immunity_observed_data,
                      immunity_predicted_data,
                      label1="Actual",
                      label2="Expected",
                      title="Immunity based on Infection Count, TPPI={0}"
                      "".format(protection_per_infection),
                      xlabel="Occurrence",
                      ylabel="Immunity Level",
                      category='immunity_based_on_infection_data',
                      alpha=0.5,
                      overlap=True,
                      sort=True)
        # plot for Typhod spec:
        lists = sorted(immunity_based_on_infection_count.items()
                       )  # sorted by key, return a list of tuples
        x, y = zip(*lists)  # unpack a list of pairs into two tuples
        fig = plt.figure()
        plt.plot(x, y, "b*", markersize=6)
        plt.title("Immunity based on Infection Count, TPPI={0}".format(
            protection_per_infection))
        plt.xlabel("Infection Count")
        plt.ylabel("Immunity")
        if sft.check_for_plotting():
            plt.show()
        fig.savefig('immunity_based_on_infection_count.png')
def create_report_file(param_obj, campaign_obj, stdout_df, report_name, debug):
    with open(report_name, "w") as outfile:
        for name, param in param_obj.items():
            outfile.write("{0} = {1}\n".format(name, param))
        success = True
        sample_threshold = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold])
        base_sensitivity = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity])
        base_specificity = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity])
        ip_key_value = campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value]
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold, sample_threshold))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity, base_sensitivity))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity, base_specificity))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value,
                                           ip_key_value))

        if sample_threshold:
            outfile.write("WARNING: {0} should be 0 in this test, got {1} from compaign file. Please fix the test.\n"
                          "".format(CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold, sample_threshold))
        if base_specificity != 1:
            outfile.write("WARNING: the {0} is {1}, expected value is 1.\n".format(
                CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity, base_specificity))
        if ip_key_value:
            success = False
            outfile.write("BAD: {0} should be empty in this test, got {1} from compaign file. Please fix the test.\n"
                          "".format(CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value, ip_key_value))

        duration = param_obj[ConfigKeys.Simulation_Duration]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        expected_positive_count = expected_negative_count = 0
        contagion_list = []
        contagion = 0

        for t in range(1, duration):
            stdout_t_df = stdout_df[stdout_df[Diagnostic_Support.ConfigKeys.Simulation_Timestep] == t]
            infected = stdout_t_df[Diagnostic_Support.Stdout.infected].iloc[0]
            stat_pop = stdout_t_df[Diagnostic_Support.Stdout.stat_pop].iloc[0]
            envi_sample = stdout_t_df[Diagnostic_Support.Stdout.sample].iloc[0]

            # calculated environmental contagion for next time step
            contagion = base_infectivity * infected /stat_pop
            if math.fabs(contagion - envi_sample) > envi_sample * 1e-2:
                success = False
                outfile.write("BAD: at time step {0} the environmental sample is {1}, expected value is {2}.\n".format(
                    t, envi_sample, contagion
                ))
            if contagion > sample_threshold:
                expected_test_positive = base_sensitivity
                expected_test_negative = 1.0 - base_sensitivity
            else:
                expected_test_positive = 1.0 - base_specificity
                expected_test_negative = base_specificity

            contagion_list.append(contagion)

            expected_positive_count += expected_test_positive
            expected_negative_count += expected_test_negative

        stdout_sum = stdout_df.sum()

        result = sft.test_multinomial([stdout_sum[Diagnostic_Support.Stdout.test_positive],
                                  stdout_sum[Diagnostic_Support.Stdout.test_negative]],
                                 proportions=[expected_positive_count, expected_negative_count],
                                 report_file=outfile,
                                 prob_flag=False, )

        message = "{0}: the total test positive and negative counts from StdOut.txt are {1} and {2}, expected values" \
                  " are {3} and {4}.\n"

        if result:
            outfile.write(message.format("GOOD", stdout_sum[Diagnostic_Support.Stdout.test_positive],
                                         stdout_sum[Diagnostic_Support.Stdout.test_negative],
                                         expected_positive_count, expected_negative_count))
        else:
            success = False
            outfile.write(message.format("BAD", stdout_sum[Diagnostic_Support.Stdout.test_positive],
                                         stdout_sum[Diagnostic_Support.Stdout.test_negative],
                                         expected_positive_count, expected_negative_count))

        sft.plot_data(stdout_df[Diagnostic_Support.Stdout.sample].tolist()[1:], contagion_list,
                          label1="Actual",
                          label2="Expected",
                          title="Environmental_Contagion", xlabel="Day",
                          ylabel="Environmental_Contagion",
                          category='Environmental_Contagion', overlap=True, alpha=0.5)

        # positive_list = []
        # negative_list = []
        # for t in range(1, duration):
        #     infected = stdout_df[Stdout.infected].iloc[t]
        #     stat_pop = stdout_df[Stdout.stat_pop].iloc[t]
        #     test_positive = stdout_df[Stdout.test_positive].iloc[t]
        #     test_negative = stdout_df[Stdout.test_negative].iloc[t]
        #     test_default = stdout_df[Stdout.test_default].iloc[t]
        #
        #     susceptible = stat_pop - infected
        #     message = "BAD: at time {0}, total infected individuals = {1} and total susceptible individuals = {2}, " \
        #               "expected {3} ± {4} individuals receive a {5} test result, got {6} from logging.\n"
        #
        #     expected_test_positive = infected * base_sensitivity + susceptible * (1.0 - base_specificity)
        #     if math.fabs(test_positive - expected_test_positive) > 5e-2 * expected_test_positive:
        #         success = False
        #         outfile.write(message.format(
        #             t, infected, susceptible, expected_test_positive, 5e-2 * expected_test_positive, "positive",
        #             test_positive))
        #
        #     expected_test_negative = infected * (1.0 - base_sensitivity) + susceptible * base_specificity
        #     if math.fabs(test_negative - expected_test_negative) > 5e-2 * expected_test_negative:
        #         success = False
        #         outfile.write(message.format(
        #             t, infected, susceptible, expected_test_negative, 5e-2 * expected_test_negative, "negative",
        #             test_negative))
        #
        #     expected_test_default = 0
        #     if test_default != expected_test_default:
        #         success = False
        #         outfile.write(message.format(
        #                 t, infected, susceptible, expected_test_default, 0, "default", test_default))
        #
        #     positive_list.append([test_positive, expected_test_positive])
        #     negative_list.append([test_negative, expected_test_negative])
        # sft.plot_data(np.array(positive_list)[:, 0], np.array(positive_list)[:, 1],
        #               label1="Actual",
        #               label2="Expected",
        #               title="Test Positive", xlabel="Day",
        #               ylabel="Positive count",
        #               category='Test_Positive', overlap=True, alpha=0.5)
        # sft.plot_data(np.array(negative_list)[:, 0], np.array(negative_list)[:, 1],
        #               label1="Actual",
        #               label2="Expected",
        #               title="Test Negative", xlabel="Day",
        #               ylabel="Negative count",
        #               category='Test_Negative', overlap=True, alpha=0.5)
        outfile.write(sft.format_success_msg(success))
        if debug:
            print(sft.format_success_msg(success))
        return success
예제 #29
0
def create_report_file(param_obj, stdout_df, property_obj, property_df,
                       report_name, debug):
    with open(report_name, "w") as outfile:
        for name, param in param_obj.items():
            outfile.write("{0} = {1}\n".format(name, param))
        success = True
        start_day = param_obj[ConfigKeys.Environmental_Peak_Start]
        ramp_up = param_obj[ConfigKeys.Environmental_Ramp_Up_Duration]
        ramp_down = param_obj[ConfigKeys.Environmental_Ramp_Down_Duration]
        cut_off = param_obj[ConfigKeys.Environmental_Cutoff_Days]
        duration = param_obj[ConfigKeys.Simulation_Duration]

        peak_duration = sft.DAYS_IN_YEAR - ramp_up - ramp_down - cut_off
        peak_starttime = start_day % sft.DAYS_IN_YEAR
        peak_endtime = peak_starttime + peak_duration
        cutoff_starttime = peak_starttime + peak_duration + ramp_down
        cutoff_endtime = peak_starttime + peak_duration + ramp_down + cut_off

        amp = []
        expected_amp = []
        expected_contagion_e_list = []
        expected_contagion_c_list = []
        # adjust the times so that the ramp up starts at time 0, which means the cut off ends at time 0 too.
        adjust_time = peak_starttime - ramp_up
        peak_starttime -= adjust_time
        peak_endtime -= adjust_time
        cutoff_starttime -= adjust_time
        cutoff_endtime -= adjust_time
        cutoff_endtime %= sft.DAYS_IN_YEAR

        contagion_channels_e = [
            c for c in property_df.columns if channels[3] in c
        ]
        contagion_channels_c = [
            c for c in property_df.columns if channels[4] in c
        ]
        property_df[channels[3]] = property_df[contagion_channels_e].sum(
            axis=1)
        property_df[channels[4]] = property_df[contagion_channels_c].sum(
            axis=1)

        for t in range(1, duration):
            amplification = stdout_df[Stdout.amplification].iloc[t]
            day_in_year = stdout_df[Stdout.day_of_year].iloc[t]
            if day_in_year != t % sft.DAYS_IN_YEAR:
                success = False
                outfile.write(
                    "BAD: at time step {0}, day_in_year is {1}, it should be {2}.\n"
                    .format(t, day_in_year, t % sft.DAYS_IN_YEAR))
                day_in_year = t % sft.DAYS_IN_YEAR
            day_in_year -= adjust_time
            day_in_year %= sft.DAYS_IN_YEAR
            # Environment Ramp Up
            if cutoff_endtime < day_in_year < peak_starttime:
                expected_amplification = day_in_year / ramp_up
            # Environment peak
            elif peak_starttime <= day_in_year <= peak_endtime:
                expected_amplification = 1
            # Environment Ramp Down
            elif peak_endtime < day_in_year < cutoff_starttime:
                expected_amplification = (cutoff_starttime -
                                          day_in_year) / ramp_down
            # Environment cutoff
            else:
                expected_amplification = 0
            if not math.fabs(amplification - expected_amplification
                             ) <= 5e-2 * expected_amplification:
                success = False
                outfile.write(
                    "BAD: at time {0}, day of year = {1}, the environmental amplification is {2}, expected {3}.\n"
                    .format(t, t % sft.DAYS_IN_YEAR, amplification,
                            expected_amplification))
            amp.append(amplification)
            expected_amp.append(expected_amplification)

            # Boxcar scaling
            boxcar_multiplier = Boxcar_Support.calculate_infectiousness(
                infected_pop=1,
                index=t,
                simulation_timestep=param_obj[ConfigKeys.Simulation_Timestep],
                start_time=param_obj[
                    ConfigKeys.Infectivity_Boxcar_Forcing_Start_Time],
                end_time=param_obj[
                    ConfigKeys.Infectivity_Boxcar_Forcing_End_Time],
                base_infectivity=1,
                amplitude=param_obj[
                    ConfigKeys.Infectivity_Boxcar_Forcing_Amplitude],
                debug=debug)
            expected_contagion_e = param_obj[ConfigKeys.Base_Infectivity] * \
                                   expected_amplification * \
                                  (len(property_obj[DemographicsKeys.PropertyKeys.Values]) ** 2)
            # infectivity scaling should only applies to contact route.
            # expected_contagion_e *= boxcar_multiplier

            expected_contagion_c = boxcar_multiplier * param_obj[ConfigKeys.Base_Infectivity] * \
                                   len(property_obj[DemographicsKeys.PropertyKeys.Values])
            actual_contagion_e = property_df[channels[3]][t]
            actual_contagion_c = property_df[channels[4]][t]
            for expected_contagion, actual_contagion, column_name in [
                (expected_contagion_e, actual_contagion_e, channels[3]),
                (expected_contagion_c, actual_contagion_c, channels[4])
            ]:
                if not math.fabs(actual_contagion - expected_contagion
                                 ) <= 5e-2 * expected_contagion:
                    success = False
                    outfile.write(
                        "BAD: at time {0}, day of year = {1}, the {2} is {3}, expected {4}.\n"
                        .format(t, t % sft.DAYS_IN_YEAR, column_name,
                                actual_contagion, expected_contagion))
            expected_contagion_e_list.append(expected_contagion_e)
            expected_contagion_c_list.append(expected_contagion_c)

        sft.plot_data(amp,
                      expected_amp,
                      label1="Actual amplification",
                      label2="Expected amplification",
                      title="Seasonality",
                      xlabel="Day",
                      ylabel="Environmental amplification",
                      category='seasonal_attenuation',
                      overlap=True,
                      alpha=0.5)

        sft.plot_data(property_df[channels[3]][1:],
                      expected_contagion_e_list[1:],
                      label1="Actual",
                      label2="Expected",
                      title="Environmental Contagion\nSeasonality_Boxcar",
                      xlabel="Day",
                      ylabel="Environmental Contagion",
                      category='Environmental_Contagion',
                      overlap=True,
                      alpha=0.5)

        sft.plot_data(property_df[channels[4]][1:],
                      expected_contagion_c_list[1:],
                      label1="Actual",
                      label2="Expected",
                      title="Contact Contagion\nSeasonality_Boxcar",
                      xlabel="Day",
                      ylabel="Contact Contagion",
                      category='Contact_Contagion',
                      overlap=True,
                      alpha=0.5)

        outfile.write(sft.format_success_msg(success))
        if debug:
            print(sft.format_success_msg(success))
        return success
def create_report_file(param_obj, campaign_obj, stdout_df, report_name, debug):
    with open(report_name, "w") as outfile:
        for name, param in param_obj.items():
            outfile.write("{0} = {1}\n".format(name, param))
        success = True
        sample_threshold = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold])
        base_sensitivity = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity])
        base_specificity = float(campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity])
        ip_key_value = campaign_obj[CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value]
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold, sample_threshold))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity, base_sensitivity))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity, base_specificity))
        outfile.write("{0} = {1}\n".format(CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value,
                                           ip_key_value))

        if base_sensitivity != 1:
            success = False
            outfile.write("BAD: the {0} is {1}, expected value is 1.\n".format(
                CampaignKeys.EnvironmentalDiagnosticKeys.Base_Sensitivity, base_sensitivity))
        if base_specificity != 1:
            success = False
            outfile.write("BAD: the {0} is {1}, expected value is 1.\n".format(
                CampaignKeys.EnvironmentalDiagnosticKeys.Base_Specificity, base_specificity))
        if ip_key_value:
            success = False
            outfile.write("BAD: {0} should be empty in this test, got {1} from compaign file. Please fix the test.\n"
                          "".format(CampaignKeys.EnvironmentalDiagnosticKeys.Environment_IP_Key_Value, ip_key_value))

        duration = param_obj[ConfigKeys.Simulation_Duration]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]

        if base_infectivity <= sample_threshold:
            outfile.write("WARNING: {0}({1}) is larger than {2}({3}), please check the test.\n".format(
                ConfigKeys.Base_Infectivity, base_infectivity,
                CampaignKeys.EnvironmentalDiagnosticKeys.Sample_Threshold, sample_threshold
            ))

        positive_list = []
        negative_list = []
        # tolerance is 0 in this test.
        tolerance = 0 if base_sensitivity == 1 and base_specificity == 1 else 5e-2
        contagion_list = []
        contagion = 0
        for t in range(1, duration):
            stdout_t_df = stdout_df[stdout_df[Diagnostic_Support.ConfigKeys.Simulation_Timestep] == t]
            infected = stdout_t_df[Diagnostic_Support.Stdout.infected].iloc[0]
            stat_pop = stdout_t_df[Diagnostic_Support.Stdout.stat_pop].iloc[0]
            test_positive = stdout_t_df[Diagnostic_Support.Stdout.test_positive].iloc[0]
            test_negative = stdout_t_df[Diagnostic_Support.Stdout.test_negative].iloc[0]
            test_default = stdout_t_df[Diagnostic_Support.Stdout.test_default].iloc[0]
            envi_sample = stdout_t_df[Diagnostic_Support.Stdout.sample].iloc[0]

            susceptible = stat_pop - infected
            message = "BAD: at time {0}, total infected individuals = {1} and total susceptible individuals = {2}," \
            " expected {3} {4} test result, got {5} from logging.\n"

            # calculated environmental contagion
            contagion = base_infectivity * infected /stat_pop
            if math.fabs(contagion - envi_sample) > envi_sample * 1e-2:
                success = False
                outfile.write("BAD: at time step {0} the environmental sample is {1}, expected value is {2}.\n".format(
                    t, envi_sample, contagion
                ))
            if contagion > sample_threshold:
                expected_test_positive = 1
                expected_test_negative = 0
            else:
                expected_test_positive = 0
                expected_test_negative = 1

            contagion_list.append(contagion)

            # tolerance is 0 in this test, so we are looking for a 100% match in this test.
            if math.fabs(test_positive - expected_test_positive) > tolerance * expected_test_positive:
                success = False
                outfile.write(message.format(
                    t, infected, susceptible, expected_test_positive, "positive", test_positive))
            if math.fabs(test_negative - expected_test_negative) > tolerance * expected_test_negative:
                success = False
                outfile.write(message.format(
                    t, infected, susceptible, expected_test_negative, "negative", test_negative))

            expected_test_default = 0
            if test_default != expected_test_default:
                success = False
                outfile.write(message.format(
                        t, infected, susceptible, expected_test_default, "default", test_default))

            positive_list.append([test_positive, expected_test_positive])
            negative_list.append([test_negative, expected_test_negative])
        sft.plot_data(stdout_df[Diagnostic_Support.Stdout.sample].tolist()[1:], contagion_list,
                          label1="Actual",
                          label2="Expected",
                          title="Environmental_Contagion", xlabel="Day",
                          ylabel="Environmental_Contagion",
                          category='Environmental_Contagion', overlap=True, alpha=0.5)

        sft.plot_data(np.array(positive_list)[:, 0], np.array(positive_list)[:, 1],
                      label1="Actual",
                      label2="Expected",
                      title="Test Positive\n infectivity = {0}, threshold = {1}".format(
                          base_infectivity, sample_threshold), xlabel="Day",
                      ylabel="Positive count",
                      category='Test_Positive', overlap=True, alpha=0.5)
        sft.plot_data(np.array(negative_list)[:, 0], np.array(negative_list)[:, 1],
                      label1="Actual",
                      label2="Expected",
                      title="Test Negative\n infectivity = {0}, threshold = {1}".format(
                          base_infectivity, sample_threshold), xlabel="Day",
                      ylabel="Negative count",
                      category='Test_Negative', overlap=True, alpha=0.5)
        outfile.write(sft.format_success_msg(success))
        if debug:
            print(sft.format_success_msg(success))
        return success
예제 #31
0
def create_report_file(param_obj, campaign_obj, stdout_df, property_df,
                       property_list, report_name, debug):
    with open(report_name, "w") as outfile:
        config_name = param_obj[ConfigKeys.Config_Name]
        base_infectivity = param_obj[ConfigKeys.Base_Infectivity]
        outfile.write("Config_name = {}\n".format(config_name))
        outfile.write("{0} = {1} {2} = {3}\n".format(
            ConfigKeys.Base_Infectivity, base_infectivity,
            ConfigKeys.Run_Number, param_obj[ConfigKeys.Run_Number]))

        success = True

        outfile.write(
            "Test 1: checking test conditions/setup in config.json and campaign.json:\n"
        )
        if int(param_obj[
                ConfigKeys.Enable_Heterogeneous_Intranode_Transmission]) != 1:
            success = False
            outfile.write("BAD: HINT is not enabled, please check the test.\n")
        else:
            if not all(x == 0 for x in campaign_obj[CampaignKeys.Start_Day]):
                success = False
                outfile.write(
                    "BAD: All intervention should start at day 0, please check campaign.json.\n"
                )

            if not all(
                    x == 0.05
                    for x in campaign_obj[CampaignKeys.Demographic_Coverage]):
                success = False
                outfile.write(
                    "BAD: {} should be 0.05, please check campaign.json.\n".
                    format(CampaignKeys.Demographic_Coverage))

            expected_property_restrictions = []
            test_groups = []
            non_test_groups = []
            for property_obj in property_list:
                property_values = property_obj[
                    DemographicsKeys.PropertyKeys.Values]
                test_groups.append(property_values[0])
                non_test_groups.append(property_values[1])
                expected_property_restrictions.append([
                    "{0}:{1}".format(
                        property_obj[DemographicsKeys.PropertyKeys.Property],
                        property_values[0])
                ])
            if campaign_obj[
                    CampaignKeys.
                    Property_Restrictions] != expected_property_restrictions:
                success = False
                outfile.write(
                    "BAD: {0} should be {1}, got {2} in campaign.json, please check campaign.json.\n"
                    .format(CampaignKeys.Property_Restrictions,
                            expected_property_restrictions,
                            campaign_obj[CampaignKeys.Property_Restrictions]))

        outfile.write(
            "Test 1: campaign and config met preconditions: {}.\n".format(
                success))

        if success:
            outfile.write(
                "Test 2: Testing contagion and probability with calculated values for every time step:\n"
            )
            outfile.write(
                "Test 3: Testing New Infection channel from property report based on transmission matrix:\n"
            )
            outfile.write("Test 2 and 3 and running at the same time:\n")
            result_2 = result_3 = True
            stat_pop = stdout_df[hint_support.Stdout.stat_pop]
            # infected = stdout_df[Stdout.infected]
            duration = param_obj[ConfigKeys.Simulation_Duration]

            contagion_list = []
            prob_list = []

            non_test_cols = []
            for non_test_group in non_test_groups:
                non_test_cols += [
                    c for c in property_df.columns if non_test_group in c
                ]
            non_test_cols = list(set(non_test_cols))
            # get all the column names that only contains the test group, which should be property_df.columns - non_test_groups
            test_only_cols = [
                c for c in property_df.columns if c not in non_test_cols
            ]

            # test data for test groups
            infected_test = property_df[[
                c for c in test_only_cols if hint_support.channels[0] in c
            ]]
            population_test = property_df[[
                c for c in test_only_cols if hint_support.channels[2] in c
            ]]
            new_infection_test = property_df[[
                c for c in test_only_cols if hint_support.channels[1] in c
            ]]

            expected_new_infection_list = []
            failed_count = 0
            for t in range(duration - 1):
                calculated_contagion = 0
                for col in infected_test:
                    # calculate infectivity of seed group
                    # nomalized with total population
                    infectivity_seed = base_infectivity * infected_test[
                        col].iloc[t] / stat_pop[t]
                    infectivity_mod = 1
                    for i in range(len(test_groups)):
                        test_group = test_groups[i]
                        if test_group in col:
                            for property_obj in property_list:
                                property_values = property_obj[
                                    DemographicsKeys.PropertyKeys.Values]
                                if test_group in property_values:
                                    transmission_matrix = property_obj[
                                        DemographicsKeys.PropertyKeys.Matrix]
                                    infectivity_mod *= transmission_matrix[
                                        property_values.index(test_group)][
                                            property_values.index(test_group)]

                    # calculate contagion of susceptible group
                    calculated_contagion += infectivity_seed * infectivity_mod

                # round the calculated value to 6 Decimal numbers
                calculated_contagion = round(calculated_contagion, 6)

                # get contagion of susceptible group from stdout
                # group_id is the first element in all group_ids
                group_id = 0
                # actual contagion is for next time step
                actual_contagion = stdout_df[
                    (stdout_df[ConfigKeys.Simulation_Timestep] == t + 1)
                    & (stdout_df[hint_support.Stdout.group_id] == group_id)][
                        hint_support.Stdout.contagion].values[0]
                contagion_list.append([actual_contagion, calculated_contagion])
                if math.fabs(calculated_contagion -
                             actual_contagion) > 5e-2 * calculated_contagion:
                    result_2 = success = False
                    outfile.write(
                        "    BAD: at time step {0}, for group {1} id {2}, the total contagion is {3}, "
                        "expected {4}.\n".format(t + 1, test_group, group_id,
                                                 actual_contagion,
                                                 calculated_contagion))

                # calculate infection probability based on contagion
                calculated_prob = 1.0 - math.exp(
                    -1 * calculated_contagion *
                    param_obj[ConfigKeys.Simulation_Timestep])
                # round the calculated value to 6 Decimal numbers
                calculated_prob = round(calculated_prob, 6)
                # get infection probability of susceptible group from stdout_df
                actual_prob = stdout_df[
                    (stdout_df[ConfigKeys.Simulation_Timestep] == t + 1)
                    & (stdout_df[hint_support.Stdout.group_id] == group_id)][
                        hint_support.Stdout.prob].values[0]
                prob_list.append([actual_prob, calculated_prob])
                if math.fabs(calculated_prob -
                             actual_prob) > 5e-2 * calculated_prob:
                    result_2 = success = False
                    outfile.write(
                        "    BAD: at time step {0}, for group {1} id {2}, the infected probability is "
                        "{3}, expected {4}.\n".format(t + 1, test_group,
                                                      group_id, actual_prob,
                                                      calculated_prob))

                # calculate expected new infection for test group
                susceptible_population = population_test.iloc[t][
                    0] - infected_test.iloc[t][0]
                expected_new_infection = susceptible_population * calculated_prob
                expected_new_infection_list.append(expected_new_infection)
                actual_new_infection = new_infection_test.iloc[t + 1][0]
                with open("DEBUG_binomial_test_{}.txt".format(test_group),
                          'w') as file:
                    if expected_new_infection < 5 or susceptible_population * (
                            1 - calculated_prob) < 5:
                        binom_pmf = stats.binom.pmf(k=actual_new_infection,
                                                    n=susceptible_population,
                                                    p=calculated_prob)
                        if binom_pmf < 1e-3:
                            failed_count += 1
                            outfile.write(
                                "WARNING: at timestep {0}, new infections for {1} group is {2}, expected "
                                " = {3}, calculated binomial pmf is {4}.\n"
                                "".format(t + 1, test_group,
                                          actual_new_infection,
                                          expected_new_infection, binom_pmf))

                    elif not sft.test_binomial_99ci(
                            num_success=actual_new_infection,
                            num_trials=susceptible_population,
                            prob=calculated_prob,
                            report_file=file,
                            category="new infections for {0} at time {1}".
                            format(test_group, t + 1)):
                        failed_count += 1
                        standard_deviation = math.sqrt(calculated_prob *
                                                       (1 - calculated_prob) *
                                                       susceptible_population)
                        # 99% confidence interval
                        lower_bound = expected_new_infection - 3 * standard_deviation
                        upper_bound = expected_new_infection + 3 * standard_deviation
                        outfile.write(
                            "WARNING: at timestep {0}, new infections for {1} group is {2}, expected "
                            "within 99% binomial interval ({3}, {4}) with mean = {5}\n"
                            .format(t + 1, test_group, actual_new_infection,
                                    lower_bound, upper_bound,
                                    expected_new_infection))
            # make sure other groups has no new infections after outbreak
            new_infection_non_test = property_df[[
                c for c in non_test_cols if hint_support.channels[1] in c
            ]]
            message_template = "{0}: total new infection after outbreak for {1} is {2}, expected 0.\n"
            for col in new_infection_non_test:
                total_new_infection = new_infection_non_test.ix[1:, col].sum()
                if total_new_infection != 0:
                    success = False
                    outfile.write(
                        message_template.format("BAD", col,
                                                total_new_infection))
                else:
                    outfile.write(
                        message_template.format("GOOD", col,
                                                total_new_infection))

            # plotting
            # get the group name for the test group
            group_name = test_only_cols[0].replace(":", " ", 1).split()[-1]
            # ":" is not allowed in filename, replace it with "-" to avoid OSError
            group_name_modified = group_name.replace(":", "-")
            sft.plot_data(np.array(contagion_list)[:, 0],
                          np.array(contagion_list)[:, 1],
                          label1='contagion from logging',
                          label2="calculated contagion",
                          title="{}\ncontagion".format(group_name),
                          xlabel='day',
                          ylabel='contagion',
                          category="contagion_{}".format(group_name_modified),
                          line=True,
                          alpha=0.5,
                          overlap=True)
            sft.plot_data(
                np.array(prob_list)[:, 0],
                np.array(prob_list)[:, 1],
                label1='probability from logging',
                label2="calculated probability",
                title="{}\nprobability".format(group_name),
                xlabel='day',
                ylabel='probability',
                category="probability_{}".format(group_name_modified),
                line=True,
                alpha=0.5,
                overlap=True)

            sft.plot_data(
                new_infection_test.ix[1:, 0].tolist(),
                expected_new_infection_list,
                label1='from property report',
                label2="calculated data",
                title="{}\nnew infections".format(group_name),
                xlabel='day',
                ylabel='new_infections',
                category="new_infections_{}".format(group_name_modified),
                line=False,
                alpha=0.5,
                overlap=True,
                sort=False)

            message_template = "{0}: binomial test for {1} failed {2} times within {3} total timesteps, which is " \
                               "{4}% fail rate, test is {5}.\n"
            if failed_count / duration > 5e-2:
                result_3 = success = False
                outfile.write(
                    message_template.format("BAD",
                                            new_infection_test.columns.values,
                                            failed_count, duration,
                                            (failed_count / duration) * 100,
                                            "failed"))
            else:
                outfile.write(
                    message_template.format("GOOD",
                                            new_infection_test.columns.values,
                                            failed_count, duration,
                                            (failed_count / duration) * 100,
                                            "passed"))

            outfile.write("Test 2: result is: {}.\n".format(result_2))
            outfile.write("Test 3: result is: {}.\n".format(result_3))

        outfile.write(sft.format_success_msg(success))
    if debug:
        print(sft.format_success_msg(success))
    return success